From d80526528c75cecbbdd95e1daed07b3fe6e714e2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 23 Sep 2024 12:54:01 -0700 Subject: [PATCH] Cleanup PostPorcessManager rendering - the main goal of this change was to move some state changes outside of loops, usually with mip generation. - for instance bindPostProcessDesciptorSet() must now be issued manually (and can be done outside the loop) - we also don't set the scissor for each pass - we also move prepareMaterial() outside of getPipelineState(), it's now done in PostProcessMaterial::getMaterial(). - We use PostProcessVariant instead of uint8_t everywhere In the end we have three drawing helpers: - commitAndRenderFullScreenQuad() which updates a material instance, binds the corresponding material and draws a full screen quad. - renderFullScreenQuad() which just renders a full screen quad. - renderFullScreenQuadWithScissor() which does the same but scisorred Additionally, we have the following helpers for getting materials and instances: - PostProcessMaterial::getMaterial(): which returns the FMaterial - PostProcessMaterial::getMaterialInstance(): which is now a helper returning a material instance from a PostProcessMaterial or FMaterial Most of the change is pluming through these API changes. --- filament/src/PostProcessManager.cpp | 464 ++++++++++++++++------------ filament/src/PostProcessManager.h | 58 ++-- 2 files changed, 305 insertions(+), 217 deletions(-) diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index b18278ffae..ec10f0abda 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -164,37 +165,27 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons } UTILS_NOINLINE -FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine) const noexcept { +FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine, + PostProcessVariant variant) const noexcept { if (UTILS_UNLIKELY(mSize)) { loadMaterial(engine); } + mMaterial->prepareProgram(Variant{ Variant::type_t(variant) }); return mMaterial; } UTILS_NOINLINE -std::pair - PostProcessManager::PostProcessMaterial::getPipelineState( - FEngine& engine, - Variant::type_t variantKey) const noexcept { - FMaterial* const material = getMaterial(engine); - material->prepareProgram(Variant{ variantKey }); - return {{ - .program = material->getProgram(Variant{ variantKey }), - .vertexBufferInfo = engine.getFullScreenVertexBuffer()->getVertexBufferInfoHandle(), - .pipelineLayout = { .setLayout = { - material->getPerViewDescriptorSetLayout().getHandle(), - engine.getPerRenderableDescriptorSetLayout().getHandle(), - material->getDescriptorSetLayout().getHandle() - } }, - .rasterState = material->getRasterState() }, - material->getDefaultInstance()->getScissor() }; +FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance( + FMaterial const* const ma) noexcept { + // TODO: we need to move away from the default instance + return const_cast(ma)->getDefaultInstance(); } UTILS_NOINLINE -FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance( - FEngine& engine) const noexcept { - FMaterial* const material = getMaterial(engine); - return material->getDefaultInstance(); +FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance(FEngine& engine, + PostProcessMaterial const& material, PostProcessVariant variant) noexcept { + FMaterial const* ma = material.getMaterial(engine, variant); + return getMaterialInstance(ma); } // ------------------------------------------------------------------------------------------------ @@ -333,6 +324,10 @@ void PostProcessManager::init() noexcept { //debugRegistry.registerProperty("d.ssao.kernelSize", &engine.debug.ssao.kernelSize); //debugRegistry.registerProperty("d.ssao.stddev", &engine.debug.ssao.stddev); + mFullScreenQuadRph = engine.getFullScreenRenderPrimitive(); + mFullScreenQuadVbih = engine.getFullScreenVertexBuffer()->getVertexBufferInfoHandle(); + mPerRenderableDslh = engine.getPerRenderableDescriptorSetLayout().getHandle(); + mSsrPassDescriptorSet.init(engine); mPostProcessDescriptorSet.init(engine); @@ -403,40 +398,70 @@ backend::Handle PostProcessManager::getZeroTextureArray() co } UTILS_NOINLINE -void PostProcessManager::render(FrameGraphResources::RenderPassInfo const& out, - backend::PipelineState const& pipeline, backend::Viewport const& scissor, - DriverApi& driver) const noexcept { +PipelineState PostProcessManager::getPipelineState( + FMaterial const* const ma, PostProcessVariant variant) const noexcept { + return { + .program = ma->getProgram(Variant{ Variant::type_t(variant) }), + .vertexBufferInfo = mFullScreenQuadVbih, + .pipelineLayout = { + .setLayout = { + ma->getPerViewDescriptorSetLayout().getHandle(), + mPerRenderableDslh, + ma->getDescriptorSetLayout().getHandle() + }}, + .rasterState = ma->getRasterState() + }; +} - bindPostProcessDescriptorSet(driver); +UTILS_NOINLINE +void PostProcessManager::renderFullScreenQuad( + FrameGraphResources::RenderPassInfo const& out, + PipelineState const& pipeline, + DriverApi& driver) const noexcept { + assert_invariant( + ((out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) + && !pipeline.rasterState.depthWrite) + || !(out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH)); + driver.beginRenderPass(out.target, out.params); + driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1); + driver.endRenderPass(); +} + +UTILS_NOINLINE +void PostProcessManager::renderFullScreenQuadWithScissor( + FrameGraphResources::RenderPassInfo const& out, + PipelineState const& pipeline, + backend::Viewport const scissor, + DriverApi& driver) const noexcept { + assert_invariant( + ((out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) + && !pipeline.rasterState.depthWrite) + || !(out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH)); + driver.beginRenderPass(out.target, out.params); + driver.scissor(scissor); + driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1); + driver.endRenderPass(); +} + +UTILS_NOINLINE +void PostProcessManager::commitAndRenderFullScreenQuad(backend::DriverApi& driver, + FrameGraphResources::RenderPassInfo const& out, FMaterialInstance const* mi, + PostProcessVariant variant) const noexcept { + mi->commit(driver); + mi->use(driver); + FMaterial const* const ma = mi->getMaterial(); + PipelineState const pipeline = getPipelineState(ma, variant); assert_invariant( ((out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) && !pipeline.rasterState.depthWrite) || !(out.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH)); - FEngine const& engine = mEngine; - Handle const fullScreenQuad = engine.getFullScreenRenderPrimitive(); driver.beginRenderPass(out.target, out.params); - driver.scissor(scissor); - driver.draw(pipeline, fullScreenQuad, 0, 3, 1); + driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1); driver.endRenderPass(); } -UTILS_NOINLINE -void PostProcessManager::commitAndRender(FrameGraphResources::RenderPassInfo const& out, - PostProcessMaterial const& material, uint8_t variant, DriverApi& driver) const noexcept { - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); - mi->commit(driver); - mi->use(driver); - render(out, material.getPipelineState(mEngine, variant), driver); -} - -UTILS_ALWAYS_INLINE -void PostProcessManager::commitAndRender(FrameGraphResources::RenderPassInfo const& out, - PostProcessMaterial const& material, DriverApi& driver) const noexcept { - commitAndRender(out, material, 0, driver); -} - // ------------------------------------------------------------------------------------------------ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph& fg, @@ -530,15 +555,25 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph } }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); + auto in = resources.getTexture(data.depth); auto& material = getPostProcessMaterial("mipmapDepth"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + auto pipeline = getPipelineState(ma); + + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma); + // The first mip already exists, so we process n-1 lods for (size_t level = 0; level < levelCount - 1; level++) { auto out = resources.getRenderPassInfo(level); + auto th = driver.createTextureView(in, level, 1); - mi->setParameter("depth", th, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); - commitAndRender(out, material, driver); + mi->setParameter("depth", th, { + .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); + mi->commit(driver); + mi->use(driver); + renderFullScreenQuad(out, pipeline, driver); driver.destroyTexture(th); } }); @@ -793,6 +828,8 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); + auto depth = resources.getTexture(data.depth); auto ssao = resources.getRenderPassInfo(); auto const& desc = resources.getDescriptor(data.depth); @@ -821,8 +858,8 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( auto& material = computeBentNormals ? getPostProcessMaterial("saoBentNormals") : getPostProcessMaterial("sao"); - - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("depth", depth, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("screenFromViewMatrix", @@ -869,10 +906,10 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( mi->commit(driver); mi->use(driver); - auto pipeline = material.getPipelineState(mEngine); - pipeline.first.rasterState.depthFunc = RasterState::DepthFunc::L; + auto pipeline = getPipelineState(ma); + pipeline.rasterState.depthFunc = RasterState::DepthFunc::L; assert_invariant(ssao.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH); - render(ssao, pipeline, driver); + renderFullScreenQuad(ssao, pipeline, driver); }); FrameGraphId ssao = SSAOPass->ssao; @@ -949,6 +986,8 @@ FrameGraphId PostProcessManager::bilateralBlurPass(FrameGraph }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); + auto ssao = resources.getTexture(data.input); auto blurred = resources.getRenderPassInfo(); auto const& desc = resources.getDescriptor(data.blurred); @@ -974,7 +1013,8 @@ FrameGraphId PostProcessManager::bilateralBlurPass(FrameGraph auto& material = config.bentNormals ? getPostProcessMaterial("bilateralBlurBentNormals") : getPostProcessMaterial("bilateralBlur"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("ssao", ssao, { /* only reads level 0 */ }); mi->setParameter("axis", axis / float2{desc.width, desc.height}); mi->setParameter("kernel", kGaussianSamples, kGaussianCount); @@ -984,9 +1024,9 @@ FrameGraphId PostProcessManager::bilateralBlurPass(FrameGraph mi->commit(driver); mi->use(driver); - auto pipeline = material.getPipelineState(mEngine); - pipeline.first.rasterState.depthFunc = RasterState::DepthFunc::L; - render(blurred, pipeline, driver); + auto pipeline = getPipelineState(ma); + pipeline.rasterState.depthFunc = RasterState::DepthFunc::L; + renderFullScreenQuad(blurred, pipeline, driver); }); return blurPass->blurred; @@ -1111,6 +1151,7 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); // don't use auto for those, b/c the ide can't resolve them using FGTD = FrameGraphTexture::Descriptor; @@ -1139,7 +1180,9 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& "separableGaussianBlur4L"sv : "separableGaussianBlur4"sv; break; } auto const& separableGaussianBlur = getPostProcessMaterial(materialName); - FMaterialInstance* const mi = separableGaussianBlur.getMaterialInstance(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance( + mEngine, separableGaussianBlur); + const size_t kernelStorageSize = mi->getMaterial()->reflect("kernel")->size; @@ -1175,7 +1218,7 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& // The framegraph only computes discard flags at FrameGraphPass boundaries hwTempRT.params.flags.discardEnd = TargetBufferFlags::NONE; - commitAndRender(hwTempRT, separableGaussianBlur, driver); + commitAndRenderFullScreenQuad(driver, hwTempRT, mi); // vertical pass UTILS_UNUSED_IN_RELEASE auto width = outDesc.width; @@ -1190,10 +1233,8 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& mi->setParameter("level", 0.0f); mi->setParameter("layer", 0.0f); mi->setParameter("axis", float2{ 0, 1.0f / tempDesc.height }); - mi->commit(driver); - mi->use(driver); - render(hwOutRT, separableGaussianBlur.getPipelineState(mEngine), driver); + commitAndRenderFullScreenQuad(driver, hwOutRT, mi); }); return blurPass->out; @@ -1426,8 +1467,8 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, assert_invariant(depth); - const uint8_t variant = uint8_t( - translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); + PostProcessVariant const variant = + translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; const TextureFormat format = translucent ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F; @@ -1577,13 +1618,16 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& out = resources.getRenderPassInfo(); auto color = resources.getTexture(data.color); auto depth = resources.getTexture(data.depth); auto const& material = (dofResolution == 1) ? getPostProcessMaterial("dofCoc") : getPostProcessMaterial("dofDownsample"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance( + mEngine, material); + mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("depth", depth, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("cocParams", cocParams); @@ -1593,7 +1637,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, mi->setParameter("texelSize", float2{ 1.0f / float(colorDesc.width), 1.0f / float(colorDesc.height) }); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); /* @@ -1633,15 +1677,17 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto desc = resources.getDescriptor(data.inOutColor); auto inOutColor = resources.getTexture(data.inOutColor); auto inOutCoc = resources.getTexture(data.inOutCoc); auto const& material = getPostProcessMaterial("dofMipmap"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma); - auto const pipeline = material.getPipelineState(mEngine, variant); + auto const pipeline = getPipelineState(ma, variant); for (size_t level = 0 ; level < mipmapCount - 1u ; level++) { const float w = FTexture::valueForLevel(level, desc.width); @@ -1655,7 +1701,9 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, mi->setParameter("texelSize", float2{ 1.0f / w, 1.0f / h }); mi->commit(driver); mi->use(driver); - render(out, pipeline, driver); + + renderFullScreenQuad(out, pipeline, driver); + driver.destroyTexture(inColor); driver.destroyTexture(inCoc); } @@ -1703,16 +1751,18 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& inputDesc = resources.getDescriptor(data.inCocMinMax); auto const& out = resources.getRenderPassInfo(); auto inCocMinMax = resources.getTexture(data.inCocMinMax); auto const& material = (!textureSwizzleSupported && (i == 0)) ? getPostProcessMaterial("dofTilesSwizzle") : getPostProcessMaterial("dofTiles"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("cocMinMax", inCocMinMax, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height }); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); inTilesCocMinMax = ppDoFTiling->outTilesCocMinMax; } @@ -1738,12 +1788,14 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& out = resources.getRenderPassInfo(); auto inTilesCocMinMax = resources.getTexture(data.inTilesCocMinMax); auto const& material = getPostProcessMaterial("dofDilate"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("tiles", inTilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST }); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); return ppDoFDilate->outTilesCocMinMax; }; @@ -1790,6 +1842,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& out = resources.getRenderPassInfo(); auto color = resources.getTexture(data.color); @@ -1799,7 +1852,8 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& inputDesc = resources.getDescriptor(data.coc); auto const& material = getPostProcessMaterial("dof"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); // it's not safe to use bilinear filtering in the general case (causes artifacts around edges) mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); @@ -1821,7 +1875,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, 0.0 // unused for now }); mi->setParameter("bokehAngle", bokehAngle); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); /* @@ -1852,6 +1906,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& out = resources.getRenderPassInfo(); auto inColor = resources.getTexture(data.inColor); @@ -1859,11 +1914,12 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax); auto const& material = getPostProcessMaterial("dofMedian"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("dof", inColor, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST }); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); @@ -1898,6 +1954,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& out = resources.getRenderPassInfo(); auto color = resources.getTexture(data.color); @@ -1906,12 +1963,13 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax); auto const& material = getPostProcessMaterial("dofCombine"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("dof", dof, { .filterMag = SamplerMagFilter::NEAREST }); mi->setParameter("alpha", alpha, { .filterMag = SamplerMagFilter::NEAREST }); mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST }); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); return ppDoFCombine->output; @@ -1933,8 +1991,11 @@ FrameGraphId PostProcessManager::downscalePass(FrameGraph& fg }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); + auto const& out = resources.getRenderPassInfo(); auto const& material = getPostProcessMaterial("bloomDownsample2x"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("source", resources.getTexture(data.input), { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR @@ -1943,7 +2004,8 @@ FrameGraphId PostProcessManager::downscalePass(FrameGraph& fg mi->setParameter("threshold", threshold ? 1.0f : 0.0f); mi->setParameter("fireflies", fireflies ? 1.0f : 0.0f); mi->setParameter("invHighlight", std::isinf(highlight) ? 0.0f : 1.0f / highlight); - commitAndRender(resources.getRenderPassInfo(), material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); + }); return downsamplePass->output; } @@ -2063,6 +2125,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); // TODO: if downsampling is not exactly a multiple of two, use the 13 samples // filter. This is generally the accepted solution, however, the 13 samples @@ -2075,13 +2138,10 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg, auto hwOut = resources.getTexture(data.out); auto const& material9 = getPostProcessMaterial("bloomDownsample9"); + auto* mi9 = PostProcessMaterial::getMaterialInstance(mEngine, material9); + auto const& material13 = getPostProcessMaterial("bloomDownsample"); - - auto* mi9 = material9.getMaterialInstance(mEngine); - auto* mi13 = material13.getMaterialInstance(mEngine); - - // PipelineState for both materials should be the same - auto const pipeline = material9.getPipelineState(mEngine); + auto* mi13 = PostProcessMaterial::getMaterialInstance(mEngine, material13); for (size_t i = 1; i < inoutBloomOptions.levels; i++) { auto hwDstRT = resources.getRenderPassInfo(data.outRT[i]); @@ -2096,9 +2156,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg, mi->setParameter("source", hwOutView, { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST }); - mi->commit(driver); - mi->use(driver); - render(hwDstRT, pipeline, driver); + commitAndRenderFullScreenQuad(driver, hwDstRT, mi); driver.destroyTexture(hwOutView); } }); @@ -2119,15 +2177,17 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg, } }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto hwOut = resources.getTexture(data.out); auto const& outDesc = resources.getDescriptor(data.out); auto const& material = getPostProcessMaterial("bloomUpsample"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + FMaterialInstance* mi = PostProcessMaterial::getMaterialInstance(ma); - auto pipeline = material.getPipelineState(mEngine); - pipeline.first.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; - pipeline.first.rasterState.blendFunctionDstRGB = BlendFunction::ONE; + auto pipeline = getPipelineState(ma); + pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; + pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE; for (size_t j = inoutBloomOptions.levels, i = j - 1; i >= 1; i--, j++) { auto hwDstRT = resources.getRenderPassInfo(data.outRT[i - 1]); @@ -2142,7 +2202,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg, .filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST}); mi->commit(driver); mi->use(driver); - render(hwDstRT, pipeline, driver); + renderFullScreenQuad(hwDstRT, pipeline, driver); driver.destroyTexture(hwOutView); } }); @@ -2173,12 +2233,14 @@ FrameGraphId PostProcessManager::flarePass(FrameGraph& fg, }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto in = resources.getTexture(data.in); auto out = resources.getRenderPassInfo(0); const float aspectRatio = float(width) / float(height); auto const& material = getPostProcessMaterial("flare"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("color", in, { .filterMag = SamplerMagFilter::LINEAR, @@ -2195,7 +2257,7 @@ FrameGraphId PostProcessManager::flarePass(FrameGraph& fg, mi->setParameter("haloRadius", bloomOptions.haloRadius); mi->setParameter("haloThickness", bloomOptions.haloThickness); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); constexpr float kernelWidth = 9; @@ -2241,7 +2303,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver, float4 const vignetteParameters = getVignetteParameters(vignetteOptions, width, height); auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("lut", colorGrading->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, @@ -2266,53 +2328,49 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver, mi->commit(driver); // load both variants - material.getMaterial(mEngine)->prepareProgram( - Variant{ Variant::type_t(PostProcessVariant::TRANSLUCENT) }); - material.getMaterial(mEngine)->prepareProgram( - Variant{ Variant::type_t(PostProcessVariant::OPAQUE) }); + material.getMaterial(mEngine, PostProcessVariant::OPAQUE); + material.getMaterial(mEngine, PostProcessVariant::TRANSLUCENT); } void PostProcessManager::colorGradingSubpass(DriverApi& driver, ColorGradingConfig const& colorGradingConfig) noexcept { - FEngine const& engine = mEngine; - Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); - - auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); - // the UBO has been set and committed in colorGradingPrepareSubpass() - FMaterialInstance* mi = material.getMaterialInstance(mEngine); - mi->use(driver); bindPostProcessDescriptorSet(driver); - const Variant::type_t variant = Variant::type_t(colorGradingConfig.translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - - auto const pipeline = material.getPipelineState(mEngine, variant); + PostProcessVariant const variant = colorGradingConfig.translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); + FMaterial const* const ma = material.getMaterial(mEngine, variant); + // the UBO has been set and committed in colorGradingPrepareSubpass() + FMaterialInstance* mi = PostProcessMaterial::getMaterialInstance(ma); + mi->use(driver); + auto const pipeline = getPipelineState(ma, variant); driver.nextSubpass(); - driver.scissor(pipeline.second); - driver.draw(pipeline.first, fullScreenRenderPrimitive, 0, 3, 1); + driver.scissor(mi->getScissor()); + driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1); } void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomResolveOp op) noexcept { auto const& material = getPostProcessMaterial("customResolveAsSubpass"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f), mi->commit(driver); - material.getMaterial(mEngine)->prepareProgram(Variant{}); + material.getMaterial(mEngine); } void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept { FEngine const& engine = mEngine; Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); auto const& material = getPostProcessMaterial("customResolveAsSubpass"); + FMaterial const* const ma = material.getMaterial(mEngine); // the UBO has been set and committed in colorGradingPrepareSubpass() - auto const pipeline = material.getPipelineState(mEngine); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* mi = PostProcessMaterial::getMaterialInstance(ma); mi->use(driver); + auto const pipeline = getPipelineState(ma); driver.nextSubpass(); - driver.scissor(pipeline.second); - driver.draw(pipeline.first, fullScreenRenderPrimitive, 0, 3, 1); + driver.scissor(mi->getScissor()); + driver.draw(pipeline, fullScreenRenderPrimitive, 0, 3, 1); } FrameGraphId PostProcessManager::customResolveUncompressPass(FrameGraph& fg, @@ -2406,6 +2464,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, } }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto colorTexture = resources.getTexture(data.input); auto bloomTexture = @@ -2423,7 +2482,12 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, auto const& out = resources.getRenderPassInfo(); auto const& material = getPostProcessMaterial("colorGrading"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + + PostProcessVariant const variant = colorGradingConfig.translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material, variant); mi->setParameter("lut", colorGrading->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, @@ -2484,10 +2548,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, (float)vp.height / input.height }); - const uint8_t variant = uint8_t(colorGradingConfig.translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - - commitAndRender(out, material, variant, driver); + commitAndRenderFullScreenQuad(driver, out, mi, variant); } ); @@ -2514,12 +2575,19 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, data.output = builder.declareRenderPass(data.output); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& inDesc = resources.getDescriptor(data.input); auto const& texture = resources.getTexture(data.input); auto const& out = resources.getRenderPassInfo(); auto const& material = getPostProcessMaterial("fxaa"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + + PostProcessVariant const variant = translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material, variant); + mi->setParameter("colorBuffer", texture, { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR @@ -2532,10 +2600,7 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, }); mi->setParameter("texelSize", 1.0f / float2{ inDesc.width, inDesc.height }); - const uint8_t variant = uint8_t(translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - - commitAndRender(out, material, variant, driver); + commitAndRenderFullScreenQuad(driver, out, mi, variant); }); return ppFXAA->output; @@ -2681,6 +2746,7 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, }); }, [=, ¤t](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); constexpr mat4f normalizedToClip{mat4f::row_major_init{ 2, 0, 0, -1, @@ -2726,7 +2792,12 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, auto history = resources.getTexture(data.history); auto const& material = getPostProcessMaterial("taa"); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + PostProcessVariant const variant = colorGradingConfig.translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + + FMaterial const* const ma = material.getMaterial(mEngine, variant); + + FMaterialInstance* mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("color", color, {}); // nearest mi->setParameter("depth", depth, {}); // nearest mi->setParameter("alpha", taaOptions.feedback); @@ -2743,17 +2814,13 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, mi->commit(driver); mi->use(driver); - const uint8_t variant = uint8_t(colorGradingConfig.translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - if (colorGradingConfig.asSubpass) { out.params.subpassMask = 1; } - auto const pipeline = material.getPipelineState(mEngine, variant); - bindPostProcessDescriptorSet(driver); + auto const pipeline = getPipelineState(ma, variant); + driver.beginRenderPass(out.target, out.params); - driver.scissor(pipeline.second); - driver.draw(pipeline.first, mEngine.getFullScreenRenderPrimitive(), 0, 3, 1); + driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1); if (colorGradingConfig.asSubpass) { colorGradingSubpass(driver, colorGradingConfig); } @@ -2806,13 +2873,18 @@ FrameGraphId PostProcessManager::rcas( }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto input = resources.getTexture(data.input); auto out = resources.getRenderPassInfo(); auto const& outputDesc = resources.getDescriptor(data.input); + PostProcessVariant const variant = translucent ? + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE; + auto& material = getPostProcessMaterial("fsr_rcas"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material, variant); FSRUniforms uniforms; FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * sharpness }); @@ -2821,14 +2893,7 @@ FrameGraphId PostProcessManager::rcas( mi->setParameter("resolution", float4{ outputDesc.width, outputDesc.height, 1.0f / outputDesc.width, 1.0f / outputDesc.height }); - mi->commit(driver); - mi->use(driver); - - const uint8_t variant = uint8_t( - translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - - auto const pipeline = material.getPipelineState(mEngine, variant); - render(out, pipeline, driver); + commitAndRenderFullScreenQuad(driver, out, mi, variant); }); return ppFsrRcas->output; @@ -2881,6 +2946,7 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool }, [this, twoPassesEASU, dsrOptions, vp, translucent, filter](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); // helper to set the EASU uniforms auto setEasuUniforms = [vp, backend = mEngine.getBackend()](FMaterialInstance* mi, @@ -2923,7 +2989,8 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool if (twoPassesEASU) { splitEasuMaterial = &getPostProcessMaterial("fsr_easu_mobileF"); - auto* mi = splitEasuMaterial->getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, *splitEasuMaterial); setEasuUniforms(mi, inputDesc, outputDesc); mi->setParameter("color", color, { .filterMag = SamplerMagFilter::LINEAR @@ -2940,7 +3007,8 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool "blitLow", "fsr_easu_mobile", "fsr_easu_mobile", "fsr_easu" }; unsigned const index = std::min(3u, (unsigned)dsrOptions.quality); easuMaterial = &getPostProcessMaterial(blitterNames[index]); - auto* mi = easuMaterial->getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, *easuMaterial); if (dsrOptions.quality != QualityLevel::LOW) { setEasuUniforms(mi, inputDesc, outputDesc); } @@ -2972,31 +3040,26 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool // -------------------------------------------------------------------------------- // render pass with draw calls - auto fullScreenRenderPrimitive = mEngine.getFullScreenRenderPrimitive(); - auto out = resources.getRenderPassInfo(); if (UTILS_UNLIKELY(twoPassesEASU)) { - auto pipeline0 = splitEasuMaterial->getPipelineState(mEngine); - auto pipeline1 = easuMaterial->getPipelineState(mEngine); - pipeline1.first.rasterState.depthFunc = backend::SamplerCompareFunc::NE; + auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine)); + auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine)); + pipeline1.rasterState.depthFunc = backend::SamplerCompareFunc::NE; if (translucent) { - enableTranslucentBlending(pipeline0.first); - enableTranslucentBlending(pipeline1.first); + enableTranslucentBlending(pipeline0); + enableTranslucentBlending(pipeline1); } - bindPostProcessDescriptorSet(driver); driver.beginRenderPass(out.target, out.params); - driver.scissor(pipeline0.second); - driver.draw(pipeline0.first, fullScreenRenderPrimitive, 0, 3, 1); - driver.scissor(pipeline1.second); - driver.draw(pipeline1.first, fullScreenRenderPrimitive, 0, 3, 1); + driver.draw(pipeline0, mFullScreenQuadRph, 0, 3, 1); + driver.draw(pipeline1, mFullScreenQuadRph, 0, 3, 1); driver.endRenderPass(); } else { - auto pipeline = easuMaterial->getPipelineState(mEngine); + auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine)); if (translucent) { - enableTranslucentBlending(pipeline.first); + enableTranslucentBlending(pipeline); } - render(out, pipeline, driver); + renderFullScreenQuad(out, pipeline, driver); } }); @@ -3038,6 +3101,7 @@ FrameGraphId PostProcessManager::blit(FrameGraph& fg, bool tr }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto color = resources.getTexture(data.input); auto const& inputDesc = resources.getDescriptor(data.input); auto out = resources.getRenderPassInfo(); @@ -3047,7 +3111,8 @@ FrameGraphId PostProcessManager::blit(FrameGraph& fg, bool tr PostProcessMaterial const& material = getPostProcessMaterial(layer ? "blitArray" : "blitLow"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + auto* mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("color", color, { .filterMag = filterMag, .filterMin = filterMin @@ -3065,14 +3130,14 @@ FrameGraphId PostProcessManager::blit(FrameGraph& fg, bool tr mi->commit(driver); mi->use(driver); - auto pipeline = material.getPipelineState(mEngine); + auto pipeline = getPipelineState(ma); if (translucent) { - pipeline.first.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; - pipeline.first.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE; - pipeline.first.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA; - pipeline.first.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA; + pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; + pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE; + pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA; + pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA; } - render(out, pipeline, driver); + renderFullScreenQuad(out, pipeline, driver); }); return ppQuadBlit->output; @@ -3136,6 +3201,7 @@ FrameGraphId PostProcessManager::blitDepth(FrameGraph& fg, {.attachments = {.depth = {data.output}}}); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto depth = resources.getTexture(data.input); auto const& inputDesc = resources.getDescriptor(data.input); auto out = resources.getRenderPassInfo(); @@ -3143,7 +3209,8 @@ FrameGraphId PostProcessManager::blitDepth(FrameGraph& fg, // -------------------------------------------------------------------------------- // set uniforms PostProcessMaterial const& material = getPostProcessMaterial("blitDepth"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("depth", depth, { .filterMag = SamplerMagFilter::NEAREST, @@ -3153,7 +3220,7 @@ FrameGraphId PostProcessManager::blitDepth(FrameGraph& fg, float4{float(vp.left) / inputDesc.width, float(vp.bottom) / inputDesc.height, float(vp.width) / inputDesc.width, float(vp.height) / inputDesc.height}); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); return ppQuadBlit->output; @@ -3248,11 +3315,13 @@ FrameGraphId PostProcessManager::resolveDepth(FrameGraph& fg, .clearFlags = TargetBufferFlags::DEPTH }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto const& input = resources.getTexture(data.input); auto const& material = getPostProcessMaterial("resolveDepth"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("depth", input, {}); // NEAREST - commitAndRender(resources.getRenderPassInfo(), material, driver); + commitAndRenderFullScreenQuad(driver, resources.getRenderPassInfo(), mi); }); return ppResolve->output; @@ -3283,6 +3352,7 @@ FrameGraphId PostProcessManager::vsmMipmapPass(FrameGraph& fg }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto in = driver.createTextureView(resources.getTexture(data.in), level, 1); auto out = resources.getRenderPassInfo(); @@ -3293,13 +3363,14 @@ FrameGraphId PostProcessManager::vsmMipmapPass(FrameGraph& fg int const dim = width >> (level + 1); auto& material = getPostProcessMaterial("vsmMipmap"); + FMaterial const* const ma = material.getMaterial(mEngine); // When generating shadow map mip levels, we want to preserve the 1 texel border. // (note clearing never respects the scissor in Filament) - auto const [pipeline, _] = material.getPipelineState(mEngine); + auto const pipeline = getPipelineState(ma); backend::Viewport const scissor = { 1u, 1u, dim - 2u, dim - 2u }; - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("color", in, { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST @@ -3308,7 +3379,9 @@ FrameGraphId PostProcessManager::vsmMipmapPass(FrameGraph& fg mi->setParameter("uvscale", 1.0f / float(dim)); mi->commit(driver); mi->use(driver); - render(out, pipeline, scissor, driver); + + renderFullScreenQuadWithScissor(out, pipeline, scissor, driver); + driver.destroyTexture(in); // `in` is just a view on `data.in` }); @@ -3334,18 +3407,16 @@ FrameGraphId PostProcessManager::debugShadowCascades(FrameGra builder.declareRenderPass(data.output); }, [=](FrameGraphResources const& resources, auto const& data, backend::DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto color = resources.getTexture(data.color); auto depth = resources.getTexture(data.depth); auto out = resources.getRenderPassInfo(); auto& material = getPostProcessMaterial("debugShadowCascades"); - auto const pipeline = material.getPipelineState(mEngine); - FMaterialInstance* mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("color", color, {}); // nearest mi->setParameter("depth", depth, {}); // nearest - mi->commit(driver); - mi->use(driver); - - render(out, pipeline, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); return debugShadowCascadePass->output; @@ -3380,8 +3451,8 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra .attachments = {.color = { data.output }}, .clearFlags = TargetBufferFlags::DEPTH }); }, - [=](FrameGraphResources const& resources, - auto const& data, DriverApi& driver) { + [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto color = resources.getTexture(data.input); auto const& inputDesc = resources.getDescriptor(data.input); auto out = resources.getRenderPassInfo(); @@ -3390,7 +3461,8 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra // set uniforms PostProcessMaterial const& material = getPostProcessMaterial("blitArray"); - auto* mi = material.getMaterialInstance(mEngine); + FMaterial const* const ma = material.getMaterial(mEngine); + auto* mi = PostProcessMaterial::getMaterialInstance(ma); mi->setParameter("color", color, { .filterMag = filterMag, .filterMin = filterMin @@ -3404,12 +3476,12 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra mi->commit(driver); mi->use(driver); - auto pipeline = material.getPipelineState(mEngine); + auto pipeline = getPipelineState(ma); if (translucent) { - pipeline.first.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; - pipeline.first.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE; - pipeline.first.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA; - pipeline.first.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA; + pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; + pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE; + pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA; + pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA; } // The width of each view takes up 1/depth of the screen width. @@ -3419,7 +3491,7 @@ FrameGraphId PostProcessManager::debugCombineArrayTexture(Fra for (uint32_t i = 0; i < inputTextureDesc.depth; ++i) { mi->setParameter("layerIndex", i); mi->commit(driver); - render(out, pipeline, driver); + renderFullScreenQuad(out, pipeline, driver); // From the second draw, don't clear the targetbuffer. out.params.flags.clear = filament::backend::TargetBufferFlags::NONE; out.params.flags.discardStart = filament::backend::TargetBufferFlags::NONE; @@ -3458,10 +3530,12 @@ FrameGraphId PostProcessManager::debugDisplayShadowTexture( }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + bindPostProcessDescriptorSet(driver); auto out = resources.getRenderPassInfo(); auto in = resources.getTexture(data.depth); auto const& material = getPostProcessMaterial("shadowmap"); - FMaterialInstance* const mi = material.getMaterialInstance(mEngine); + FMaterialInstance* const mi = + PostProcessMaterial::getMaterialInstance(mEngine, material); mi->setParameter("shadowmap", in, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("scale", s); @@ -3469,7 +3543,7 @@ FrameGraphId PostProcessManager::debugDisplayShadowTexture( mi->setParameter("level", (uint32_t)level); mi->setParameter("channel", (uint32_t)channel); mi->setParameter("power", power); - commitAndRender(out, material, driver); + commitAndRenderFullScreenQuad(driver, out, mi); }); input = shadomapDebugPass->color; } diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index ee1c58ce5e..e7c9b142c7 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -332,11 +334,17 @@ public: void terminate(FEngine& engine) noexcept; - FMaterial* getMaterial(FEngine& engine) const noexcept; - FMaterialInstance* getMaterialInstance(FEngine& engine) const noexcept; + FMaterial* getMaterial(FEngine& engine, + PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept; - std::pair getPipelineState(FEngine& engine, - Variant::type_t variantKey = 0u) const noexcept; + // Helper to get a MaterialInstance from a FMaterial + // This currently just call FMaterial::getDefaultInstance(). + static FMaterialInstance* getMaterialInstance(FMaterial const* ma) noexcept; + + // Helper to get a MaterialInstance from a PostProcessMaterial. + static FMaterialInstance* getMaterialInstance(FEngine& engine, + PostProcessMaterial const& material, + PostProcessVariant variant = PostProcessVariant::OPAQUE) noexcept; private: void loadMaterial(FEngine& engine) const noexcept; @@ -355,30 +363,36 @@ public: PostProcessMaterial& getPostProcessMaterial(std::string_view name) noexcept; - void commitAndRender(FrameGraphResources::RenderPassInfo const& out, - PostProcessMaterial const& material, uint8_t variant, - backend::DriverApi& driver) const noexcept; - - void commitAndRender(FrameGraphResources::RenderPassInfo const& out, - PostProcessMaterial const& material, - backend::DriverApi& driver) const noexcept; - - void render(FrameGraphResources::RenderPassInfo const& out, - backend::PipelineState const& pipeline, backend::Viewport const& scissor, - backend::DriverApi& driver) const noexcept; - - void render(FrameGraphResources::RenderPassInfo const& out, - std::pair const& combo, - backend::DriverApi& driver) const noexcept { - render(out, combo.first, combo.second, driver); - } - void setFrameUniforms(backend::DriverApi& driver, TypedUniformBuffer& uniforms) noexcept; void bindPostProcessDescriptorSet(backend::DriverApi& driver) const noexcept; + backend::PipelineState getPipelineState( + FMaterial const* ma, + PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept; + + void renderFullScreenQuad(FrameGraphResources::RenderPassInfo const& out, + backend::PipelineState const& pipeline, + backend::DriverApi& driver) const noexcept; + + void renderFullScreenQuadWithScissor(FrameGraphResources::RenderPassInfo const& out, + backend::PipelineState const& pipeline, + backend::Viewport scissor, + backend::DriverApi& driver) const noexcept; + + // Helper for a common case. Don't use in a loop because retrieving the PipelineState + // from FMaterialInstance is not trivial. + void commitAndRenderFullScreenQuad(backend::DriverApi& driver, + FrameGraphResources::RenderPassInfo const& out, + FMaterialInstance const* mi, + PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept; + private: + backend::RenderPrimitiveHandle mFullScreenQuadRph; + backend::VertexBufferInfoHandle mFullScreenQuadVbih; + backend::DescriptorSetLayoutHandle mPerRenderableDslh; + FEngine& mEngine; mutable SsrPassDescriptorSet mSsrPassDescriptorSet;