From 5850a7eee4aabc481da64538db3d244548d6dde2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 18 Jul 2025 17:20:01 -0700 Subject: [PATCH] use a separate UBO for the postfx user passes some of the postfx passes (picking, ssao, structure) are user passes because they call user materials; these now use their own ubo, which should prevent us from having to update a UBO mid frame. --- filament/src/PostProcessManager.cpp | 65 +++++++- filament/src/PostProcessManager.h | 8 + filament/src/details/Renderer.cpp | 179 +++++++-------------- filament/src/details/Renderer.h | 4 +- filament/src/details/View.cpp | 1 + filament/src/details/View.h | 15 +- filament/src/ds/DescriptorSet.cpp | 3 +- filament/src/ds/StructureDescriptorSet.cpp | 28 +++- filament/src/ds/StructureDescriptorSet.h | 7 +- filament/src/ds/TypedUniformBuffer.h | 18 ++- 10 files changed, 185 insertions(+), 143 deletions(-) diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 43e8666d68..f9b9950159 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -329,6 +329,7 @@ void PostProcessManager::init() noexcept { mSsrPassDescriptorSet.init(engine); mPostProcessDescriptorSet.init(engine); + mStructureDescriptorSet.init(engine); mWorkaroundSplitEasu = driver.isWorkaroundNeeded(Workaround::SPLIT_EASU); @@ -405,6 +406,7 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept { mPostProcessDescriptorSet.terminate(engine.getDescriptorSetLayoutFactory(), driver); mSsrPassDescriptorSet.terminate(driver); + mStructureDescriptorSet.terminate(driver); } Handle PostProcessManager::getOneTexture() const { @@ -546,7 +548,8 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph Variant structureVariant(Variant::DEPTH_VARIANT); structureVariant.setPicking(config.picking); - bindPostProcessDescriptorSet(driver); + // bind the per-view descriptorSet that is used for the structure pass + getStructureDescriptorSet().bind(driver); passBuilder.renderFlags(structureRenderFlags); passBuilder.variant(structureVariant); @@ -609,6 +612,63 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph return { depth, structurePass->picking }; } +FrameGraphId PostProcessManager::transparentPicking(FrameGraph& fg, + RenderPassBuilder const& passBuilder, uint8_t const structureRenderFlags, + uint32_t width, uint32_t height, float const scale) noexcept { + + struct PickingRenderPassData { + FrameGraphId depth; + FrameGraphId picking; + }; + auto const& pickingRenderPass = fg.addPass("Picking Render Pass", + [&](FrameGraph::Builder& builder, auto& data) { + bool const isFL0 = mEngine.getDriverApi().getFeatureLevel() == + FeatureLevel::FEATURE_LEVEL_0; + + // TODO: Specify the precision for picking pass + width = std::max(32u, uint32_t(std::ceil(float(width) * scale))); + height = std::max(32u, uint32_t(std::ceil(float(height) * scale))); + data.depth = builder.createTexture("Depth Buffer", { + .width = width, .height = height, + .format = isFL0 ? TextureFormat::DEPTH24 : TextureFormat::DEPTH32F }); + + data.depth = builder.write(data.depth, + FrameGraphTexture::Usage::DEPTH_ATTACHMENT); + + data.picking = builder.createTexture("Picking Buffer", { + .width = width, .height = height, + .format = isFL0 ? TextureFormat::RGBA8 : TextureFormat::RG32F }); + + data.picking = builder.write(data.picking, + FrameGraphTexture::Usage::COLOR_ATTACHMENT); + + builder.declareRenderPass("Picking Render Target", { + .attachments = {.color = { data.picking }, .depth = data.depth }, + .clearFlags = TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH + }); + }, + [=, passBuilder = passBuilder](FrameGraphResources const& resources, + auto const&, DriverApi& driver) mutable { + Variant pickingVariant(Variant::DEPTH_VARIANT); + pickingVariant.setPicking(true); + + // bind the per-view descriptorSet that is used for the structure pass + getStructureDescriptorSet().bind(driver); + + auto [target, params] = resources.getRenderPassInfo(); + passBuilder.renderFlags(structureRenderFlags); + passBuilder.variant(pickingVariant); + passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::DEPTH); + + RenderPass const pass{ passBuilder.build(mEngine, driver) }; + driver.beginRenderPass(target, params); + pass.getExecutor().execute(mEngine, driver); + driver.endRenderPass(); + }); + + return pickingRenderPass->picking; +} + // ------------------------------------------------------------------------------------------------ FrameGraphId PostProcessManager::ssr(FrameGraph& fg, @@ -858,7 +918,8 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( }); }, [=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { - bindPostProcessDescriptorSet(driver); + // bind the per-view descriptorSet that is used for the structure pass + getStructureDescriptorSet().bind(driver); auto depth = resources.getTexture(data.depth); auto ssao = resources.getRenderPassInfo(); diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 27933038af..e698fadfac 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -23,6 +23,7 @@ #include "ds/PostProcessDescriptorSet.h" #include "ds/SsrPassDescriptorSet.h" +#include "ds/StructureDescriptorSet.h" #include "ds/TypedUniformBuffer.h" #include "materials/StaticMaterialInfo.h" @@ -104,6 +105,10 @@ public: RenderPassBuilder const& passBuilder, uint8_t structureRenderFlags, uint32_t width, uint32_t height, StructurePassConfig const& config) noexcept; + FrameGraphId transparentPicking(FrameGraph& fg, + RenderPassBuilder const& passBuilder, uint8_t structureRenderFlags, + uint32_t width, uint32_t height, float scale) noexcept; + // reflections pass FrameGraphId ssr(FrameGraph& fg, RenderPassBuilder const& passBuilder, @@ -393,6 +398,8 @@ public: ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions, uint32_t width, uint32_t height) noexcept; + StructureDescriptorSet& getStructureDescriptorSet() const noexcept { return mStructureDescriptorSet; } + private: backend::RenderPrimitiveHandle mFullScreenQuadRph; backend::VertexBufferInfoHandle mFullScreenQuadVbih; @@ -402,6 +409,7 @@ private: mutable SsrPassDescriptorSet mSsrPassDescriptorSet; mutable PostProcessDescriptorSet mPostProcessDescriptorSet; + mutable StructureDescriptorSet mStructureDescriptorSet; struct BilateralPassConfig { uint8_t kernelSize = 11; diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 7d8d7e68b9..29f78d5f14 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -28,9 +28,19 @@ #include "details/Fence.h" #include "details/Scene.h" #include "details/SwapChain.h" -#include "details/Texture.h" #include "details/View.h" +#include "ds/StructureDescriptorSet.h" + +#include "fg/FrameGraph.h" +#include "fg/FrameGraphId.h" +#include "fg/FrameGraphResources.h" +#include "fg/FrameGraphTexture.h" + +#include + +#include + #include #include #include @@ -41,23 +51,17 @@ #include #include -#include "fg/FrameGraph.h" -#include "fg/FrameGraphId.h" -#include "fg/FrameGraphResources.h" -#include "fg/FrameGraphTexture.h" - #include #include #include -#include - +#include +#include #include #include #include #include #include -#include #include #include @@ -198,6 +202,7 @@ TextureFormat FRenderer::getHdrFormat(const FView& view, bool const translucent) return mHdrQualityHigh; } } + return mHdrQualityMedium; } TextureFormat FRenderer::getLdrFormat(bool const translucent) const noexcept { @@ -230,7 +235,7 @@ void FRenderer::initializeClearFlags() noexcept { mClearFlags = getClearFlags(); } -void FRenderer::setPresentationTime(int64_t const monotonic_clock_ns) { +void FRenderer::setPresentationTime(int64_t const monotonic_clock_ns) const { FEngine::DriverApi& driver = mEngine.getDriverApi(); driver.setPresentationTime(monotonic_clock_ns); } @@ -301,7 +306,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN using namespace std::chrono; const steady_clock::time_point now{ steady_clock::now() }; const steady_clock::time_point userVsync{ steady_clock::duration(vsyncSteadyClockTimeNano) }; - const time_point appVsync(vsyncSteadyClockTimeNano ? userVsync : now); + const time_point appVsync(vsyncSteadyClockTimeNano ? userVsync : now); mFrameId++; mViewRenderedCount = 0; @@ -341,7 +346,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN * to ignore the return value and render the frame anyway -- which is perfectly fine. * The remaining work will be done when the first render() call is made. */ - auto beginFrameInternal = [this, appVsync, swapChain]() { + auto beginFrameInternal = [this, appVsync, swapChain] { FEngine& engine = mEngine; FEngine::DriverApi& driver = engine.getDriverApi(); @@ -398,7 +403,7 @@ void FRenderer::endFrame() { FEngine& engine = mEngine; FEngine::DriverApi& driver = engine.getDriverApi(); - if (UTILS_HAS_THREADING) { + if constexpr (UTILS_HAS_THREADING) { // on debug builds this helps to catch cases where we're writing to // the buffer form another thread, which is currently not allowed. driver.debugThreading(); @@ -441,7 +446,9 @@ void FRenderer::endFrame() { js.waitAndRelease(job); } -void FRenderer::readPixels(uint32_t const xoffset, uint32_t const yoffset, uint32_t const width, uint32_t const height, +void FRenderer::readPixels( + uint32_t const xoffset, uint32_t const yoffset, + uint32_t const width, uint32_t const height, PixelBufferDescriptor&& buffer) { const bool withinFrame = mSwapChain != nullptr; @@ -453,8 +460,9 @@ void FRenderer::readPixels(uint32_t const xoffset, uint32_t const yoffset, uint3 xoffset, yoffset, width, height, std::move(buffer)); } -void FRenderer::readPixels(FRenderTarget* renderTarget, - uint32_t const xoffset, uint32_t const yoffset, uint32_t const width, uint32_t const height, +void FRenderer::readPixels(FRenderTarget const* renderTarget, + uint32_t const xoffset, uint32_t const yoffset, + uint32_t const width, uint32_t const height, PixelBufferDescriptor&& buffer) { // TODO: change the following to an assert when client call sites have addressed the issue. @@ -795,6 +803,24 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { view.prepareUpscaler(scale, taaOptions, dsrOptions); + // Set the PER_VIEW UBO for the passes that use the user materials, but are not the color pass + // (e.g. structure, ssao). The PER_VIEW UBO may be different because these passes don't run + // at the same resolution. We set only the values that are relevant to both user-materials + // and the concerned passes. The PER_VIEW UBO contains data that is needed by the user + // materials public APIs. + StructureDescriptorSet& descriptorSet = ppm.getStructureDescriptorSet(); + descriptorSet.prepareCamera(engine, cameraInfo); + descriptorSet.prepareTime(engine, getShaderUserTime()); + descriptorSet.prepareViewport(svp, { + int32_t(float(xvp.left) * aoOptions.resolution), + int32_t(float(xvp.bottom) * aoOptions.resolution), + uint32_t(float(xvp.width) * aoOptions.resolution), + uint32_t(float(xvp.height) * aoOptions.resolution) }); + //descriptorSet.prepareLodBias(); // FIXME: we need to do that too + descriptorSet.prepareMaterialGlobals(view.getMaterialGlobals()); + descriptorSet.commit(driver); + + /* * Allocate command buffer */ @@ -938,46 +964,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { passBuilder.camera(cameraInfo); passBuilder.geometry(scene.getRenderableData(), view.getVisibleRenderables()); - // view set-ups that need to happen before rendering - fg.addTrivialSideEffectPass("Prepare View Uniforms", - [=, &view, &engine](DriverApi& driver) { - view.prepareCamera(engine, cameraInfo); - - // The code here is a little fragile. In theory, we need to call prepareViewport() - // for each render pass, because the viewport parameters depend on the resolution. - // However, in practice, we only have two resolutions: the color pass resolution, - // and the structure pass which is governed by aoOptions.resolution (this could - // change in the future). - // So here we set the parameters for the structure pass and SSAO passes which - // are always done first. The SSR pass will also use these parameters which - // is wrong if it doesn't run at the same resolution as SSAO. - // prepareViewport() is called again during the color pass, which resets the - // values correctly for the Color pass, however, this will be again wrong - // for passes that come after the Color pass, such as DoF. - // - // The solution is to call prepareViewport() for each pass, really (so we should - // move it to its own UBO). - // - // The reason why this bug is acceptable is that the viewport parameters are - // currently only used for generating noise, so it's not too bad. - - // note: aoOptions.resolution is either 1.0 or 0.5, and the result is then - // guaranteed to be an integer (because xvp is a multiple of 16). - view.prepareViewport(svp, - filament::Viewport{ - int32_t(float(xvp.left ) * aoOptions.resolution), - int32_t(float(xvp.bottom) * aoOptions.resolution), - uint32_t(float(xvp.width ) * aoOptions.resolution), - uint32_t(float(xvp.height) * aoOptions.resolution)}); - - // this needs to reset the sampler that are only set in RendererUtils::colorPass(), because - // this descriptor-set is also used for ssr/picking/structure and these could be stale - // it would be better to use a separate desriptor-set for those two cases so that we don't - // have to do this - view.unbindSamplers(engine); - view.commitUniformsAndSamplers(driver); - }); - // -------------------------------------------------------------------------------------------- // structure pass -- automatically culled if not used // Currently it consists of a simple depth pass. @@ -998,68 +984,20 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { if (view.hasPicking()) { if (view.isTransparentPickingEnabled()) { - struct PickingRenderPassData { - FrameGraphId depth; - FrameGraphId picking; - }; - auto& pickingRenderPass = fg.addPass("Picking Render Pass", - [&](FrameGraph::Builder& builder, auto& data) { - bool const isFL0 = mEngine.getDriverApi().getFeatureLevel() == - FeatureLevel::FEATURE_LEVEL_0; - - // TODO: Specify the precision for picking pass - uint32_t const width = std::max(32u, - (uint32_t)std::ceil(float(svp.width) * aoOptions.resolution)); - uint32_t const height = std::max(32u, - (uint32_t)std::ceil(float(svp.height) * aoOptions.resolution)); - data.depth = builder.createTexture("Depth Buffer", { - .width = width, .height = height, - .format = isFL0 ? TextureFormat::DEPTH24 : TextureFormat::DEPTH32F }); - - data.depth = builder.write(data.depth, - FrameGraphTexture::Usage::DEPTH_ATTACHMENT); - - data.picking = builder.createTexture("Picking Buffer", { - .width = width, .height = height, - .format = isFL0 ? TextureFormat::RGBA8 : TextureFormat::RG32F }); - - data.picking = builder.write(data.picking, - FrameGraphTexture::Usage::COLOR_ATTACHMENT); - - builder.declareRenderPass("Picking Render Target", { - .attachments = {.color = { data.picking }, .depth = data.depth }, - .clearFlags = TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH - }); - }, - [=, passBuilder = passBuilder](FrameGraphResources const& resources, - auto const& data, DriverApi& driver) mutable { - Variant pickingVariant(Variant::DEPTH_VARIANT); - pickingVariant.setPicking(true); - - auto out = resources.getRenderPassInfo(); - passBuilder.renderFlags(renderFlags); - passBuilder.variant(pickingVariant); - passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::DEPTH); - - RenderPass const pass{ passBuilder.build(mEngine, driver) }; - driver.beginRenderPass(out.target, out.params); - pass.getExecutor().execute(mEngine, driver); - driver.endRenderPass(); - }); - picking = pickingRenderPass->picking; + picking = ppm.transparentPicking(fg, + passBuilder, renderFlags, svp.width, svp.height, aoOptions.resolution); } struct PickingResolvePassData { FrameGraphId picking; }; - fg.addPass( - "Picking Resolve Pass", + fg.addPass("Picking Resolve Pass", [&](FrameGraph::Builder& builder, auto& data) { // Note that BLIT_SRC is needed because this texture will be read later (via // readPixels()). - data.picking = - builder.read(picking, FrameGraphTexture::Usage::COLOR_ATTACHMENT | - FrameGraphTexture::Usage::BLIT_SRC); + data.picking = builder.read(picking, + FrameGraphTexture::Usage::COLOR_ATTACHMENT | + FrameGraphTexture::Usage::BLIT_SRC); builder.declareRenderPass("Picking Resolve Target", { .attachments = { .color = { data.picking }} }); @@ -1067,23 +1005,21 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { }, [=, &view](FrameGraphResources const& resources, auto const&, DriverApi& driver) mutable { - auto out = resources.getRenderPassInfo(); - view.executePickingQueries(driver, out.target, scale * aoOptions.resolution); + auto [target, params] = resources.getRenderPassInfo(); + view.executePickingQueries(driver, target, scale * aoOptions.resolution); }); } // Store this frame's camera projection in the frame history. + // TODO: We do this after we're configured the structure and ssao passes; + // but I'm not 100% sure this should be done before or after. if (UTILS_UNLIKELY(taaOptions.enabled)) { // Apply the TAA jitter to everything after the structure pass, starting with the color pass. ppm.TaaJitterCamera(svp, taaOptions, view.getFrameHistory(), &FrameHistoryEntry::taa, &cameraInfo); - fg.addTrivialSideEffectPass("Jitter Camera", - [&engine, &cameraInfo, &descriptorSet = view.getColorPassDescriptorSet()] - (DriverApi& driver) { - descriptorSet.prepareCamera(engine, cameraInfo); - descriptorSet.commit(driver); - }); + // this just re-set the color pass UBO content + view.prepareCamera(engine, cameraInfo); } // -------------------------------------------------------------------------------------------- @@ -1143,7 +1079,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { passBuilder.customCommand(3, RenderPass::Pass::BLENDED, RenderPass::CustomCommand::EPILOG, - 0, [&ppm, &driver, colorGradingConfigForColor]() { + 0, [&ppm, &driver, colorGradingConfigForColor] { ppm.colorGradingSubpass(driver, colorGradingConfigForColor); }); } else if (colorGradingConfig.customResolve) { @@ -1151,7 +1087,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { passBuilder.customCommand(3, RenderPass::Pass::BLENDED, RenderPass::CustomCommand::EPILOG, - 0, [&ppm, &driver]() { + 0, [&ppm, &driver] { ppm.customResolveSubpass(driver); }); } @@ -1222,8 +1158,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { // We use a framegraph pass to wait for froxelization to finish (so it can be done // in parallel with .compile() - auto sync = view.getFroxelizerSync(); - if (sync) { + if (auto sync = view.getFroxelizerSync()) { js.waitAndRelease(sync); view.commitFroxels(driver); } diff --git a/filament/src/details/Renderer.h b/filament/src/details/Renderer.h index 903f33c212..3f36b4343c 100644 --- a/filament/src/details/Renderer.h +++ b/filament/src/details/Renderer.h @@ -87,7 +87,7 @@ public: void renderStandaloneView(FView const* view); - void setPresentationTime(int64_t monotonic_clock_ns); + void setPresentationTime(int64_t monotonic_clock_ns) const; void setVsyncTime(uint64_t steadyClockTimeNano) noexcept; @@ -108,7 +108,7 @@ public: backend::PixelBufferDescriptor&& buffer); // read pixel from a rendertarget. must be called between beginFrame/enfFrame. - void readPixels(FRenderTarget* renderTarget, + void readPixels(FRenderTarget const* renderTarget, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, backend::PixelBufferDescriptor&& buffer); diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index 008b16ebe0..8d4dd3c0f3 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -854,6 +854,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren auto const fogTransform = tcm.getWorldTransformAccurate(tcm.getInstance(mFogEntity)); auto& colorPassDescriptorSet = getColorPassDescriptorSet(); + colorPassDescriptorSet.prepareCamera(engine, cameraInfo); colorPassDescriptorSet.prepareTime(engine, userTime); colorPassDescriptorSet.prepareFog(engine, cameraInfo, fogTransform, mFogOptions, scene->getIndirectLight()); diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 2cf72712fe..3e465ed06d 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -102,6 +102,7 @@ class FScene; class FView : public View { public: + using MaterialGlobals = std::array; using Range = utils::Range; explicit FView(FEngine& engine); @@ -483,6 +484,8 @@ public: return mFrameGraphViewerViewHandle; } + MaterialGlobals getMaterialGlobals() const { return mMaterialGlobals; } + private: struct FPickingQuery : public PickingQuery { private: @@ -609,12 +612,12 @@ private: std::unique_ptr mShadowMapManager; - std::array mMaterialGlobals = {{ - { 0, 0, 0, 1 }, - { 0, 0, 0, 1 }, - { 0, 0, 0, 1 }, - { 0, 0, 0, 1 }, - }}; + MaterialGlobals mMaterialGlobals = {{ + { 0, 0, 0, 1 }, + { 0, 0, 0, 1 }, + { 0, 0, 0, 1 }, + { 0, 0, 0, 1 }, + }}; fgviewer::ViewHandle mFrameGraphViewerViewHandle; diff --git a/filament/src/ds/DescriptorSet.cpp b/filament/src/ds/DescriptorSet.cpp index 6448f96721..dfdefd7190 100644 --- a/filament/src/ds/DescriptorSet.cpp +++ b/filament/src/ds/DescriptorSet.cpp @@ -73,8 +73,7 @@ DescriptorSet& DescriptorSet::operator=(DescriptorSet&& rhs) noexcept { void DescriptorSet::terminate(FEngine::DriverApi& driver) noexcept { if (mDescriptorSetHandle) { - driver.destroyDescriptorSet(mDescriptorSetHandle); - mDescriptorSetHandle.clear(); + driver.destroyDescriptorSet(std::move(mDescriptorSetHandle)); } } diff --git a/filament/src/ds/StructureDescriptorSet.cpp b/filament/src/ds/StructureDescriptorSet.cpp index 8cdd19ba78..843f8751a6 100644 --- a/filament/src/ds/StructureDescriptorSet.cpp +++ b/filament/src/ds/StructureDescriptorSet.cpp @@ -24,6 +24,9 @@ #include #include +#include +#include + #include #include @@ -33,15 +36,24 @@ namespace filament { using namespace backend; using namespace math; -StructureDescriptorSet::StructureDescriptorSet(FEngine& engine) noexcept - : mDescriptorSetLayout(engine.getPerViewDescriptorSetLayoutDepthVariant()), - mUniforms(engine.getDriverApi()) { +StructureDescriptorSet::StructureDescriptorSet() noexcept = default; + +StructureDescriptorSet::~StructureDescriptorSet() noexcept { + assert_invariant(!mDescriptorSet.getHandle()); +} + +void StructureDescriptorSet::init(FEngine& engine) noexcept { + + mUniforms.init(engine.getDriverApi()); + + mDescriptorSetLayout = &engine.getPerViewDescriptorSetLayoutDepthVariant(); + // create the descriptor-set from the layout mDescriptorSet = DescriptorSet{ - "StructureDescriptorSet", mDescriptorSetLayout }; + "StructureDescriptorSet", *mDescriptorSetLayout }; // initialize the descriptor-set - mDescriptorSet.setBuffer(mDescriptorSetLayout, +PerViewBindingPoints::FRAME_UNIFORMS, + mDescriptorSet.setBuffer(*mDescriptorSetLayout, +PerViewBindingPoints::FRAME_UNIFORMS, mUniforms.getUboHandle(), 0, sizeof(PerViewUib)); } @@ -53,7 +65,11 @@ void StructureDescriptorSet::terminate(DriverApi& driver) { void StructureDescriptorSet::commit(DriverApi& driver) noexcept { driver.updateBufferObject(mUniforms.getUboHandle(), mUniforms.toBufferDescriptor(driver), 0); - mDescriptorSet.commit(mDescriptorSetLayout, driver); + + assert_invariant(mDescriptorSetLayout); + if (mDescriptorSetLayout) { + mDescriptorSet.commit(*mDescriptorSetLayout, driver); + } } void StructureDescriptorSet::bind(DriverApi& driver) const noexcept { diff --git a/filament/src/ds/StructureDescriptorSet.h b/filament/src/ds/StructureDescriptorSet.h index b8042d3cff..9c47b392f5 100644 --- a/filament/src/ds/StructureDescriptorSet.h +++ b/filament/src/ds/StructureDescriptorSet.h @@ -38,7 +38,10 @@ struct CameraInfo; class StructureDescriptorSet { public: - explicit StructureDescriptorSet(FEngine& engine) noexcept; + StructureDescriptorSet() noexcept; + ~StructureDescriptorSet() noexcept; + + void init(FEngine& engine) noexcept; void terminate(backend::DriverApi& driver); @@ -61,7 +64,7 @@ public: void prepareMaterialGlobals(std::array const& materialGlobals) noexcept; private: - DescriptorSetLayout const& mDescriptorSetLayout; + DescriptorSetLayout const* mDescriptorSetLayout = nullptr; DescriptorSet mDescriptorSet; TypedUniformBuffer mUniforms; }; diff --git a/filament/src/ds/TypedUniformBuffer.h b/filament/src/ds/TypedUniformBuffer.h index 44d2699566..340c45d8af 100644 --- a/filament/src/ds/TypedUniformBuffer.h +++ b/filament/src/ds/TypedUniformBuffer.h @@ -21,7 +21,11 @@ #include #include +#include #include +#include + +#include #include @@ -31,7 +35,14 @@ template class TypedUniformBuffer { public: + TypedUniformBuffer() noexcept = default; + explicit TypedUniformBuffer(backend::DriverApi& driver) noexcept { + init(driver); + } + + void init(backend::DriverApi& driver) noexcept { + assert_invariant(!mUboHandle); mUboHandle = driver.createBufferObject( mTypedBuffer.getSize(), backend::BufferObjectBinding::UNIFORM, @@ -39,7 +50,12 @@ public: } void terminate(backend::DriverApi& driver) noexcept { - driver.destroyBufferObject(mUboHandle); + assert_invariant(mUboHandle); + driver.destroyBufferObject(std::move(mUboHandle)); + } + + ~TypedUniformBuffer() noexcept { + assert_invariant(!mUboHandle); } TypedBuffer& getTypedBuffer() noexcept {