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.
This commit is contained in:
Mathias Agopian
2025-07-22 16:53:42 -07:00
committed by Mathias Agopian
parent 1b2620cdf3
commit 5850a7eee4
10 changed files with 185 additions and 143 deletions
+63 -2
View File
@@ -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<HwTexture> 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<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGraph& fg,
RenderPassBuilder const& passBuilder, uint8_t const structureRenderFlags,
uint32_t width, uint32_t height, float const scale) noexcept {
struct PickingRenderPassData {
FrameGraphId<FrameGraphTexture> depth;
FrameGraphId<FrameGraphTexture> picking;
};
auto const& pickingRenderPass = fg.addPass<PickingRenderPassData>("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<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
@@ -858,7 +918,8 @@ FrameGraphId<FrameGraphTexture> 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();
+8
View File
@@ -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<FrameGraphTexture> transparentPicking(FrameGraph& fg,
RenderPassBuilder const& passBuilder, uint8_t structureRenderFlags,
uint32_t width, uint32_t height, float scale) noexcept;
// reflections pass
FrameGraphId<FrameGraphTexture> 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;
+57 -122
View File
@@ -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 <private/filament/Variant.h>
#include <private/utils/Tracing.h>
#include <filament/Camera.h>
#include <filament/Fence.h>
#include <filament/Options.h>
@@ -41,23 +51,17 @@
#include <backend/Handle.h>
#include <backend/PixelBufferDescriptor.h>
#include "fg/FrameGraph.h"
#include "fg/FrameGraphId.h"
#include "fg/FrameGraphResources.h"
#include "fg/FrameGraphTexture.h"
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/mat4.h>
#include <private/utils/Tracing.h>
#include <utils/architecture.h>
#include <utils/Allocator.h>
#include <utils/JobSystem.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <chrono>
#include <limits>
@@ -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<steady_clock> 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<FrameGraphTexture> depth;
FrameGraphId<FrameGraphTexture> picking;
};
auto& pickingRenderPass = fg.addPass<PickingRenderPassData>("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<FrameGraphTexture> picking;
};
fg.addPass<PickingResolvePassData>(
"Picking Resolve Pass",
fg.addPass<PickingResolvePassData>("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);
}
+2 -2
View File
@@ -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);
+1
View File
@@ -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());
+9 -6
View File
@@ -102,6 +102,7 @@ class FScene;
class FView : public View {
public:
using MaterialGlobals = std::array<math::float4, 4>;
using Range = utils::Range<uint32_t>;
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<ShadowMapManager> mShadowMapManager;
std::array<math::float4, 4> 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;
+1 -2
View File
@@ -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));
}
}
+22 -6
View File
@@ -24,6 +24,9 @@
#include <private/filament/EngineEnums.h>
#include <private/filament/UibStructs.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <math/vec4.h>
#include <array>
@@ -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 {
+5 -2
View File
@@ -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<math::float4, 4> const& materialGlobals) noexcept;
private:
DescriptorSetLayout const& mDescriptorSetLayout;
DescriptorSetLayout const* mDescriptorSetLayout = nullptr;
DescriptorSet mDescriptorSet;
TypedUniformBuffer<PerViewUib> mUniforms;
};
+17 -1
View File
@@ -21,7 +21,11 @@
#include <backend/BufferDescriptor.h>
#include <backend/DriverApiForward.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <utils/debug.h>
#include <utility>
#include <stddef.h>
@@ -31,7 +35,14 @@ template<typename T, size_t N = 1>
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<T,N>& getTypedBuffer() noexcept {