| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsRenderCompositor.h"
- #include "BsGpuResourcePool.h"
- #include "BsRendererView.h"
- #include "Renderer/BsRendererUtility.h"
- #include "Mesh/BsMesh.h"
- #include "RenderAPI/BsGpuBuffer.h"
- #include "BsStandardDeferredLighting.h"
- #include "BsRenderBeastOptions.h"
- #include "Renderer/BsCamera.h"
- #include "BsRendererScene.h"
- #include "BsRenderBeast.h"
- #include "Utility/BsBitwise.h"
- #include "BsRendererTextures.h"
- #include "BsObjectRendering.h"
- #include "Material/BsGpuParamsSet.h"
- #include "Renderer/BsRendererExtension.h"
- #include "Renderer/BsSkybox.h"
- #include "BsLightProbes.h"
- namespace bs { namespace ct
- {
- UnorderedMap<StringID, RenderCompositor::NodeType*> RenderCompositor::mNodeTypes;
- RenderCompositor::~RenderCompositor()
- {
- clear();
- }
- void RenderCompositor::build(const RendererView& view, const StringID& finalNode)
- {
- clear();
- bs_frame_mark();
- {
- FrameUnorderedMap<StringID, UINT32> processedNodes;
- mIsValid = true;
- std::function<bool(const StringID&)> registerNode = [&](const StringID& nodeId)
- {
- // Find node type
- auto iterFind = mNodeTypes.find(nodeId);
- if (iterFind == mNodeTypes.end())
- {
- LOGERR("Cannot find render compositor node of type \"" + String(nodeId.cstr()) + "\".");
- return false;
- }
- NodeType* nodeType = iterFind->second;
- // Register current node
- auto iterFind2 = processedNodes.find(nodeId);
- // New node
- if (iterFind2 == processedNodes.end())
- {
- // Mark it as invalid for now
- processedNodes[nodeId] = -1;
- }
- // Register node dependencies
- SmallVector<StringID, 4> depIds = nodeType->getDependencies(view);
- for (auto& dep : depIds)
- {
- if (!registerNode(dep))
- return false;
- }
- // Register current node
- UINT32 curIdx;
- // New node, properly populate its index
- if (iterFind2 == processedNodes.end())
- {
- iterFind2 = processedNodes.find(nodeId);
- curIdx = (UINT32)mNodeInfos.size();
- mNodeInfos.push_back(NodeInfo());
- processedNodes[nodeId] = curIdx;
- NodeInfo& nodeInfo = mNodeInfos.back();
- nodeInfo.node = nodeType->create();
- nodeInfo.lastUseIdx = -1;
- for (auto& depId : depIds)
- {
- iterFind2 = processedNodes.find(depId);
- NodeInfo& depNodeInfo = mNodeInfos[iterFind2->second];
- nodeInfo.inputs.push_back(depNodeInfo.node);
- }
- }
- else // Existing node
- {
- curIdx = iterFind2->second;
- // Check if invalid
- if (curIdx == (UINT32)-1)
- {
- LOGERR("Render compositor nodes recursion detected. Node \"" + String(nodeId.cstr()) + "\" " +
- "depends on node \"" + String(iterFind->first.cstr()) + "\" which is not available at " +
- "this stage.");
- return false;
- }
- }
- // Update dependency last use counters
- for (auto& dep : depIds)
- {
- iterFind2 = processedNodes.find(dep);
- NodeInfo& depNodeInfo = mNodeInfos[iterFind2->second];
- if (depNodeInfo.lastUseIdx == (UINT32)-1)
- depNodeInfo.lastUseIdx = curIdx;
- else
- depNodeInfo.lastUseIdx = std::max(depNodeInfo.lastUseIdx, curIdx);
- }
- return true;
- };
- mIsValid = registerNode(finalNode);
- if (!mIsValid)
- clear();
- }
- bs_frame_clear();
- }
- void RenderCompositor::execute(RenderCompositorNodeInputs& inputs) const
- {
- if (!mIsValid)
- return;
- bs_frame_mark();
- {
- FrameVector<const NodeInfo*> activeNodes;
- UINT32 idx = 0;
- for (auto& entry : mNodeInfos)
- {
- inputs.inputNodes = entry.inputs;
- entry.node->render(inputs);
- activeNodes.push_back(&entry);
- for (UINT32 i = 0; i < (UINT32)activeNodes.size(); ++i)
- {
- if (activeNodes[i] == nullptr)
- continue;
- if (activeNodes[i]->lastUseIdx <= idx)
- {
- activeNodes[i]->node->clear();
- activeNodes[i] = nullptr;
- }
- }
- idx++;
- }
- }
- bs_frame_clear();
- if (!mNodeInfos.empty())
- mNodeInfos.back().node->clear();
- }
- void RenderCompositor::clear()
- {
- for (auto& entry : mNodeInfos)
- bs_delete(entry.node);
- mNodeInfos.clear();
- mIsValid = false;
- }
- void RCNodeSceneDepth::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
- depthTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height, TU_DEPTHSTENCIL,
- numSamples, false));
- }
- void RCNodeSceneDepth::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(depthTex);
- }
- SmallVector<StringID, 4> RCNodeSceneDepth::getDependencies(const RendererView& view)
- {
- return {};
- }
- void RCNodeGBuffer::render(const RenderCompositorNodeInputs& inputs)
- {
- // Allocate necessary textures & targets
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
- // Note: Consider customizable formats. e.g. for testing if quality can be improved with higher precision normals.
- albedoTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA8, width, height, TU_RENDERTARGET,
- numSamples, true));
- normalTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGB10A2, width, height, TU_RENDERTARGET,
- numSamples, false));
- roughMetalTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RG16F, width, height, TU_RENDERTARGET,
- numSamples, false)); // Note: Metal doesn't need 16-bit float
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
- SPtr<PooledRenderTexture> sceneDepthTex = sceneDepthNode->depthTex;
- bool rebuildRT = false;
- if (renderTarget != nullptr)
- {
- rebuildRT |= renderTarget->getColorTexture(0) != albedoTex->texture;
- rebuildRT |= renderTarget->getColorTexture(1) != normalTex->texture;
- rebuildRT |= renderTarget->getColorTexture(2) != roughMetalTex->texture;
- rebuildRT |= renderTarget->getDepthStencilTexture() != sceneDepthTex->texture;
- }
- else
- rebuildRT = true;
- if (renderTarget == nullptr || rebuildRT)
- {
- RENDER_TEXTURE_DESC gbufferDesc;
- gbufferDesc.colorSurfaces[0].texture = albedoTex->texture;
- gbufferDesc.colorSurfaces[0].face = 0;
- gbufferDesc.colorSurfaces[0].numFaces = 1;
- gbufferDesc.colorSurfaces[0].mipLevel = 0;
- gbufferDesc.colorSurfaces[1].texture = normalTex->texture;
- gbufferDesc.colorSurfaces[1].face = 0;
- gbufferDesc.colorSurfaces[1].numFaces = 1;
- gbufferDesc.colorSurfaces[1].mipLevel = 0;
- gbufferDesc.colorSurfaces[2].texture = roughMetalTex->texture;
- gbufferDesc.colorSurfaces[2].face = 0;
- gbufferDesc.colorSurfaces[2].numFaces = 1;
- gbufferDesc.colorSurfaces[2].mipLevel = 0;
- gbufferDesc.depthStencilSurface.texture = sceneDepthTex->texture;
- gbufferDesc.depthStencilSurface.face = 0;
- gbufferDesc.depthStencilSurface.mipLevel = 0;
- renderTarget = RenderTexture::create(gbufferDesc);
- }
- // Prepare all visible objects. Note that this also prepares non-opaque objects.
- const VisibilityInfo& visibility = inputs.view.getVisibilityMasks();
- UINT32 numRenderables = (UINT32)inputs.scene.renderables.size();
- for (UINT32 i = 0; i < numRenderables; i++)
- {
- if (!visibility.renderables[i])
- continue;
- RendererObject* rendererObject = inputs.scene.renderables[i];
- rendererObject->updatePerCallBuffer(viewProps.viewProjTransform);
- for (auto& element : inputs.scene.renderables[i]->elements)
- {
- SPtr<GpuParams> gpuParams = element.params->getGpuParams();
- for(UINT32 j = 0; j < GPT_COUNT; j++)
- {
- const GpuParamBinding& binding = element.perCameraBindings[j];
- if(binding.slot != (UINT32)-1)
- gpuParams->setParamBlockBuffer(binding.set, binding.slot, inputs.view.getPerViewBuffer());
- }
- }
- }
- Camera* sceneCamera = inputs.view.getSceneCamera();
- // Trigger pre-base-pass callbacks
- if (sceneCamera != nullptr)
- {
- for(auto& extension : inputs.extPreBasePass)
- {
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- }
- }
- // Render base pass
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(renderTarget);
- Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
- rapi.setViewport(area);
- // Clear all targets
- rapi.clearViewport(FBT_COLOR | FBT_DEPTH | FBT_STENCIL, Color::ZERO, 1.0f, 0);
- // Render all visible opaque elements
- const Vector<RenderQueueElement>& opaqueElements = inputs.view.getOpaqueQueue()->getSortedElements();
- for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
- {
- BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
- SPtr<Material> material = renderElem->material;
- if (iter->applyPass)
- gRendererUtility().setPass(material, iter->passIdx, renderElem->techniqueIdx);
- gRendererUtility().setPassParams(renderElem->params, iter->passIdx);
- if(renderElem->morphVertexDeclaration == nullptr)
- gRendererUtility().draw(renderElem->mesh, renderElem->subMesh);
- else
- gRendererUtility().drawMorph(renderElem->mesh, renderElem->subMesh, renderElem->morphShapeBuffer,
- renderElem->morphVertexDeclaration);
- }
- // Make sure that any compute shaders are able to read g-buffer by unbinding it
- rapi.setRenderTarget(nullptr);
- // Trigger post-base-pass callbacks
- if (sceneCamera != nullptr)
- {
- for(auto& extension : inputs.extPostBasePass)
- {
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- }
- }
- }
- void RCNodeGBuffer::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(albedoTex);
- resPool.release(normalTex);
- resPool.release(roughMetalTex);
- }
- SmallVector<StringID, 4> RCNodeGBuffer::getDependencies(const RendererView& view)
- {
- return { RCNodeSceneDepth::getNodeId() };
- }
- void RCNodeSceneColor::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
- UINT32 usageFlags = TU_RENDERTARGET;
- bool tiledDeferredSupported = inputs.featureSet != RenderBeastFeatureSet::DesktopMacOS;
- if(tiledDeferredSupported)
- usageFlags |= TU_LOADSTORE;
- // Note: Consider customizable HDR format via options? e.g. smaller PF_FLOAT_R11G11B10 or larger 32-bit format
- sceneColorTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width, height, usageFlags,
- numSamples, false));
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
- SPtr<PooledRenderTexture> sceneDepthTex = sceneDepthNode->depthTex;
- if (tiledDeferredSupported && viewProps.numSamples > 1)
- {
- UINT32 bufferNumElements = width * height * viewProps.numSamples;
- flattenedSceneColorBuffer = resPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
- }
- else
- flattenedSceneColorBuffer = nullptr;
- bool rebuildRT = false;
- if (renderTarget != nullptr)
- {
- rebuildRT |= renderTarget->getColorTexture(0) != sceneColorTex->texture;
- rebuildRT |= renderTarget->getDepthStencilTexture() != sceneDepthTex->texture;
- }
- else
- rebuildRT = true;
- if (rebuildRT)
- {
- RENDER_TEXTURE_DESC sceneColorDesc;
- sceneColorDesc.colorSurfaces[0].texture = sceneColorTex->texture;
- sceneColorDesc.colorSurfaces[0].face = 0;
- sceneColorDesc.colorSurfaces[0].numFaces = 1;
- sceneColorDesc.colorSurfaces[0].mipLevel = 0;
- sceneColorDesc.depthStencilSurface.texture = sceneDepthTex->texture;
- sceneColorDesc.depthStencilSurface.face = 0;
- sceneColorDesc.depthStencilSurface.numFaces = 1;
- sceneColorDesc.depthStencilSurface.mipLevel = 0;
- renderTarget = RenderTexture::create(sceneColorDesc);
- }
- }
- void RCNodeSceneColor::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(sceneColorTex);
- if (flattenedSceneColorBuffer != nullptr)
- resPool.release(flattenedSceneColorBuffer);
- }
- SmallVector<StringID, 4> RCNodeSceneColor::getDependencies(const RendererView& view)
- {
- return { RCNodeSceneDepth::getNodeId() };
- }
- void RCNodeMSAACoverage::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width, height, TU_RENDERTARGET));
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[0]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- MSAACoverageMat* mat = MSAACoverageMat::getVariation(viewProps.numSamples);
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(output->renderTexture);
- mat->execute(inputs.view, gbuffer);
- MSAACoverageStencilMat* stencilMat = MSAACoverageStencilMat::get();
- rapi.setRenderTarget(sceneDepthNode->depthTex->renderTexture);
- stencilMat->execute(inputs.view, output->texture);
- rapi.setRenderTarget(nullptr);
- }
- void RCNodeMSAACoverage::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(output);
- }
- SmallVector<StringID, 4> RCNodeMSAACoverage::getDependencies(const RendererView& view)
- {
- return { RCNodeGBuffer::getNodeId(), RCNodeSceneDepth::getNodeId() };
- }
- void RCNodeLightAccumulation::render(const RenderCompositorNodeInputs& inputs)
- {
- bool supportsTiledDeferred = gRenderBeast()->getFeatureSet() != RenderBeastFeatureSet::DesktopMacOS;
- if(!supportsTiledDeferred)
- {
- // If tiled deferred is not supported, we don't need a separate texture for light accumulation, instead we
- // use scene color directly
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- lightAccumulationTex = sceneColorNode->sceneColorTex;
- renderTarget = sceneColorNode->renderTarget;
- mOwnsTexture = false;
- return;
- }
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- RCNodeSceneDepth* depthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
-
- if (numSamples > 1)
- {
- UINT32 bufferNumElements = width * height * numSamples;
- flattenedLightAccumBuffer =
- resPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
- SPtr<GpuBuffer> buffer = flattenedLightAccumBuffer->buffer;
- auto& bufferProps = buffer->getProperties();
- UINT32 bufferSize = bufferProps.getElementSize() * bufferProps.getElementCount();
- UINT16* data = (UINT16*)buffer->lock(0, bufferSize, GBL_WRITE_ONLY_DISCARD);
- {
- memset(data, 0, bufferSize);
- }
- buffer->unlock();
- }
- else
- flattenedLightAccumBuffer = nullptr;
- lightAccumulationTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width,
- height, TU_LOADSTORE | TU_RENDERTARGET, numSamples, false));
- bool rebuildRT;
- if (renderTarget != nullptr)
- {
- rebuildRT = renderTarget->getColorTexture(0) != lightAccumulationTex->texture;
- rebuildRT |= renderTarget->getDepthStencilTexture() != depthNode->depthTex->texture;
- }
- else
- rebuildRT = true;
- if (rebuildRT)
- {
- RENDER_TEXTURE_DESC lightAccumulationRTDesc;
- lightAccumulationRTDesc.colorSurfaces[0].texture = lightAccumulationTex->texture;
- lightAccumulationRTDesc.colorSurfaces[0].face = 0;
- lightAccumulationRTDesc.colorSurfaces[0].numFaces = 1;
- lightAccumulationRTDesc.colorSurfaces[0].mipLevel = 0;
- lightAccumulationRTDesc.depthStencilSurface.texture = depthNode->depthTex->texture;
- lightAccumulationRTDesc.depthStencilSurface.face = 0;
- lightAccumulationRTDesc.depthStencilSurface.numFaces = 1;
- lightAccumulationRTDesc.depthStencilSurface.mipLevel = 0;
- renderTarget = RenderTexture::create(lightAccumulationRTDesc);
- }
- mOwnsTexture = true;
- }
- void RCNodeLightAccumulation::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- if(mOwnsTexture)
- resPool.release(lightAccumulationTex);
- else
- {
- lightAccumulationTex = nullptr;
- renderTarget = nullptr;
- }
- if (flattenedLightAccumBuffer)
- resPool.release(flattenedLightAccumBuffer);
- }
- SmallVector<StringID, 4> RCNodeLightAccumulation::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- bool supportsTiledDeferred = gRenderBeast()->getFeatureSet() != RenderBeastFeatureSet::DesktopMacOS;
- if(!supportsTiledDeferred)
- deps.push_back(RCNodeSceneColor::getNodeId());
- else
- deps.push_back(RCNodeSceneDepth::getNodeId());
- return deps;
- }
- void RCNodeTiledDeferredLighting::render(const RenderCompositorNodeInputs& inputs)
- {
- output = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[0]);
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- SPtr<Texture> msaaCoverage;
- if(viewProps.numSamples > 1)
- {
- RCNodeMSAACoverage* coverageNode = static_cast<RCNodeMSAACoverage*>(inputs.inputNodes[3]);
- msaaCoverage = coverageNode->output->texture;
- }
- TiledDeferredLightingMat* tiledDeferredMat = TiledDeferredLightingMat::getVariation(viewProps.numSamples);
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- const VisibleLightData& lightData = inputs.viewGroup.getVisibleLightData();
- SPtr<GpuBuffer> flattenedLightAccumBuffer;
- if (output->flattenedLightAccumBuffer)
- flattenedLightAccumBuffer = output->flattenedLightAccumBuffer->buffer;
- tiledDeferredMat->execute(inputs.view, lightData, gbuffer, output->lightAccumulationTex->texture,
- flattenedLightAccumBuffer, msaaCoverage);
- }
- void RCNodeTiledDeferredLighting::clear()
- {
- output = nullptr;
- }
- SmallVector<StringID, 4> RCNodeTiledDeferredLighting::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeSceneDepth::getNodeId());
- if(view.getProperties().numSamples > 1)
- deps.push_back(RCNodeMSAACoverage::getNodeId());
- return deps;
- }
- void RCNodeStandardDeferredLighting::render(const RenderCompositorNodeInputs& inputs)
- {
- SPtr<RenderTexture> outputRT;
- bool tiledDeferredSupported = inputs.featureSet == RenderBeastFeatureSet::Desktop;
- if(tiledDeferredSupported)
- {
- RCNodeTiledDeferredLighting* tileDeferredNode = static_cast<RCNodeTiledDeferredLighting*>(inputs.inputNodes[2]);
- outputRT = tileDeferredNode->output->renderTarget;
- // If shadows are disabled we handle all lights through tiled deferred, except when tiled deferred isn't available
- if (!inputs.view.getRenderSettings().enableShadows)
- {
- mLightOcclusionRT = nullptr;
- return;
- }
- }
- else
- {
- RCNodeLightAccumulation* lightAccumNode = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[2]);
- outputRT = lightAccumNode->renderTarget;
- mLightOcclusionRT = nullptr;
- }
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[0]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- const VisibleLightData& lightData = inputs.viewGroup.getVisibleLightData();
- RenderAPI& rapi = RenderAPI::instance();
- // Render unshadowed lights
- if(!tiledDeferredSupported)
- {
- rapi.setRenderTarget(outputRT, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
- for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
- {
- LightType lightType = (LightType)i;
- auto& lights = lightData.getLights(lightType);
- UINT32 count = lightData.getNumUnshadowedLights(lightType);
- for (UINT32 j = 0; j < count; j++)
- {
- UINT32 lightIdx = j;
- const RendererLight& light = *lights[lightIdx];
- StandardDeferred::instance().renderLight(lightType, light, inputs.view, gbuffer, Texture::BLACK);
- }
- }
- }
- // Allocate light occlusion
- SPtr<PooledRenderTexture> lightOcclusionTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width,
- height, TU_RENDERTARGET, numSamples, false));
- bool rebuildRT = false;
- if (mLightOcclusionRT != nullptr)
- {
- rebuildRT |= mLightOcclusionRT->getColorTexture(0) != lightOcclusionTex->texture;
- rebuildRT |= mLightOcclusionRT->getDepthStencilTexture() != sceneDepthNode->depthTex->texture;
- }
- else
- rebuildRT = true;
- if (rebuildRT)
- {
- RENDER_TEXTURE_DESC lightOcclusionRTDesc;
- lightOcclusionRTDesc.colorSurfaces[0].texture = lightOcclusionTex->texture;
- lightOcclusionRTDesc.colorSurfaces[0].face = 0;
- lightOcclusionRTDesc.colorSurfaces[0].numFaces = 1;
- lightOcclusionRTDesc.colorSurfaces[0].mipLevel = 0;
- lightOcclusionRTDesc.depthStencilSurface.texture = sceneDepthNode->depthTex->texture;
- lightOcclusionRTDesc.depthStencilSurface.face = 0;
- lightOcclusionRTDesc.depthStencilSurface.numFaces = 1;
- lightOcclusionRTDesc.depthStencilSurface.mipLevel = 0;
- mLightOcclusionRT = RenderTexture::create(lightOcclusionRTDesc);
- }
- // Render shadowed lights
- const ShadowRendering& shadowRenderer = inputs.viewGroup.getShadowRenderer();
- for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
- {
- LightType lightType = (LightType)i;
- auto& lights = lightData.getLights(lightType);
- UINT32 count = lightData.getNumShadowedLights(lightType);
- UINT32 offset = lightData.getNumUnshadowedLights(lightType);
- for (UINT32 j = 0; j < count; j++)
- {
- rapi.setRenderTarget(mLightOcclusionRT, FBT_DEPTH, RT_DEPTH_STENCIL);
- Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
- rapi.setViewport(area);
- rapi.clearViewport(FBT_COLOR, Color::ZERO);
- UINT32 lightIdx = offset + j;
- const RendererLight& light = *lights[lightIdx];
- shadowRenderer.renderShadowOcclusion(inputs.view, inputs.options.shadowFilteringQuality, light, gbuffer);
- rapi.setRenderTarget(outputRT, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
- StandardDeferred::instance().renderLight(lightType, light, inputs.view, gbuffer,
- lightOcclusionTex->texture);
- }
- }
- // Makes sure light accumulation can be read by following passes
- rapi.setRenderTarget(nullptr);
- resPool.release(lightOcclusionTex);
- }
- void RCNodeStandardDeferredLighting::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeStandardDeferredLighting::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeSceneDepth::getNodeId());
- if(gRenderBeast()->getFeatureSet() == RenderBeastFeatureSet::DesktopMacOS)
- {
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- }
- else
- {
- deps.push_back(RCNodeTiledDeferredLighting::getNodeId());
- if (view.getProperties().numSamples > 1)
- deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
- }
- return deps;
- }
- void RCNodeStandardDeferredIBL::render(const RenderCompositorNodeInputs& inputs)
- {
- RCNodeLightAccumulation* lightAccumNode = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[2]);
- SPtr<RenderTexture> outputRT = lightAccumNode->renderTarget;
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 numSamples = viewProps.numSamples;
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[0]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- RenderAPI& rapi = RenderAPI::instance();
- const RenderSettings& rs = inputs.view.getRenderSettings();
- bool isMSAA = viewProps.numSamples > 1;
- SPtr<PooledRenderTexture> iblRadianceTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width,
- height, TU_RENDERTARGET, numSamples, false));
- RENDER_TEXTURE_DESC rtDesc;
- rtDesc.colorSurfaces[0].texture = iblRadianceTex->texture;
- rtDesc.depthStencilSurface.texture = sceneDepthNode->depthTex->texture;
- SPtr<GpuParamBlockBuffer> perViewBuffer = inputs.view.getPerViewBuffer();
- SPtr<RenderTexture> iblRadianceRT = RenderTexture::create(rtDesc);
- rapi.setRenderTarget(iblRadianceRT, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
- const VisibleReflProbeData& probeData = inputs.viewGroup.getVisibleReflProbeData();
- ReflProbeParamBuffer reflProbeParams;
- reflProbeParams.populate(inputs.scene.skybox, probeData.getNumProbes(), inputs.scene.reflProbeCubemapsTex,
- viewProps.renderingReflections);
- // Prepare the texture for refl. probe and skybox rendering
- {
- SPtr<Texture> ssr;
- if (rs.screenSpaceReflections.enabled)
- {
- RCNodeSSR* ssrNode = static_cast<RCNodeSSR*>(inputs.inputNodes[3]);
- ssr = ssrNode->output->texture;
- }
- else
- ssr = Texture::BLACK;
- UINT32 nodeIdx = 4;
- SPtr<Texture> ssao;
- if (rs.ambientOcclusion.enabled)
- {
- RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[nodeIdx++]);
- ssao = ssaoNode->output->texture;
- }
- else
- ssao = Texture::WHITE;
- DeferredIBLSetupMat* mat = DeferredIBLSetupMat::getVariation(isMSAA, true);
- mat->bind(gbuffer, perViewBuffer, ssr, ssao, reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- // Draw pixels requiring per-sample evaluation
- if (isMSAA)
- {
- DeferredIBLSetupMat* msaaMat = DeferredIBLSetupMat::getVariation(true, false);
- msaaMat->bind(gbuffer, perViewBuffer, ssr, ssao, reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- }
- }
- if (viewProps.renderingReflections)
- {
- // Render refl. probes
- UINT32 numProbes = probeData.getNumProbes();
- for (UINT32 i = 0; i < numProbes; i++)
- {
- const ReflProbeData& probe = probeData.getProbeData(i);
- StandardDeferred::instance().renderReflProbe(probe, inputs.view, gbuffer, inputs.scene,
- reflProbeParams.buffer);
- }
- // Render sky
- SPtr<Texture> skyFilteredRadiance;
- if (inputs.scene.skybox)
- skyFilteredRadiance = inputs.scene.skybox->getFilteredRadiance();
- if (skyFilteredRadiance)
- {
- DeferredIBLSkyMat* skymat = DeferredIBLSkyMat::getVariation(isMSAA, true);
- skymat->bind(gbuffer, perViewBuffer, inputs.scene.skybox, reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- // Draw pixels requiring per-sample evaluation
- if (isMSAA)
- {
- DeferredIBLSkyMat* msaaMat = DeferredIBLSkyMat::getVariation(true, false);
- msaaMat->bind(gbuffer, perViewBuffer, inputs.scene.skybox, reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- }
- }
- }
- // Finalize rendered reflections and output them to main render target
- {
- rapi.setRenderTarget(outputRT, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
- DeferredIBLFinalizeMat* mat = DeferredIBLFinalizeMat::getVariation(isMSAA, true);
- mat->bind(gbuffer, perViewBuffer, iblRadianceTex->texture, RendererTextures::preintegratedEnvGF,
- reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- // Draw pixels requiring per-sample evaluation
- if (isMSAA)
- {
- DeferredIBLFinalizeMat* msaaMat = DeferredIBLFinalizeMat::getVariation(true, false);
- msaaMat->bind(gbuffer, perViewBuffer, iblRadianceTex->texture, RendererTextures::preintegratedEnvGF,
- reflProbeParams.buffer);
- gRendererUtility().drawScreenQuad();
- }
- }
- // Makes sure light accumulation can be read by following passes
- rapi.setRenderTarget(nullptr);
- }
- void RCNodeStandardDeferredIBL::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeStandardDeferredIBL::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeSceneDepth::getNodeId());
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- deps.push_back(RCNodeSSR::getNodeId());
- if (view.getRenderSettings().ambientOcclusion.enabled)
- deps.push_back(RCNodeSSAO::getNodeId());
- deps.push_back(RCNodeStandardDeferredLighting::getNodeId());
- return deps;
- }
- void RCNodeUnflattenLightAccum::render(const RenderCompositorNodeInputs& inputs)
- {
- RCNodeLightAccumulation* lightAccumNode = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[0]);
- FlatFramebufferToTextureMat* material = FlatFramebufferToTextureMat::get();
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(lightAccumNode->renderTarget, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
- material->execute(lightAccumNode->flattenedLightAccumBuffer->buffer, lightAccumNode->lightAccumulationTex->texture);
- }
- void RCNodeUnflattenLightAccum::clear()
- {
- output = nullptr;
- }
- SmallVector<StringID, 4> RCNodeUnflattenLightAccum::getDependencies(const RendererView& view)
- {
- return { RCNodeLightAccumulation::getNodeId() };
- }
- void RCNodeIndirectLighting::render(const RenderCompositorNodeInputs& inputs)
- {
- if (!inputs.view.getRenderSettings().enableIndirectLighting)
- return;
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[0]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
- RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[2]);
- SPtr<Texture> ssao;
- if (inputs.view.getRenderSettings().ambientOcclusion.enabled)
- {
- RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[4]);
- ssao = ssaoNode->output->texture;
- }
- else
- ssao = Texture::WHITE;
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- const LightProbes& lightProbes = inputs.scene.lightProbes;
- LightProbesInfo lpInfo = lightProbes.getInfo();
- IrradianceEvaluateMat* evaluateMat;
- SPtr<PooledRenderTexture> volumeIndices;
- if(lightProbes.hasAnyProbes())
- {
- POOLED_RENDER_TEXTURE_DESC volumeIndicesDesc;
- POOLED_RENDER_TEXTURE_DESC depthDesc;
- TetrahedraRenderMat::getOutputDesc(inputs.view, volumeIndicesDesc, depthDesc);
- volumeIndices = resPool.get(volumeIndicesDesc);
- SPtr<PooledRenderTexture> depthTex = resPool.get(depthDesc);
- RENDER_TEXTURE_DESC rtDesc;
- rtDesc.colorSurfaces[0].texture = volumeIndices->texture;
- rtDesc.depthStencilSurface.texture = depthTex->texture;
- SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(rt);
- rapi.clearRenderTarget(FBT_DEPTH);
- gRendererUtility().clear(-1);
- TetrahedraRenderMat* renderTetrahedra = TetrahedraRenderMat::getVariation(viewProps.numSamples > 1, true);
- renderTetrahedra->execute(inputs.view, sceneDepthNode->depthTex->texture, lpInfo.tetrahedraVolume, rt);
- rt = nullptr;
- resPool.release(depthTex);
- evaluateMat = IrradianceEvaluateMat::getVariation(viewProps.numSamples > 1, true, false);
- }
- else // Sky only
- {
- evaluateMat = IrradianceEvaluateMat::getVariation(viewProps.numSamples > 1, true, true);
- }
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- SPtr<Texture> volumeIndicesTex;
- if (volumeIndices)
- volumeIndicesTex = volumeIndices->texture;
- evaluateMat->execute(inputs.view, gbuffer, volumeIndicesTex, lpInfo, inputs.scene.skybox, ssao,
- lightAccumNode->renderTarget);
- if(volumeIndices)
- resPool.release(volumeIndices);
- }
- void RCNodeIndirectLighting::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeIndirectLighting::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeSceneDepth::getNodeId());
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- bool supportsTiledDeferred = gRenderBeast()->getFeatureSet() != RenderBeastFeatureSet::DesktopMacOS;
- if(supportsTiledDeferred)
- deps.push_back(RCNodeStandardDeferredLighting::getNodeId());
- else
- deps.push_back(RCNodeStandardDeferredIBL::getNodeId());
- if(view.getRenderSettings().ambientOcclusion.enabled)
- deps.push_back(RCNodeSSAO::getNodeId());
- if(supportsTiledDeferred)
- {
- if (view.getProperties().numSamples > 1)
- deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
- }
- return deps;
- }
- void RCNodeTiledDeferredIBL::render(const RenderCompositorNodeInputs& inputs)
- {
- const RenderSettings& rs = inputs.view.getRenderSettings();
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
- RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[3]);
- SPtr<Texture> ssr;
- if (rs.screenSpaceReflections.enabled)
- {
- RCNodeSSR* ssrNode = static_cast<RCNodeSSR*>(inputs.inputNodes[5]);
- ssr = ssrNode->output->texture;
- }
- else
- ssr = Texture::BLACK;
- UINT32 nodeIdx = 6;
- SPtr<Texture> ssao;
- if (rs.ambientOcclusion.enabled)
- {
- RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[nodeIdx++]);
- ssao = ssaoNode->output->texture;
- }
- else
- ssao = Texture::WHITE;
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- SPtr<Texture> msaaCoverage;
- if(viewProps.numSamples > 1)
- {
- RCNodeMSAACoverage* coverageNode = static_cast<RCNodeMSAACoverage*>(inputs.inputNodes[nodeIdx++]);
- msaaCoverage = coverageNode->output->texture;
- }
- TiledDeferredImageBasedLightingMat* material = TiledDeferredImageBasedLightingMat::getVariation(viewProps.numSamples);
- TiledDeferredImageBasedLightingMat::Inputs iblInputs;
- iblInputs.gbuffer.albedo = gbufferNode->albedoTex->texture;
- iblInputs.gbuffer.normals = gbufferNode->normalTex->texture;
- iblInputs.gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- iblInputs.gbuffer.depth = sceneDepthNode->depthTex->texture;
- iblInputs.sceneColorTex = sceneColorNode->sceneColorTex->texture;
- iblInputs.lightAccumulation = lightAccumNode->lightAccumulationTex->texture;
- iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
- iblInputs.ambientOcclusion = ssao;
- iblInputs.ssr = ssr;
- iblInputs.msaaCoverage = msaaCoverage;
- if(sceneColorNode->flattenedSceneColorBuffer)
- iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
- material->execute(inputs.view, inputs.scene, inputs.viewGroup.getVisibleReflProbeData(), iblInputs);
- }
- void RCNodeTiledDeferredIBL::clear()
- {
- output = nullptr;
- }
- SmallVector<StringID, 4> RCNodeTiledDeferredIBL::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeSceneColor::getNodeId());
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeSceneDepth::getNodeId());
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- deps.push_back(RCNodeIndirectLighting::getNodeId());
- deps.push_back(RCNodeSSR::getNodeId());
- if(view.getRenderSettings().ambientOcclusion.enabled)
- deps.push_back(RCNodeSSAO::getNodeId());
- if(view.getProperties().numSamples > 1)
- deps.push_back(RCNodeMSAACoverage::getNodeId());
- return deps;
- }
- void RCNodeUnflattenSceneColor::render(const RenderCompositorNodeInputs& inputs)
- {
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- FlatFramebufferToTextureMat* material = FlatFramebufferToTextureMat::get();
- int readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(sceneColorNode->renderTarget, readOnlyFlags, RT_DEPTH_STENCIL);
- Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
- rapi.setViewport(area);
- material->execute(sceneColorNode->flattenedSceneColorBuffer->buffer, sceneColorNode->sceneColorTex->texture);
- }
- void RCNodeUnflattenSceneColor::clear()
- {
- output = nullptr;
- }
- SmallVector<StringID, 4> RCNodeUnflattenSceneColor::getDependencies(const RendererView& view)
- {
- return { RCNodeSceneColor::getNodeId() };
- }
- RCNodeClusteredForward::RCNodeClusteredForward()
- {
- SAMPLER_STATE_DESC desc;
- desc.minFilter = FO_POINT;
- desc.magFilter = FO_POINT;
- desc.mipFilter = FO_POINT;
- desc.addressMode.u = TAM_CLAMP;
- desc.addressMode.v = TAM_CLAMP;
- desc.addressMode.w = TAM_CLAMP;
- mSSRAOSamplerState = SamplerState::create(desc);
- }
- void RCNodeClusteredForward::render(const RenderCompositorNodeInputs& inputs)
- {
- const SceneInfo& sceneInfo = inputs.scene;
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- const VisibleLightData& visibleLightData = inputs.viewGroup.getVisibleLightData();
- const VisibleReflProbeData& visibleReflProbeData = inputs.viewGroup.getVisibleReflProbeData();
- const LightGrid& lightGrid = inputs.view.getLightGrid();
- SPtr<GpuParamBlockBuffer> gridParams;
- SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
- SPtr<GpuBuffer> gridProbeOffsetsAndSize, gridProbeIndices;
- lightGrid.getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices,
- gridParams);
- // Prepare refl. probe param buffer
- ReflProbeParamBuffer reflProbeParamBuffer;
- reflProbeParamBuffer.populate(sceneInfo.skybox, visibleReflProbeData.getNumProbes(), sceneInfo.reflProbeCubemapsTex,
- viewProps.renderingReflections);
- SPtr<Texture> skyFilteredRadiance;
- if(sceneInfo.skybox)
- skyFilteredRadiance = sceneInfo.skybox->getFilteredRadiance();
- // Prepare objects for rendering
- const VisibilityInfo& visibility = inputs.view.getVisibilityMasks();
- UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
- for (UINT32 i = 0; i < numRenderables; i++)
- {
- if (!visibility.renderables[i])
- continue;
- for (auto& element : sceneInfo.renderables[i]->elements)
- {
- bool isTransparent = (element.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
- if (!isTransparent)
- continue;
- // Note: It would be nice to be able to set this once and keep it, only updating if the buffers actually
- // change (e.g. when growing).
- SPtr<GpuParams> gpuParams = element.params->getGpuParams();
- for(UINT32 j = 0; j < GPT_COUNT; j++)
- {
- const GpuParamBinding& binding = element.gridParamsBindings[j];
- if (binding.slot != (UINT32)-1)
- gpuParams->setParamBlockBuffer(binding.set, binding.slot, gridParams);
- }
- element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
- element.gridLightIndicesParam.set(gridLightIndices);
- element.lightsBufferParam.set(visibleLightData.getLightBuffer());
- // Image based lighting params
- ImageBasedLightingParams& iblParams = element.imageBasedParams;
- if (iblParams.reflProbeParamBindings.set != (UINT32)-1)
- {
- gpuParams->setParamBlockBuffer(
- iblParams.reflProbeParamBindings.set,
- iblParams.reflProbeParamBindings.slot,
- reflProbeParamBuffer.buffer);
- }
- element.gridProbeOffsetsAndSizeParam.set(gridProbeOffsetsAndSize);
- iblParams.reflectionProbeIndicesParam.set(gridProbeIndices);
- iblParams.reflectionProbesParam.set(visibleReflProbeData.getProbeBuffer());
- iblParams.skyReflectionsTexParam.set(skyFilteredRadiance);
- iblParams.ambientOcclusionTexParam.set(Texture::WHITE); // Note: Add SSAO here?
- iblParams.ssrTexParam.set(Texture::BLACK); // Note: Add SSR here?
- iblParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
- iblParams.preintegratedEnvBRDFParam.set(RendererTextures::preintegratedEnvGF);
- iblParams.ssrSampParam.set(mSSRAOSamplerState);
- iblParams.ambientOcclusionSampParam.set(mSSRAOSamplerState);
- }
- }
- // TODO: Transparent objects cannot receive shadows. In order to support this I'd have to render the light occlusion
- // for all lights affecting this object into a single (or a few) textures. I can likely use texture arrays for this,
- // or to avoid sampling many textures, perhaps just jam it all in one or few texture channels.
- const Vector<RenderQueueElement>& transparentElements = inputs.view.getTransparentQueue()->getSortedElements();
- for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
- {
- BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
- SPtr<Material> material = renderElem->material;
- if (iter->applyPass)
- gRendererUtility().setPass(material, iter->passIdx, renderElem->techniqueIdx);
- gRendererUtility().setPassParams(renderElem->params, iter->passIdx);
- if(renderElem->morphVertexDeclaration == nullptr)
- gRendererUtility().draw(renderElem->mesh, renderElem->subMesh);
- else
- gRendererUtility().drawMorph(renderElem->mesh, renderElem->subMesh, renderElem->morphShapeBuffer,
- renderElem->morphVertexDeclaration);
- }
- // Trigger post-lighting callbacks
- Camera* sceneCamera = inputs.view.getSceneCamera();
- if (sceneCamera != nullptr)
- {
- for(auto& extension : inputs.extPostLighting)
- {
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- }
- }
- }
- void RCNodeClusteredForward::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeClusteredForward::getDependencies(const RendererView& view)
- {
- return { RCNodeSceneColor::getNodeId(), RCNodeSkybox::getNodeId() };
- }
- void RCNodeSkybox::render(const RenderCompositorNodeInputs& inputs)
- {
- Skybox* skybox = inputs.scene.skybox;
- SPtr<Texture> radiance = skybox ? skybox->getTexture() : nullptr;
- if (radiance != nullptr)
- {
- SkyboxMat* material = SkyboxMat::getVariation(false);
- material->bind(inputs.view.getPerViewBuffer(), radiance, Color::White);
- }
- else
- {
- Color clearColor = inputs.view.getProperties().clearColor;
- SkyboxMat* material = SkyboxMat::getVariation(true);
- material->bind(inputs.view.getPerViewBuffer(), nullptr, clearColor);
- }
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- int readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(sceneColorNode->renderTarget, readOnlyFlags, RT_COLOR0 | RT_DEPTH_STENCIL);
- Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
- rapi.setViewport(area);
- SPtr<Mesh> mesh = gRendererUtility().getSkyBoxMesh();
- gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
- }
- void RCNodeSkybox::clear()
- { }
- SmallVector<StringID, 4> RCNodeSkybox::getDependencies(const RendererView& view)
- {
- bool supportsTiledDeferred = gRenderBeast()->getFeatureSet() != RenderBeastFeatureSet::DesktopMacOS;
- SmallVector<StringID, 4> deps;
- deps.push_back(RCNodeSceneColor::getNodeId());
- if(supportsTiledDeferred)
- {
- deps.push_back(RCNodeTiledDeferredIBL::getNodeId());
- if (view.getProperties().numSamples > 1)
- deps.push_back(RCNodeUnflattenSceneColor::getNodeId());
- }
- else
- deps.push_back(RCNodeIndirectLighting::getNodeId());
- return deps;
- }
- void RCNodeFinalResolve::render(const RenderCompositorNodeInputs& inputs)
- {
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- SPtr<Texture> input;
- if(viewProps.runPostProcessing)
- {
- RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[0]);
- // Note: Ideally the last PP effect could write directly to the final target and we could avoid this copy
- input = postProcessNode->getLastOutput();
- }
- else
- {
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- input = sceneColorNode->sceneColorTex->texture;
- }
- SPtr<RenderTarget> target = viewProps.target;
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(target);
- rapi.setViewport(viewProps.nrmViewRect);
- gRendererUtility().blit(input, Rect2I::EMPTY, viewProps.flipView);
- if(viewProps.encodeDepth)
- {
- RCNodeResolvedSceneDepth* resolvedSceneDepthNode = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
- EncodeDepthMat* encodeDepthMat = EncodeDepthMat::get();
- encodeDepthMat->execute(resolvedSceneDepthNode->output->texture, viewProps.depthEncodeNear,
- viewProps.depthEncodeFar, target);
- }
- // Trigger overlay callbacks
- Camera* sceneCamera = inputs.view.getSceneCamera();
- if (sceneCamera != nullptr)
- {
- for(auto& extension : inputs.extOverlay)
- {
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- }
- }
- }
- void RCNodeFinalResolve::clear()
- { }
- SmallVector<StringID, 4> RCNodeFinalResolve::getDependencies(const RendererView& view)
- {
- const RendererViewProperties& viewProps = view.getProperties();
- SmallVector<StringID, 4> deps;
- if(viewProps.runPostProcessing)
- {
- deps.push_back(RCNodePostProcess::getNodeId());
- deps.push_back(RCNodeFXAA::getNodeId());
- }
- else
- {
- deps.push_back(RCNodeSceneColor::getNodeId());
- deps.push_back(RCNodeClusteredForward::getNodeId());
- }
- if(viewProps.encodeDepth)
- deps.push_back(RCNodeResolvedSceneDepth::getNodeId());
- return deps;
- }
- RCNodePostProcess::RCNodePostProcess()
- :mOutput(), mAllocated()
- { }
- void RCNodePostProcess::getAndSwitch(const RendererView& view, SPtr<RenderTexture>& output, SPtr<Texture>& lastFrame) const
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- if(!mAllocated[mCurrentIdx])
- {
- mOutput[mCurrentIdx] = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA8, width, height,
- TU_RENDERTARGET, 1, false));
- mAllocated[mCurrentIdx] = true;
- }
- output = mOutput[mCurrentIdx]->renderTexture;
- UINT32 otherIdx = (mCurrentIdx + 1) % 2;
- if (mAllocated[otherIdx])
- lastFrame = mOutput[otherIdx]->texture;
- mCurrentIdx = otherIdx;
- }
- SPtr<Texture> RCNodePostProcess::getLastOutput() const
- {
- UINT32 otherIdx = (mCurrentIdx + 1) % 2;
- if (mAllocated[otherIdx])
- return mOutput[otherIdx]->texture;
-
- return nullptr;
- }
- void RCNodePostProcess::render(const RenderCompositorNodeInputs& inputs)
- {
- // Do nothing, this is just a helper node
- }
- void RCNodePostProcess::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- if (mAllocated[0])
- resPool.release(mOutput[0]);
- if (mAllocated[1])
- resPool.release(mOutput[1]);
- mAllocated[0] = false;
- mAllocated[1] = false;
- mCurrentIdx = 0;
- }
- SmallVector<StringID, 4> RCNodePostProcess::getDependencies(const RendererView& view)
- {
- return {};
- }
- RCNodeTonemapping::~RCNodeTonemapping()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- if (mTonemapLUT)
- resPool.release(mTonemapLUT);
- if (prevEyeAdaptation)
- resPool.release(prevEyeAdaptation);
- }
- void RCNodeTonemapping::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- const RenderSettings& settings = inputs.view.getRenderSettings();
- RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
- RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[2]);
- SPtr<Texture> sceneColor = sceneColorNode->sceneColorTex->texture;
- bool hdr = settings.enableHDR;
- bool msaa = viewProps.numSamples > 1;
- if(hdr && settings.enableAutoExposure)
- {
- // Downsample scene
- DownsampleMat* downsampleMat = DownsampleMat::getVariation(1, msaa);
- SPtr<PooledRenderTexture> downsampledScene = resPool.get(DownsampleMat::getOutputDesc(sceneColor));
- downsampleMat->execute(sceneColor, downsampledScene->renderTexture);
- if(useHistogramEyeAdapatation(inputs))
- {
- // Generate histogram
- SPtr<PooledRenderTexture> eyeAdaptHistogram =
- resPool.get(EyeAdaptHistogramMat::getOutputDesc(downsampledScene->texture));
- EyeAdaptHistogramMat* eyeAdaptHistogramMat = EyeAdaptHistogramMat::get();
- eyeAdaptHistogramMat->execute(downsampledScene->texture, eyeAdaptHistogram->texture, settings.autoExposure);
- // Reduce histogram
- SPtr<PooledRenderTexture> reducedHistogram = resPool.get(EyeAdaptHistogramReduceMat::getOutputDesc());
- SPtr<Texture> prevFrameEyeAdaptation;
- if (prevEyeAdaptation != nullptr)
- prevFrameEyeAdaptation = prevEyeAdaptation->texture;
- EyeAdaptHistogramReduceMat* eyeAdaptHistogramReduce = EyeAdaptHistogramReduceMat::get();
- eyeAdaptHistogramReduce->execute(
- downsampledScene->texture,
- eyeAdaptHistogram->texture,
- prevFrameEyeAdaptation,
- reducedHistogram->renderTexture);
- resPool.release(downsampledScene);
- downsampledScene = nullptr;
- resPool.release(eyeAdaptHistogram);
- eyeAdaptHistogram = nullptr;
- // Generate eye adaptation value
- eyeAdaptation = resPool.get(EyeAdaptationMat::getOutputDesc());
- EyeAdaptationMat* eyeAdaptationMat = EyeAdaptationMat::get();
- eyeAdaptationMat->execute(
- reducedHistogram->texture,
- eyeAdaptation->renderTexture,
- inputs.frameInfo.timeDelta,
- settings.autoExposure,
- settings.exposureScale);
- resPool.release(reducedHistogram);
- reducedHistogram = nullptr;
- }
- else
- {
- // Populate alpha values of the downsampled texture with luminance
- SPtr<PooledRenderTexture> luminanceTex =
- resPool.get(EyeAdaptationBasicSetupMat::getOutputDesc(downsampledScene->texture));
- EyeAdaptationBasicSetupMat* setupMat = EyeAdaptationBasicSetupMat::get();
- setupMat->execute(
- downsampledScene->texture,
- luminanceTex->renderTexture,
- inputs.frameInfo.timeDelta,
- settings.autoExposure,
- settings.exposureScale);
- SPtr<Texture> downsampleInput = luminanceTex->texture;
- luminanceTex = nullptr;
- // Downsample some more
- for(UINT32 i = 0; i < 5; i++)
- {
- downsampleMat = DownsampleMat::getVariation(1, false);
- SPtr<PooledRenderTexture> downsampledLuminance =
- resPool.get(DownsampleMat::getOutputDesc(downsampleInput));
- downsampleMat->execute(downsampleInput, downsampledLuminance->renderTexture);
- downsampleInput = downsampledLuminance->texture;
- }
- // Generate eye adaptation value
- EyeAdaptationBasicMat* eyeAdaptationMat = EyeAdaptationBasicMat::get();
- SPtr<Texture> prevFrameEyeAdaptation;
- if (prevEyeAdaptation != nullptr)
- prevFrameEyeAdaptation = prevEyeAdaptation->texture;
- eyeAdaptation = resPool.get(EyeAdaptationBasicMat::getOutputDesc());
- eyeAdaptationMat->execute(
- downsampleInput,
- prevFrameEyeAdaptation,
- eyeAdaptation->renderTexture,
- inputs.frameInfo.timeDelta,
- settings.autoExposure,
- settings.exposureScale);
- }
- }
- else
- {
- if(prevEyeAdaptation)
- resPool.release(prevEyeAdaptation);
- prevEyeAdaptation = nullptr;
- eyeAdaptation = nullptr;
- }
- bool volumeLUT = inputs.featureSet == RenderBeastFeatureSet::Desktop;
- bool gammaOnly;
- bool autoExposure;
- if (hdr)
- {
- if (settings.enableTonemapping)
- {
- UINT64 latestHash = inputs.view.getRenderSettingsHash();
- bool tonemapLUTDirty = mTonemapLastUpdateHash != latestHash;
- if (tonemapLUTDirty) // Rebuild LUT if PP settings changed
- {
- CreateTonemapLUTMat* createLUT = CreateTonemapLUTMat::getVariation(volumeLUT);
- if(mTonemapLUT == nullptr)
- mTonemapLUT = resPool.get(createLUT->getOutputDesc());
- if(volumeLUT)
- createLUT->execute3D(mTonemapLUT->texture, settings);
- else
- createLUT->execute2D(mTonemapLUT->renderTexture, settings);
- mTonemapLastUpdateHash = latestHash;
- }
- gammaOnly = false;
- }
- else
- gammaOnly = true;
- autoExposure = settings.enableAutoExposure;
- }
- else
- {
- gammaOnly = true;
- autoExposure = false;
- }
- if(gammaOnly)
- {
- if(mTonemapLUT)
- {
- resPool.release(mTonemapLUT);
- mTonemapLUT = nullptr;
- }
- }
- TonemappingMat* tonemapping = TonemappingMat::getVariation(volumeLUT, gammaOnly, autoExposure, msaa);
- SPtr<RenderTexture> ppOutput;
- SPtr<Texture> ppLastFrame;
- postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
- SPtr<Texture> eyeAdaptationTex;
- if (eyeAdaptation)
- eyeAdaptationTex = eyeAdaptation->texture;
- SPtr<Texture> tonemapLUTTex;
- if (mTonemapLUT)
- tonemapLUTTex = mTonemapLUT->texture;
- tonemapping->execute(sceneColor, eyeAdaptationTex, tonemapLUTTex, ppOutput, settings);
- }
- void RCNodeTonemapping::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- // Save eye adaptation for next frame
- if(prevEyeAdaptation)
- resPool.release(prevEyeAdaptation);
- std::swap(eyeAdaptation, prevEyeAdaptation);
- }
-
- bool RCNodeTonemapping::useHistogramEyeAdapatation(const RenderCompositorNodeInputs& inputs)
- {
- return inputs.featureSet == RenderBeastFeatureSet::Desktop;
- }
- SmallVector<StringID, 4> RCNodeTonemapping::getDependencies(const RendererView& view)
- {
- return{ RCNodeSceneColor::getNodeId(), RCNodeClusteredForward::getNodeId(), RCNodePostProcess::getNodeId() };
- }
- void RCNodeGaussianDOF::render(const RenderCompositorNodeInputs& inputs)
- {
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
- RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[2]);
- const DepthOfFieldSettings& settings = inputs.view.getRenderSettings().depthOfField;
- bool near = settings.nearBlurAmount > 0.0f;
- bool far = settings.farBlurAmount > 0.0f;
- bool enabled = settings.enabled && (near || far);
- if(!enabled)
- return;
- GaussianDOFSeparateMat* separateMat = GaussianDOFSeparateMat::getVariation(near, far);
- GaussianDOFCombineMat* combineMat = GaussianDOFCombineMat::getVariation(near, far);
- GaussianBlurMat* blurMat = GaussianBlurMat::get();
- SPtr<RenderTexture> ppOutput;
- SPtr<Texture> ppLastFrame;
- postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
- separateMat->execute(ppLastFrame, sceneDepthNode->depthTex->texture, inputs.view, settings);
- SPtr<PooledRenderTexture> nearTex, farTex;
- if(near && far)
- {
- nearTex = separateMat->getOutput(0);
- farTex = separateMat->getOutput(1);
- }
- else
- {
- if (near)
- nearTex = separateMat->getOutput(0);
- else
- farTex = separateMat->getOutput(0);
- }
- // Blur the out of focus pixels
- // Note: Perhaps set up stencil so I can avoid performing blur on unused parts of the textures?
- const TextureProperties& texProps = nearTex ? nearTex->texture->getProperties() : farTex->texture->getProperties();
- POOLED_RENDER_TEXTURE_DESC tempTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(texProps.getFormat(),
- texProps.getWidth(), texProps.getHeight(), TU_RENDERTARGET);
- SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTexDesc);
- SPtr<Texture> blurredNearTex;
- if(nearTex)
- {
- blurMat->execute(nearTex->texture, settings.nearBlurAmount, tempTexture->renderTexture);
- blurredNearTex = tempTexture->texture;
- }
- SPtr<Texture> blurredFarTex;
- if(farTex)
- {
- // If temporary texture is used up, re-use the original near texture for the blurred result
- if(blurredNearTex)
- {
- blurMat->execute(farTex->texture, settings.farBlurAmount, nearTex->renderTexture);
- blurredFarTex = nearTex->texture;
- }
- else // Otherwise just use the temporary
- {
- blurMat->execute(farTex->texture, settings.farBlurAmount, tempTexture->renderTexture);
- blurredFarTex = tempTexture->texture;
- }
- }
- combineMat->execute(ppLastFrame, blurredNearTex, blurredFarTex,
- sceneDepthNode->depthTex->texture, ppOutput, inputs.view, settings);
- separateMat->release();
- GpuResourcePool::instance().release(tempTexture);
- }
- void RCNodeGaussianDOF::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeGaussianDOF::getDependencies(const RendererView& view)
- {
- return { RCNodeTonemapping::getNodeId(), RCNodeSceneDepth::getNodeId(), RCNodePostProcess::getNodeId() };
- }
- void RCNodeFXAA::render(const RenderCompositorNodeInputs& inputs)
- {
- const RenderSettings& settings = inputs.view.getRenderSettings();
- if (!settings.enableFXAA)
- return;
- RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[1]);
- SPtr<RenderTexture> ppOutput;
- SPtr<Texture> ppLastFrame;
- postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
- // Note: I could skip executing FXAA over DOF and motion blurred pixels
- FXAAMat* fxaa = FXAAMat::get();
- fxaa->execute(ppLastFrame, ppOutput);
- }
- void RCNodeFXAA::clear()
- {
- // Do nothing
- }
- SmallVector<StringID, 4> RCNodeFXAA::getDependencies(const RendererView& view)
- {
- return { RCNodeGaussianDOF::getNodeId(), RCNodePostProcess::getNodeId() };
- }
- void RCNodeResolvedSceneDepth::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
- if (viewProps.numSamples > 1)
- {
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height,
- TU_DEPTHSTENCIL, 1, false));
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(output->renderTexture);
- rapi.clearRenderTarget(FBT_STENCIL);
- gRendererUtility().blit(sceneDepthNode->depthTex->texture, Rect2I::EMPTY, false, true);
- mPassThrough = false;
- }
- else
- {
- output = sceneDepthNode->depthTex;
- mPassThrough = true;
- }
- }
- void RCNodeResolvedSceneDepth::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- if (!mPassThrough)
- resPool.release(output);
- else
- output = nullptr;
- mPassThrough = false;
- }
- SmallVector<StringID, 4> RCNodeResolvedSceneDepth::getDependencies(const RendererView& view)
- {
- // GBuffer require because it renders the base pass (populates the depth buffer)
- return { RCNodeSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
- }
- void RCNodeHiZ::render(const RenderCompositorNodeInputs& inputs)
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- RCNodeResolvedSceneDepth* resolvedSceneDepth = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- UINT32 size = Bitwise::nextPow2(std::max(width, height));
- UINT32 numMips = PixelUtil::getMaxMipmaps(size, size, 1, PF_R32F);
- size = 1 << numMips;
- // Note: Use the 32-bit buffer here as 16-bit causes too much banding (most of the scene gets assigned 4-5 different
- // depth values).
- // - When I add UNORM 16-bit format I should be able to switch to that
- output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R32F, size, size, TU_RENDERTARGET, 1, false, 1,
- numMips));
- Rect2 srcRect = viewProps.nrmViewRect;
- // If viewport size is odd, adjust UV
- srcRect.width += (viewProps.viewRect.width % 2) * (1.0f / viewProps.viewRect.width);
- srcRect.height += (viewProps.viewRect.height % 2) * (1.0f / viewProps.viewRect.height);
- // Generate first mip
- RENDER_TEXTURE_DESC rtDesc;
- rtDesc.colorSurfaces[0].texture = output->texture;
- rtDesc.colorSurfaces[0].mipLevel = 0;
- SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
- Rect2 destRect;
- bool downsampledFirstMip = false; // Not used currently
- if (downsampledFirstMip)
- {
- // Make sure that 1 pixel in HiZ maps to a 2x2 block in source
- destRect = Rect2(0, 0,
- Math::ceilToInt(viewProps.viewRect.width / 2.0f) / (float)size,
- Math::ceilToInt(viewProps.viewRect.height / 2.0f) / (float)size);
- BuildHiZMat* material = BuildHiZMat::get();
- material->execute(resolvedSceneDepth->output->texture, 0, srcRect, destRect, rt);
- }
- else // First level is just a copy of the depth buffer
- {
- destRect = Rect2(0, 0,
- viewProps.viewRect.width / (float)size,
- viewProps.viewRect.height / (float)size);
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(rt);
- rapi.setViewport(destRect);
- Rect2I srcAreaInt;
- srcAreaInt.x = (INT32)(srcRect.x * viewProps.viewRect.width);
- srcAreaInt.y = (INT32)(srcRect.y * viewProps.viewRect.height);
- srcAreaInt.width = (UINT32)(srcRect.width * viewProps.viewRect.width);
- srcAreaInt.height = (UINT32)(srcRect.height * viewProps.viewRect.height);
- gRendererUtility().blit(resolvedSceneDepth->output->texture, srcAreaInt);
- rapi.setViewport(Rect2(0, 0, 1, 1));
- }
- // Generate remaining mip levels
- for(UINT32 i = 1; i <= numMips; i++)
- {
- rtDesc.colorSurfaces[0].mipLevel = i;
- rt = RenderTexture::create(rtDesc);
- BuildHiZMat* material = BuildHiZMat::get();
- material->execute(output->texture, i - 1, destRect, destRect, rt);
- }
- }
- void RCNodeHiZ::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(output);
- }
- SmallVector<StringID, 4> RCNodeHiZ::getDependencies(const RendererView& view)
- {
- // Note: This doesn't actually use any gbuffer textures, but node is a dependency because it renders to the depth
- // buffer. In order to avoid keeping gbuffer textures alive I could separate out the base pass into its own node
- // perhaps. But at the moment it doesn't matter, as anything using HiZ also needs gbuffer.
- return { RCNodeResolvedSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
- }
- void RCNodeSSAO::render(const RenderCompositorNodeInputs& inputs)
- {
- /** Maximum valid depth range within samples in a sample set. In meters. */
- static const float DEPTH_RANGE = 1.0f;
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- const AmbientOcclusionSettings& settings = inputs.view.getRenderSettings().ambientOcclusion;
- RCNodeResolvedSceneDepth* resolvedDepthNode = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
- SPtr<Texture> sceneDepth = resolvedDepthNode->output->texture;
- SPtr<Texture> sceneNormals = gbufferNode->normalTex->texture;
- const TextureProperties& normalsProps = sceneNormals->getProperties();
- SPtr<PooledRenderTexture> resolvedNormals;
- RenderAPI& rapi = RenderAPI::instance();
- if(sceneNormals->getProperties().getNumSamples() > 1)
- {
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(normalsProps.getFormat(),
- normalsProps.getWidth(), normalsProps.getHeight(), TU_RENDERTARGET);
- resolvedNormals = resPool.get(desc);
- rapi.setRenderTarget(resolvedNormals->renderTexture);
- gRendererUtility().blit(sceneNormals);
- sceneNormals = resolvedNormals->texture;
- }
- // Multiple downsampled AO levels are used to minimize cache trashing. Downsampled AO targets use larger radius,
- // whose contents are then blended with the higher level.
- UINT32 quality = settings.quality;
- UINT32 numDownsampleLevels = 0;
- if (quality > 1)
- numDownsampleLevels = 1;
- else if (quality > 2)
- numDownsampleLevels = 2;
- SSAODownsampleMat* downsample = SSAODownsampleMat::get();
- SPtr<PooledRenderTexture> setupTex0;
- if(numDownsampleLevels > 0)
- {
- Vector2I downsampledSize(
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
- );
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, downsampledSize.x,
- downsampledSize.y, TU_RENDERTARGET);
- setupTex0 = GpuResourcePool::instance().get(desc);
- downsample->execute(inputs.view, sceneDepth, sceneNormals, setupTex0->renderTexture, DEPTH_RANGE);
- }
- SPtr<PooledRenderTexture> setupTex1;
- if(numDownsampleLevels > 1)
- {
- Vector2I downsampledSize(
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
- );
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, downsampledSize.x,
- downsampledSize.y, TU_RENDERTARGET);
- setupTex1 = GpuResourcePool::instance().get(desc);
- downsample->execute(inputs.view, sceneDepth, sceneNormals, setupTex1->renderTexture, DEPTH_RANGE);
- }
- SSAOTextureInputs textures;
- textures.sceneDepth = sceneDepth;
- textures.sceneNormals = sceneNormals;
- textures.randomRotations = RendererTextures::ssaoRandomization4x4;
- SPtr<PooledRenderTexture> downAOTex1;
- if(numDownsampleLevels > 1)
- {
- textures.aoSetup = setupTex1->texture;
- Vector2I downsampledSize(
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
- );
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x,
- downsampledSize.y, TU_RENDERTARGET);
- downAOTex1 = GpuResourcePool::instance().get(desc);
- SSAOMat* ssaoMat = SSAOMat::getVariation(false, false, quality);
- ssaoMat->execute(inputs.view, textures, downAOTex1->renderTexture, settings);
- GpuResourcePool::instance().release(setupTex1);
- setupTex1 = nullptr;
- }
- SPtr<PooledRenderTexture> downAOTex0;
- if(numDownsampleLevels > 0)
- {
- textures.aoSetup = setupTex0->texture;
- if(downAOTex1)
- textures.aoDownsampled = downAOTex1->texture;
- Vector2I downsampledSize(
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
- std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
- );
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x,
- downsampledSize.y, TU_RENDERTARGET);
- downAOTex0 = GpuResourcePool::instance().get(desc);
- bool upsample = numDownsampleLevels > 1;
- SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, false, quality);
- ssaoMat->execute(inputs.view, textures, downAOTex0->renderTexture, settings);
- if(upsample)
- {
- GpuResourcePool::instance().release(downAOTex1);
- downAOTex1 = nullptr;
- }
- }
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width, height, TU_RENDERTARGET));
- {
- if(setupTex0)
- textures.aoSetup = setupTex0->texture;
- if(downAOTex0)
- textures.aoDownsampled = downAOTex0->texture;
- bool upsample = numDownsampleLevels > 0;
- SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, true, quality);
- ssaoMat->execute(inputs.view, textures, output->renderTexture, settings);
- }
- if(resolvedNormals)
- {
- GpuResourcePool::instance().release(resolvedNormals);
- resolvedNormals = nullptr;
- }
- if(numDownsampleLevels > 0)
- {
- GpuResourcePool::instance().release(setupTex0);
- GpuResourcePool::instance().release(downAOTex0);
- }
- // Blur the output
- // Note: If I implement temporal AA then this can probably be avoided. I can instead jitter the sample offsets
- // each frame, and averaging them out should yield blurred AO.
- if(quality > 1) // On level 0 we don't blur at all, on level 1 we use the ad-hoc blur in shader
- {
- const RenderTargetProperties& rtProps = output->renderTexture->getProperties();
- POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, rtProps.width,
- rtProps.height, TU_RENDERTARGET);
- SPtr<PooledRenderTexture> blurIntermediateTex = GpuResourcePool::instance().get(desc);
- SSAOBlurMat* blurHorz = SSAOBlurMat::getVariation(true);
- SSAOBlurMat* blurVert = SSAOBlurMat::getVariation(false);
- blurHorz->execute(inputs.view, output->texture, sceneDepth, blurIntermediateTex->renderTexture, DEPTH_RANGE);
- blurVert->execute(inputs.view, blurIntermediateTex->texture, sceneDepth, output->renderTexture, DEPTH_RANGE);
- GpuResourcePool::instance().release(blurIntermediateTex);
- }
- RenderAPI::instance().setRenderTarget(nullptr);
- }
- void RCNodeSSAO::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- resPool.release(output);
- }
- SmallVector<StringID, 4> RCNodeSSAO::getDependencies(const RendererView& view)
- {
- return { RCNodeResolvedSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
- }
- RCNodeSSR::~RCNodeSSR()
- {
- deallocOutputs();
- }
- void RCNodeSSR::render(const RenderCompositorNodeInputs& inputs)
- {
- const ScreenSpaceReflectionsSettings& settings = inputs.view.getRenderSettings().screenSpaceReflections;
- if (settings.enabled)
- {
- RenderAPI& rapi = RenderAPI::instance();
- RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
- RCNodeLightAccumulation* lightAccumNode = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[1]);
- RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[2]);
- RCNodeHiZ* hiZNode = static_cast<RCNodeHiZ*>(inputs.inputNodes[3]);
- RCNodeResolvedSceneDepth* resolvedSceneDepthNode = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[4]);
- GpuResourcePool& resPool = GpuResourcePool::instance();
- const RendererViewProperties& viewProps = inputs.view.getProperties();
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- SPtr<Texture> hiZ = hiZNode->output->texture;
- // This will be executing before scene color is resolved, so get the light accum buffer instead
- SPtr<Texture> sceneColor = lightAccumNode->lightAccumulationTex->texture;
- // Resolve multiple samples if MSAA is used
- SPtr<PooledRenderTexture> resolvedSceneColor;
- if(viewProps.numSamples > 1)
- {
- resolvedSceneColor = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width, height,
- TU_RENDERTARGET));
- rapi.setRenderTarget(resolvedSceneColor->renderTexture);
- gRendererUtility().blit(sceneColor);
- sceneColor = resolvedSceneColor->texture;
- }
- GBufferTextures gbuffer;
- gbuffer.albedo = gbufferNode->albedoTex->texture;
- gbuffer.normals = gbufferNode->normalTex->texture;
- gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
- gbuffer.depth = sceneDepthNode->depthTex->texture;
- SSRStencilMat* stencilMat = SSRStencilMat::getVariation(viewProps.numSamples > 1, true);
- // Note: Making the assumption that the stencil buffer is clear at this point
- rapi.setRenderTarget(resolvedSceneDepthNode->output->renderTexture, FBT_DEPTH, RT_DEPTH_STENCIL);
- stencilMat->execute(inputs.view, gbuffer, settings);
- SPtr<PooledRenderTexture> traceOutput = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width,
- height, TU_RENDERTARGET));
- RENDER_TEXTURE_DESC traceRtDesc;
- traceRtDesc.colorSurfaces[0].texture = traceOutput->texture;
- traceRtDesc.depthStencilSurface.texture = resolvedSceneDepthNode->output->texture;
- SPtr<RenderTexture> traceRt = RenderTexture::create(traceRtDesc);
- rapi.setRenderTarget(traceRt, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
- rapi.clearRenderTarget(FBT_COLOR, Color::ZERO);
- SSRTraceMat* traceMat = SSRTraceMat::getVariation(settings.quality, viewProps.numSamples > 1, true);
- traceMat->execute(inputs.view, gbuffer, sceneColor, hiZ, settings, traceRt);
- if (resolvedSceneColor)
- {
- resPool.release(resolvedSceneColor);
- resolvedSceneColor = nullptr;
- }
- if (mPrevFrame)
- {
- output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA16F, width, height, TU_RENDERTARGET));
- rapi.setRenderTarget(output->renderTexture);
- rapi.clearRenderTarget(FBT_COLOR);
- SSRResolveMat* resolveMat = SSRResolveMat::getVariation(viewProps.numSamples > 1);
- resolveMat->execute(inputs.view, mPrevFrame->texture, traceOutput->texture, sceneDepthNode->depthTex->texture,
- output->renderTexture);
- resPool.release(traceOutput);
- }
- else
- output = traceOutput;
- RenderAPI::instance().setRenderTarget(nullptr);
- }
- else
- deallocOutputs();
- }
- void RCNodeSSR::clear()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- if(mPrevFrame)
- resPool.release(mPrevFrame);
- mPrevFrame = output;
- output = nullptr;
- }
- void RCNodeSSR::deallocOutputs()
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
-
- if(mPrevFrame)
- {
- resPool.release(mPrevFrame);
- mPrevFrame = nullptr;
- }
- }
- SmallVector<StringID, 4> RCNodeSSR::getDependencies(const RendererView& view)
- {
- SmallVector<StringID, 4> deps;
- if (view.getRenderSettings().screenSpaceReflections.enabled)
- {
- deps.push_back(RCNodeSceneDepth::getNodeId());
- deps.push_back(RCNodeLightAccumulation::getNodeId());
- deps.push_back(RCNodeGBuffer::getNodeId());
- deps.push_back(RCNodeHiZ::getNodeId());
- deps.push_back(RCNodeResolvedSceneDepth::getNodeId());
- bool supportsTiledDeferred = gRenderBeast()->getFeatureSet() != RenderBeastFeatureSet::DesktopMacOS;
- if(supportsTiledDeferred)
- {
- if (view.getProperties().numSamples > 1)
- deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
- }
- }
- return deps;
- }
- }}
|