From bd30abb168ff4b1bd7b729eb4089c2da39203cff Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 29 Jul 2020 13:01:23 -0700 Subject: [PATCH] attempt to reduce code size in PostProcessManager (#2880) * attempt to reduce code size in PostProcessManager The two main changes are: - materials are now stored in a hash map which allows us to automatically destroy all of them using one loop -- instead of having to call terminate() for each of them. - factored a very common sequence of code: commit() use() beginRenderPass() draw() endRenderPass() This makes the code easier to write and also results in less code. There are also minor other changes, e.g. RenderPass constructor is not inline anymore. --- filament/src/PostProcessManager.cpp | 284 ++++++++++------------- filament/src/PostProcessManager.h | 39 ++-- filament/src/RenderPass.cpp | 4 + filament/src/RenderPass.h | 3 + filament/src/materials/blitHigh.mat | 2 +- filament/src/materials/blitLow.mat | 2 +- filament/src/materials/blitMedium.mat | 2 +- filament/src/materials/dof.mat | 2 +- filament/src/materials/dofCombine.mat | 2 +- filament/src/materials/dofDilate.mat | 2 +- filament/src/materials/dofDownsample.mat | 2 +- filament/src/materials/dofMedian.mat | 2 +- filament/src/materials/dofMipmap.mat | 2 +- filament/src/materials/dofTiles.mat | 2 +- 14 files changed, 164 insertions(+), 186 deletions(-) diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index db5385f753..86d961478f 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -57,7 +57,6 @@ PostProcessManager::PostProcessMaterial::PostProcessMaterial() noexcept { mEngine = nullptr; mData = nullptr; mMaterial = nullptr; // aliased to mEngine - mMaterialInstance = nullptr; // aliased to mData } PostProcessManager::PostProcessMaterial::PostProcessMaterial(FEngine& engine, @@ -94,46 +93,50 @@ PostProcessManager::PostProcessMaterial::~PostProcessMaterial() { void PostProcessManager::PostProcessMaterial::terminate(FEngine& engine) noexcept { if (mHasMaterial) { engine.destroy(mMaterial); +// this is only needed for validation in the dtor in debug builds +#ifndef NDEBUG mMaterial = nullptr; - mMaterialInstance = nullptr; mHasMaterial = false; } else { mEngine = nullptr; mData = nullptr; +#endif } } -void PostProcessManager::PostProcessMaterial::assertMaterial() const noexcept { +UTILS_NOINLINE +FMaterial* PostProcessManager::PostProcessMaterial::loadMaterial() const noexcept { + // TODO: After all materials using this class have been converted to the post-process material + // domain, load both OPAQUE and TRANSPARENT variants here. + mHasMaterial = true; + mMaterial = upcast(Material::Builder().package(mData, mSize).build(*mEngine)); + return mMaterial; +} + +FMaterial* PostProcessManager::PostProcessMaterial::assertMaterial() const noexcept { if (UTILS_UNLIKELY(!mHasMaterial)) { - // TODO: After all materials using this class have been converted to the post-process material - // domain, load both OPAQUE and TRANSPARENT variants here. - mMaterial = upcast(Material::Builder().package(mData, mSize).build(*mEngine)); - mMaterialInstance = mMaterial->getDefaultInstance(); - mHasMaterial = true; + return loadMaterial(); } + return mMaterial; } PipelineState PostProcessManager::PostProcessMaterial::getPipelineState(uint8_t variant) const noexcept { - assertMaterial(); + FMaterial* const material = assertMaterial(); return { - .program = mMaterial->getProgram(variant), - .rasterState = mMaterial->getRasterState(), - .scissor = mMaterialInstance->getScissor() + .program = material->getProgram(variant), + .rasterState = material->getRasterState(), + .scissor = material->getDefaultInstance()->getScissor() }; } -PipelineState PostProcessManager::PostProcessMaterial::getPipelineState() const noexcept { - return getPipelineState(0); -} - FMaterial* PostProcessManager::PostProcessMaterial::getMaterial() const { assertMaterial(); return mMaterial; } FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance() const { - assertMaterial(); - return mMaterialInstance; + FMaterial* const material = assertMaterial(); + return material->getDefaultInstance(); } // ------------------------------------------------------------------------------------------------ @@ -141,33 +144,41 @@ FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance( PostProcessManager::PostProcessManager(FEngine& engine) noexcept : mEngine(engine) { } +UTILS_NOINLINE +void PostProcessManager::registerPostProcessMaterial(utils::StaticString name, uint8_t const* data, int size) { + mMaterialRegistry.try_emplace(name, mEngine, data, size); +} + +PostProcessManager::PostProcessMaterial& PostProcessManager::getPostProcessMaterial(utils::StaticString name) noexcept { + assert(mMaterialRegistry.find(name) != mMaterialRegistry.end()); + return mMaterialRegistry[name]; +} + #define MATERIAL(n) MATERIALS_ ## n ## _DATA, MATERIALS_ ## n ## _SIZE void PostProcessManager::init() noexcept { auto& engine = mEngine; DriverApi& driver = engine.getDriverApi(); - mSSAO = { engine, MATERIAL(SAO) }; - mMipmapDepth = { engine, MATERIAL(MIPMAPDEPTH) }; - mBilateralBlur = { engine, MATERIAL(BILATERALBLUR) }; - mSeparableGaussianBlur = { engine, MATERIAL(SEPARABLEGAUSSIANBLUR) }; - mBloomDownsample = { engine, MATERIAL(BLOOMDOWNSAMPLE) }; - mBloomUpsample = { engine, MATERIAL(BLOOMUPSAMPLE) }; - mBlit[0] = { engine, MATERIAL(BLITLOW) }; - mBlit[1] = { engine, MATERIAL(BLITMEDIUM) }; - mBlit[2] = { engine, MATERIAL(BLITHIGH) }; - mColorGrading = { engine, MATERIAL(COLORGRADING) }; - mFxaa = { engine, MATERIAL(FXAA) }; - mDoFDownsample = { engine, MATERIAL(DOFDOWNSAMPLE) }; - mDoFMipmap = { engine, MATERIAL(DOFMIPMAP) }; - mDoFTiles = { engine, MATERIAL(DOFTILES) }; - mDoFDilate = { engine, MATERIAL(DOFDILATE) }; - mDoF = { engine, MATERIAL(DOF) }; - mDoFMedian = { engine, MATERIAL(DOFMEDIAN) }; - mDoFCombine = { engine, MATERIAL(DOFCOMBINE) }; - if (driver.isFrameBufferFetchSupported()) { - mColorGradingAsSubpass = { engine, MATERIAL(COLORGRADINGASSUBPASS) }; - } + registerPostProcessMaterial("sao", MATERIAL(SAO)); + registerPostProcessMaterial("mipmapDepth", MATERIAL(MIPMAPDEPTH)); + registerPostProcessMaterial("bilateralBlur", MATERIAL(BILATERALBLUR)); + registerPostProcessMaterial("separableGaussianBlur", MATERIAL(SEPARABLEGAUSSIANBLUR)); + registerPostProcessMaterial("bloomDownsample", MATERIAL(BLOOMDOWNSAMPLE)); + registerPostProcessMaterial("bloomUpsample", MATERIAL(BLOOMUPSAMPLE)); + registerPostProcessMaterial("blitLow", MATERIAL(BLITLOW)); + registerPostProcessMaterial("blitMedium", MATERIAL(BLITMEDIUM)); + registerPostProcessMaterial("blitHigh", MATERIAL(BLITHIGH)); + registerPostProcessMaterial("colorGrading", MATERIAL(COLORGRADING)); + registerPostProcessMaterial("colorGradingAsSubpass", MATERIAL(COLORGRADINGASSUBPASS)); + registerPostProcessMaterial("fxaa", MATERIAL(FXAA)); + registerPostProcessMaterial("dofDownsample", MATERIAL(DOFDOWNSAMPLE)); + registerPostProcessMaterial("dofMipmap", MATERIAL(DOFMIPMAP)); + registerPostProcessMaterial("dofTiles", MATERIAL(DOFTILES)); + registerPostProcessMaterial("dofDilate", MATERIAL(DOFDILATE)); + registerPostProcessMaterial("dof", MATERIAL(DOF)); + registerPostProcessMaterial("dofMedian", MATERIAL(DOFMEDIAN)); + registerPostProcessMaterial("dofCombine", MATERIAL(DOFCOMBINE)); // UBO storage size. // The effective kernel size is (kMaxPositiveKernelSize - 1) * 4 + 1. @@ -175,7 +186,8 @@ void PostProcessManager::init() noexcept { // taking advantage of linear filtering produces an effective kernel of 8+1+8=17 samples // and because it's a separable filter, the effective 2D filter kernel size is 17*17 // The total number of samples needed over the two passes is 18. - mSeparableGaussianBlurKernelStorageSize = mSeparableGaussianBlur.getMaterial()->reflect("kernel")->size; + auto& separableGaussianBlur = getPostProcessMaterial("separableGaussianBlur"); + mSeparableGaussianBlurKernelStorageSize = separableGaussianBlur.getMaterial()->reflect("kernel")->size; mDummyOneTexture = driver.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 0, 1, 1, 1, TextureUsage::DEFAULT); @@ -195,25 +207,29 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept { FEngine& engine = mEngine; driver.destroyTexture(mDummyOneTexture); driver.destroyTexture(mDummyZeroTexture); - mSSAO.terminate(engine); - mMipmapDepth.terminate(engine); - mBilateralBlur.terminate(engine); - mSeparableGaussianBlur.terminate(engine); - mBloomDownsample.terminate(engine); - mBloomUpsample.terminate(engine); - mBlit[0].terminate(engine); - mBlit[1].terminate(engine); - mBlit[2].terminate(engine); - mColorGrading.terminate(engine); - mColorGradingAsSubpass.terminate(engine); - mFxaa.terminate(engine); - mDoFDownsample.terminate(engine); - mDoFMipmap.terminate(engine); - mDoFTiles.terminate(engine); - mDoFDilate.terminate(engine); - mDoF.terminate(engine); - mDoFMedian.terminate(engine); - mDoFCombine.terminate(engine); + auto first = mMaterialRegistry.begin(); + auto last = mMaterialRegistry.end(); + while (first != last) { + first.value().terminate(engine); + ++first; + } +} + +UTILS_NOINLINE +void PostProcessManager::commitAndRender(FrameGraphRenderTarget const& out, + PostProcessMaterial const& material, uint8_t variant, DriverApi& driver) const noexcept { + FMaterialInstance* const mi = material.getMaterialInstance(); + mi->commit(driver); + mi->use(driver); + driver.beginRenderPass(out.target, out.params); + driver.draw(material.getPipelineState(variant), mEngine.getFullScreenRenderPrimitive()); + driver.endRenderPass(); +} + +UTILS_ALWAYS_INLINE +void PostProcessManager::commitAndRender(FrameGraphRenderTarget const& out, + PostProcessMaterial const& material, DriverApi& driver) const noexcept { + commitAndRender(out, material, 0, driver); } // ------------------------------------------------------------------------------------------------ @@ -277,8 +293,6 @@ FrameGraphId PostProcessManager::structure(FrameGraph& fg, FrameGraphId PostProcessManager::mipmapPass(FrameGraph& fg, FrameGraphId input, size_t level) noexcept { - Handle fullScreenRenderPrimitive = mEngine.getFullScreenRenderPrimitive(); - struct DepthMipData { FrameGraphId in; FrameGraphId out; @@ -300,15 +314,12 @@ FrameGraphId PostProcessManager::mipmapPass(FrameGraph& fg, auto in = resources.getTexture(data.in); auto out = resources.get(data.rt); - FMaterialInstance* const mi = mMipmapDepth.getMaterialInstance(); + auto& material = getPostProcessMaterial("mipmapDepth"); + FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("depth", in, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("level", uint32_t(level)); - mi->commit(driver); - mi->use(driver); - driver.beginRenderPass(out.target, out.params); - driver.draw(mMipmapDepth.getPipelineState(), fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); return depthMipmapPass.getData().out; @@ -405,7 +416,8 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOclusion( const auto invProjection = inverse(cameraInfo.projection); const float inc = (1.0f / (sampleCount - 0.5f)) * spiralTurns * 2.0f * float(math::F_PI); - FMaterialInstance* const mi = mSSAO.getMaterialInstance(); + auto& material = getPostProcessMaterial("sao"); + FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("depth", depth, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); @@ -429,7 +441,7 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOclusion( mi->commit(driver); mi->use(driver); - PipelineState pipeline(mSSAO.getPipelineState()); + PipelineState pipeline(material.getPipelineState()); pipeline.rasterState.depthFunc = RasterState::DepthFunc::G; driver.beginRenderPass(ssao.target, ssao.params); @@ -499,14 +511,15 @@ FrameGraphId PostProcessManager::bilateralBlurPass( // TODO: "oneOverEdgeDistance" should be a user-settable parameter // z-distance that constitute an edge for bilateral filtering - FMaterialInstance* const mi = mBilateralBlur.getMaterialInstance(); + auto& material = getPostProcessMaterial("bilateralBlur"); + FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("ssao", ssao, { /* only reads level 0 */ }); mi->setParameter("axis", axis / float2{desc.width, desc.height}); mi->setParameter("farPlaneOverEdgeDistance", -zf / 0.0625f); mi->commit(driver); mi->use(driver); - PipelineState pipeline(mBilateralBlur.getPipelineState()); + PipelineState pipeline(material.getPipelineState()); pipeline.rasterState.depthFunc = RasterState::DepthFunc::G; driver.beginRenderPass(blurred.target, blurred.params); @@ -611,7 +624,7 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& [=](FrameGraphPassResources const& resources, auto const& data, DriverApi& driver) { - PostProcessMaterial const& separableGaussianBlur = mSeparableGaussianBlur; + auto const& separableGaussianBlur = getPostProcessMaterial("separableGaussianBlur"); FMaterialInstance* const mi = separableGaussianBlur.getMaterialInstance(); float2 kernel[64]; @@ -640,15 +653,11 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& float2{ 1.0f / FTexture::valueForLevel(srcLevel, inDesc.width), 0 }); mi->setParameter("count", (int32_t)m); mi->setParameter("kernel", kernel, m); - mi->commit(driver); - mi->use(driver); // The framegraph only computes discard flags at FrameGraphPass boundaries hwTempRT.params.flags.discardEnd = TargetBufferFlags::NONE; - driver.beginRenderPass(hwTempRT.target, hwTempRT.params); - driver.draw(separableGaussianBlur.getPipelineState(), fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(hwTempRT, separableGaussianBlur, driver); // vertical pass auto width = FTexture::valueForLevel(dstLevel, outDesc.width); @@ -665,6 +674,7 @@ FrameGraphId PostProcessManager::gaussianBlurPass(FrameGraph& float4{ width, height, 1.0f / width, 1.0f / height }); mi->setParameter("axis", float2{ 0, 1.0f / tempDesc.height }); mi->commit(driver); + // we don't need to call use() here, since it's the same material driver.beginRenderPass(hwOutRT.target, hwOutRT.params); driver.draw(separableGaussianBlur.getPipelineState(), fullScreenRenderPrimitive); @@ -772,18 +782,13 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& out = resources.get(data.rt); auto color = resources.getTexture(data.color); auto depth = resources.getTexture(data.depth); - PostProcessMaterial& material = mDoFDownsample; + auto const& material = getPostProcessMaterial("dofDownsample"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("depth", depth, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("cocParams", cocParams); mi->setParameter("uvscale", float4{ width, height, 1.0f / colorDesc.width, 1.0f / colorDesc.height }); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState(variant)); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); /* @@ -835,19 +840,20 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto inOutBackground = resources.getTexture(data.inOutBackground); auto inOutCocFgBg = resources.getTexture(data.inOutCocFgBg); - PostProcessMaterial& material = mDoFMipmap; + auto const& material = getPostProcessMaterial("dofMipmap"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("foreground", inOutForeground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("background", inOutBackground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("cocFgBg", inOutCocFgBg, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->use(driver); + const PipelineState pipeline(material.getPipelineState(variant)); + for (size_t level = 0 ; level < mipmapCount - 1u ; level++) { auto const& out = resources.get(data.rt[level]); mi->setParameter("mip", uint32_t(level)); mi->setParameter("weightScale", 0.5f / float(1u<commit(driver); - PipelineState pipeline(material.getPipelineState(variant)); driver.beginRenderPass(out.target, out.params); driver.draw(pipeline, fullScreenRenderPrimitive); driver.endRenderPass(); @@ -895,16 +901,13 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& outputDesc = resources.getDescriptor(data.outTilesCocMaxMin); auto const& out = resources.get(data.rt); auto inCocMaxMin = resources.getTexture(data.inCocMaxMin); - PostProcessMaterial& material = mDoFTiles; + auto const& material = getPostProcessMaterial("dofTiles"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("cocMaxMin", inCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST }); - mi->setParameter("uvscale", float4{ outputDesc.width, outputDesc.height, 1.0f / inputDesc.width, 1.0f / inputDesc.height }); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState()); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + mi->setParameter("uvscale", float4{ + outputDesc.width, outputDesc.height, + 1.0f / inputDesc.width, 1.0f / inputDesc.height }); + commitAndRender(out, material, driver); }); inTilesCocMaxMin = ppDoFTiling.getData().outTilesCocMaxMin; } @@ -936,15 +939,10 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& data, DriverApi& driver) { auto const& out = resources.get(data.rt); auto inTilesCocMaxMin = resources.getTexture(data.inTilesCocMaxMin); - PostProcessMaterial& material = mDoFDilate; + auto const& material = getPostProcessMaterial("dofDilate"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("tiles", inTilesCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST }); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState()); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); return ppDoFDilate.getData().outTilesCocMaxMin; }; @@ -1007,7 +1005,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& outputDesc = resources.getDescriptor(data.outForeground); auto const& tilesDesc = resources.getDescriptor(data.tilesCocMaxMin); - PostProcessMaterial& material = mDoF; + auto const& material = getPostProcessMaterial("dof"); FMaterialInstance* const mi = material.getMaterialInstance(); // it's not safe to use bilinear filtering in the general case (causes artifacts around edges) mi->setParameter("foreground", foreground, @@ -1028,12 +1026,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, outputDesc.height / (tileSize * 0.5f * tilesDesc.height) }); mi->setParameter("bokehAngle", bokehAngle); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState(variant)); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); /* @@ -1077,7 +1070,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto const& outputDesc = resources.getDescriptor(data.outForeground); auto const& tilesDesc = resources.getDescriptor(data.tilesCocMaxMin); - PostProcessMaterial& material = mDoFMedian; + auto const& material = getPostProcessMaterial("dofMedian"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("dof", inForeground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST }); @@ -1086,12 +1079,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, outputDesc.width / (tileSize * 0.5f * tilesDesc.width), outputDesc.height / (tileSize * 0.5f * tilesDesc.height) }); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState(variant)); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); @@ -1139,7 +1127,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, auto alpha = resources.getTexture(data.alpha); auto tilesCocMaxMin = resources.getTexture(data.tilesCocMaxMin); - PostProcessMaterial& material = mDoFCombine; + auto const& material = getPostProcessMaterial("dofCombine"); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST }); mi->setParameter("dof", dof, { .filterMag = SamplerMagFilter::NEAREST }); @@ -1151,12 +1139,7 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, colorDesc.width / (tilesDesc.width * float(tileSize)), colorDesc.height / (tilesDesc.height * float(tileSize)) }); - mi->commit(driver); - mi->use(driver); - PipelineState pipeline(material.getPipelineState(variant)); - driver.beginRenderPass(out.target, out.params); - driver.draw(pipeline, fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, driver); }); return ppDoFCombine.getData().output; @@ -1226,10 +1209,10 @@ FrameGraphId PostProcessManager::bloomPass(FrameGraph& fg, [=](FrameGraphPassResources const& resources, auto const& data, DriverApi& driver) { - PostProcessMaterial const& bloomDownsample = mBloomDownsample; - FMaterialInstance* mi = bloomDownsample.getMaterialInstance(); + auto const& material = getPostProcessMaterial("bloomDownsample"); + FMaterialInstance* mi = material.getMaterialInstance(); - const PipelineState pipeline(bloomDownsample.getPipelineState()); + const PipelineState pipeline(material.getPipelineState()); auto hwIn = resources.getTexture(data.in); auto hwOut = resources.getTexture(data.out); @@ -1285,9 +1268,9 @@ FrameGraphId PostProcessManager::bloomPass(FrameGraph& fg, auto hwIn = resources.getTexture(data.in); auto const& outDesc = resources.getDescriptor(data.out); - PostProcessMaterial const& bloomUpsample = mBloomUpsample; - FMaterialInstance* mi = bloomUpsample.getMaterialInstance(); - PipelineState pipeline(bloomUpsample.getPipelineState()); + auto const& material = getPostProcessMaterial("bloomUpsample"); + FMaterialInstance* mi = material.getMaterialInstance(); + PipelineState pipeline(material.getPipelineState()); pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE; pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE; @@ -1338,11 +1321,11 @@ static float4 getVignetteParameters(View::VignetteOptions options, uint32_t widt // Factor to transform oval into circle float aspect = mix(1.0f, float(width) / float(height), circle); - return float4{midPoint, radius, aspect, options.feather}; + return float4{ midPoint, radius, aspect, options.feather }; } // Set half-max to show disabled - return float4{std::numeric_limits::max()}; + return float4{ std::numeric_limits::max() }; } void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver, @@ -1351,7 +1334,8 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver, float4 vignetteParameters = getVignetteParameters(vignetteOptions, width, height); - FMaterialInstance* mi = mColorGradingAsSubpass.getMaterialInstance(); + auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); + FMaterialInstance* mi = material.getMaterialInstance(); mi->setParameter("lut", colorGrading->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR @@ -1367,12 +1351,13 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver, bool translucen FEngine& engine = mEngine; Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); - mColorGradingAsSubpass.getMaterialInstance()->use(driver); + auto const& material = getPostProcessMaterial("colorGradingAsSubpass"); + material.getMaterialInstance()->use(driver); const uint8_t variant = uint8_t(translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); driver.nextSubpass(); - driver.draw(mColorGradingAsSubpass.getPipelineState(variant), fullScreenRenderPrimitive); + driver.draw(material.getPipelineState(variant), fullScreenRenderPrimitive); } FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, @@ -1380,9 +1365,6 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, TextureFormat outFormat, bool translucent, bool fxaa, float2 scale, View::BloomOptions bloomOptions, View::VignetteOptions vignetteOptions, bool dithering) noexcept { - FEngine& engine = mEngine; - Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); - struct PostProcessColorGrading { FrameGraphId input; FrameGraphId output; @@ -1438,7 +1420,10 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, Handle dirtTexture = data.dirt.isValid() ? resources.getTexture(data.dirt) : getOneTexture(); - FMaterialInstance* mi = mColorGrading.getMaterialInstance(); + auto const& out = resources.get(data.rt); + + auto const& material = getPostProcessMaterial("colorGrading"); + FMaterialInstance* mi = material.getMaterialInstance(); mi->setParameter("lut", colorGrading->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR @@ -1473,16 +1458,11 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, mi->setParameter("vignette", vignetteParameters); mi->setParameter("vignetteColor", vignetteOptions.color); mi->setParameter("fxaa", fxaa); - mi->commit(driver); - mi->use(driver); const uint8_t variant = uint8_t(translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - auto const& target = resources.get(data.rt); - driver.beginRenderPass(target.target, target.params); - driver.draw(mColorGrading.getPipelineState(variant), fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, variant, driver); } ); @@ -1493,9 +1473,6 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, FrameGraphId input, TextureFormat outFormat, bool translucent) noexcept { - FEngine& engine = mEngine; - Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); - struct PostProcessFXAA { FrameGraphId input; FrameGraphId output; @@ -1518,23 +1495,19 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, [=](FrameGraphPassResources const& resources, auto const& data, DriverApi& driver) { auto const& texture = resources.getTexture(data.input); + auto const& out = resources.get(data.rt); - FMaterialInstance* mi = mFxaa.getMaterialInstance(); + auto const& material = getPostProcessMaterial("fxaa"); + FMaterialInstance* mi = material.getMaterialInstance(); mi->setParameter("colorBuffer", texture, { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR }); - mi->commit(driver); - mi->use(driver); - const uint8_t variant = uint8_t(translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); - auto const& target = resources.get(data.rt); - driver.beginRenderPass(target.target, target.params); - driver.draw(mFxaa.getPipelineState(variant), fullScreenRenderPrimitive); - driver.endRenderPass(); + commitAndRender(out, material, variant, driver); }); return ppFXAA.getData().output; @@ -1620,8 +1593,9 @@ FrameGraphId PostProcessManager::blendBlit( auto out = resources.get(data.drt); auto const& desc = resources.getDescriptor(data.input); + const StaticString blitterNames[3] = { "blitLow", "blitMedium", "blitHigh" }; unsigned index = std::min(2u, (unsigned)quality); - PostProcessMaterial& material = mBlit[index]; + auto& material = getPostProcessMaterial(blitterNames[index]); FMaterialInstance* const mi = material.getMaterialInstance(); mi->setParameter("color", color, { .filterMag = SamplerMagFilter::LINEAR, diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 09707868f3..8375f4c24e 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -26,6 +26,10 @@ #include #include +#include + +#include + namespace filament { class FColorGrading; @@ -101,6 +105,7 @@ public: private: FEngine& mEngine; + class PostProcessMaterial; FrameGraphId mipmapPass(FrameGraph& fg, FrameGraphId input, size_t level) noexcept; @@ -118,6 +123,13 @@ private: FrameGraphId input, backend::TextureFormat outFormat, View::BloomOptions& bloomOptions, math::float2 scale) noexcept; + void commitAndRender(FrameGraphRenderTarget const& out, + PostProcessMaterial const& material, uint8_t variant, + backend::DriverApi& driver) const noexcept; + + void commitAndRender(FrameGraphRenderTarget const& out, + PostProcessMaterial const& material, + backend::DriverApi& driver) const noexcept; class PostProcessMaterial { public: @@ -137,16 +149,15 @@ private: FMaterial* getMaterial() const; FMaterialInstance* getMaterialInstance() const; - backend::PipelineState getPipelineState(uint8_t variant) const noexcept; - backend::PipelineState getPipelineState() const noexcept; + backend::PipelineState getPipelineState(uint8_t variant = 0u) const noexcept; private: - void assertMaterial() const noexcept; + FMaterial* assertMaterial() const noexcept; + FMaterial* loadMaterial() const noexcept; union { struct { mutable FMaterial* mMaterial; - mutable FMaterialInstance* mMaterialInstance; }; struct { FEngine* mEngine; @@ -157,24 +168,10 @@ private: mutable bool mHasMaterial{}; }; - PostProcessMaterial mMipmapDepth; + tsl::robin_map mMaterialRegistry; - PostProcessMaterial mSSAO; - PostProcessMaterial mBilateralBlur; - PostProcessMaterial mSeparableGaussianBlur; - PostProcessMaterial mDoFDownsample; - PostProcessMaterial mDoFMipmap; - PostProcessMaterial mDoF; - PostProcessMaterial mDoFTiles; - PostProcessMaterial mDoFDilate; - PostProcessMaterial mDoFMedian; - PostProcessMaterial mDoFCombine; - PostProcessMaterial mBloomDownsample; - PostProcessMaterial mBloomUpsample; - PostProcessMaterial mColorGradingAsSubpass; - PostProcessMaterial mColorGrading; - PostProcessMaterial mFxaa; - PostProcessMaterial mBlit[3]; + void registerPostProcessMaterial(utils::StaticString name, uint8_t const* data, int size); + PostProcessMaterial& getPostProcessMaterial(utils::StaticString name) noexcept; backend::Handle mDummyOneTexture; backend::Handle mDummyZeroTexture; diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index d4c6354ea8..c5973295db 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -46,6 +46,10 @@ RenderPass::RenderPass(FEngine& engine, mCustomCommands.reserve(8); // preallocate allocate a reasonable number of custom commands } +RenderPass::RenderPass(RenderPass const& rhs) = default; + +RenderPass::~RenderPass() noexcept = default; + void RenderPass::setGeometry(FScene::RenderableSoa const& soa, Range vr, backend::Handle uboHandle) noexcept { mRenderableSoa = &soa; diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 40dbf0f71f..fbf2a684c6 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -241,6 +241,9 @@ public: RenderPass(FEngine& engine, utils::GrowingSlice commands) noexcept; + RenderPass(RenderPass const& rhs); + ~RenderPass() noexcept; + void overridePolygonOffset(backend::PolygonOffset* polygonOffset) noexcept; void setGeometry(FScene::RenderableSoa const& soa, utils::Range vr, backend::Handle uboHandle) noexcept; diff --git a/filament/src/materials/blitHigh.mat b/filament/src/materials/blitHigh.mat index 9608548911..88f307e076 100644 --- a/filament/src/materials/blitHigh.mat +++ b/filament/src/materials/blitHigh.mat @@ -1,5 +1,5 @@ material { - name : blit, + name : blitHigh, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/blitLow.mat b/filament/src/materials/blitLow.mat index 075a987517..23da1e50b0 100644 --- a/filament/src/materials/blitLow.mat +++ b/filament/src/materials/blitLow.mat @@ -1,5 +1,5 @@ material { - name : blit, + name : blitLow, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/blitMedium.mat b/filament/src/materials/blitMedium.mat index f904fa91f0..ce4c69911e 100644 --- a/filament/src/materials/blitMedium.mat +++ b/filament/src/materials/blitMedium.mat @@ -1,5 +1,5 @@ material { - name : blit, + name : blitMedium, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dof.mat b/filament/src/materials/dof.mat index 2f848e9628..0e609c9e06 100644 --- a/filament/src/materials/dof.mat +++ b/filament/src/materials/dof.mat @@ -1,5 +1,5 @@ material { - name : DepthOfField, + name : dof, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofCombine.mat b/filament/src/materials/dofCombine.mat index b561df7b4d..6c5a723843 100644 --- a/filament/src/materials/dofCombine.mat +++ b/filament/src/materials/dofCombine.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldCombine, + name : dofCombine, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofDilate.mat b/filament/src/materials/dofDilate.mat index a35c404ada..1502da2eaa 100644 --- a/filament/src/materials/dofDilate.mat +++ b/filament/src/materials/dofDilate.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldDilate, + name : dofDilate, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofDownsample.mat b/filament/src/materials/dofDownsample.mat index f773fcc356..c6b32fba80 100644 --- a/filament/src/materials/dofDownsample.mat +++ b/filament/src/materials/dofDownsample.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldDownsample, + name : dofDownsample, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofMedian.mat b/filament/src/materials/dofMedian.mat index b639c5431e..bf1a86b1c4 100644 --- a/filament/src/materials/dofMedian.mat +++ b/filament/src/materials/dofMedian.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldMedian, + name : dofMedian, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofMipmap.mat b/filament/src/materials/dofMipmap.mat index d1a17829da..48df2e65ee 100644 --- a/filament/src/materials/dofMipmap.mat +++ b/filament/src/materials/dofMipmap.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldMipmap, + name : dofMipmap, parameters : [ { type : sampler2d, diff --git a/filament/src/materials/dofTiles.mat b/filament/src/materials/dofTiles.mat index 0b32fae8d9..cb87054e46 100644 --- a/filament/src/materials/dofTiles.mat +++ b/filament/src/materials/dofTiles.mat @@ -1,5 +1,5 @@ material { - name : DepthOfFieldTiles, + name : dofTiles, parameters : [ { type : sampler2d,