move FScene::updateUBO() back to FView

it really didn't belong to FScene
This commit is contained in:
Mathias Agopian
2025-08-25 12:32:21 -07:00
committed by Mathias Agopian
parent a7894b5876
commit 39bf0f0a71
7 changed files with 101 additions and 107 deletions

View File

@@ -18,8 +18,10 @@
#define TNT_FILAMENT_BUFFERPOOLALLOCATOR_H
#include <utils/Allocator.h>
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <memory>
#include <utility>
#include <stdint.h>
@@ -110,7 +112,7 @@ void* BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>:
if (UTILS_UNLIKELY(size > mSize)) {
clearInternal(); // free all buffers
// round to 4K allocations to help cutting down on calling malloc.
size_t roundedSize = ((size + sizeof(Header)) + (ALLOCATION_ROUNDING - 1)) & ~(ALLOCATION_ROUNDING - 1);
size_t const roundedSize = ((size + sizeof(Header)) + (ALLOCATION_ROUNDING - 1)) & ~(ALLOCATION_ROUNDING - 1);
mSize = roundedSize - sizeof(Header); // record the new buffer size
assert_invariant(mSize >= size);
}
@@ -119,7 +121,7 @@ void* BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>:
// larger than the requested size).
if (UTILS_UNLIKELY(mEntries.empty())) {
++mOutstandingBuffers;
Header* p = (Header*)mAllocator.alloc(mSize + sizeof(Header), ALIGNMENT);
Header* p = static_cast<Header*>(mAllocator.alloc(mSize + sizeof(Header), ALIGNMENT));
p->size = mSize;
return p + 1;
}

View File

@@ -127,9 +127,8 @@ void FInstanceBuffer::setLocalTransforms(
memcpy(mLocalTransforms.data() + offset, localTransforms, sizeof(math::mat4f) * count);
}
void FInstanceBuffer::prepare(FEngine& engine, math::mat4f const& rootTransform,
void FInstanceBuffer::prepare(DriverApi& driver, math::mat4f const& rootTransform,
const PerRenderableData& ubo) {
DriverApi& driver = engine.getDriverApi();
// TODO: allocate this staging buffer from a pool.
constexpr uint32_t stagingBufferSize = sizeof(PerRenderableUib);

View File

@@ -21,6 +21,7 @@
#include <filament/InstanceBuffer.h>
#include <backend/DriverApiForward.h>
#include <backend/Handle.h>
#include <math/mat4.h>
@@ -48,7 +49,7 @@ public:
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset);
void prepare(FEngine& engine, math::mat4f const& rootTransform, const PerRenderableData& ubo);
void prepare(backend::DriverApi& driver, math::mat4f const& rootTransform, const PerRenderableData& ubo);
utils::CString const& getName() const noexcept { return mName; }

View File

@@ -17,18 +17,18 @@
#include "details/Scene.h"
#include "Allocators.h"
#include "BufferPoolAllocator.h"
#include "backend/Handle.h"
#include "components/LightManager.h"
#include "components/RenderableManager.h"
#include "components/TransformManager.h"
#include "details/Engine.h"
#include "details/InstanceBuffer.h"
#include "details/Skybox.h"
#include <backend/Handle.h>
#include <private/filament/UibStructs.h>
#include <private/utils/Tracing.h>
#include <filament/Box.h>
@@ -70,7 +70,7 @@ namespace filament {
// ------------------------------------------------------------------------------------------------
FScene::FScene(FEngine& engine) :
mEngine(engine), mSharedState(std::make_shared<SharedState>()) {
mEngine(engine) {
}
FScene::~FScene() noexcept = default;
@@ -406,66 +406,6 @@ void FScene::prepareVisibleRenderables(Range<uint32_t> visibleRenderables) noexc
}
}
void FScene::updateUBOs(
Range<uint32_t> visibleRenderables,
Handle<HwBufferObject> renderableUbh) noexcept {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
FEngine::DriverApi& driver = mEngine.getDriverApi();
// don't allocate more than 16 KiB directly into the render stream
static constexpr size_t MAX_STREAM_ALLOCATION_COUNT = 64; // 16 KiB
const size_t count = visibleRenderables.size();
PerRenderableData* buffer = [&]{
if (count >= MAX_STREAM_ALLOCATION_COUNT) {
// use the heap allocator
auto& bufferPoolAllocator = mSharedState->mBufferPoolAllocator;
return static_cast<PerRenderableData*>(bufferPoolAllocator.get(count * sizeof(PerRenderableData)));
} else {
// allocate space into the command stream directly
return driver.allocatePod<PerRenderableData>(count);
}
}();
PerRenderableData const* const uboData = mRenderableData.data<UBO>();
mat4f const* const worldTransformData = mRenderableData.data<WORLD_TRANSFORM>();
// prepare each InstanceBuffer.
FRenderableManager::InstancesInfo const* instancesData = mRenderableData.data<INSTANCES>();
for (uint32_t const i : visibleRenderables) {
auto& instancesInfo = instancesData[i];
if (UTILS_UNLIKELY(instancesInfo.buffer)) {
instancesInfo.buffer->prepare(
mEngine, worldTransformData[i], uboData[i]);
}
}
// copy our data into the UBO for each visible renderable
for (uint32_t const i : visibleRenderables) {
buffer[i] = uboData[i];
}
// We capture state shared between Scene and the update buffer callback, because the Scene could
// be destroyed before the callback executes.
std::weak_ptr<SharedState>* const weakShared =
new (std::nothrow) std::weak_ptr<SharedState>(mSharedState);
// update the UBO
driver.resetBufferObject(renderableUbh);
driver.updateBufferObjectUnsynchronized(renderableUbh, {
buffer, count * sizeof(PerRenderableData),
+[](void* p, size_t const s, void* user) {
std::weak_ptr<SharedState>* const weakShared =
static_cast<std::weak_ptr<SharedState>*>(user);
if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof(PerRenderableData)) {
if (auto state = weakShared->lock()) {
state->mBufferPoolAllocator.put(p);
}
}
delete weakShared;
}, weakShared
}, 0);
}
void FScene::terminate(FEngine&) {
}
@@ -497,7 +437,7 @@ void FScene::prepareDynamicLights(const CameraInfo& camera,
auto const* UTILS_RESTRICT shadowInfo = lightData.data<SHADOW_INFO>();
for (size_t i = DIRECTIONAL_LIGHTS_COUNT, c = size; i < c; ++i) {
const size_t gpuIndex = i - DIRECTIONAL_LIGHTS_COUNT;
auto li = instances[i];
auto const li = instances[i];
lp[gpuIndex].positionFalloff = { spheres[i].xyz, lcm.getSquaredFalloffInv(li) };
lp[gpuIndex].direction = directions[i];
lp[gpuIndex].reserved1 = {};
@@ -627,7 +567,7 @@ bool FScene::hasContactShadows() const noexcept {
// find out if at least one light has contact-shadow enabled
// TODO: we could cache the result of this Loop in the LightManager
auto& lcm = mEngine.getLightManager();
auto const& lcm = mEngine.getLightManager();
const auto *pFirst = mLightData.begin<LIGHT_INSTANCE>();
const auto *pLast = mLightData.end<LIGHT_INSTANCE>();
while (pFirst != pLast) {

View File

@@ -26,28 +26,18 @@
#include "components/LightManager.h"
#include "components/RenderableManager.h"
#include "components/TransformManager.h"
#include "BufferPoolAllocator.h"
#include <filament/Box.h>
#include <filament/Scene.h>
#include <math/mathfwd.h>
#include <utils/compiler.h>
#include <utils/Entity.h>
#include <utils/Slice.h>
#include <utils/StructureOfArrays.h>
#include <utils/Range.h>
#include <utils/debug.h>
#include <stddef.h>
#include <tsl/robin_set.h>
#include <memory>
namespace filament {
struct CameraInfo;
@@ -136,14 +126,14 @@ public:
RenderableSoa const& getRenderableData() const noexcept { return mRenderableData; }
RenderableSoa& getRenderableData() noexcept { return mRenderableData; }
static inline uint32_t getPrimitiveCount(RenderableSoa const& soa,
static uint32_t getPrimitiveCount(RenderableSoa const& soa,
uint32_t const first, uint32_t const last) noexcept {
// the caller must guarantee that last is dereferenceable
return soa.elementAt<SUMMED_PRIMITIVE_COUNT>(last) -
soa.elementAt<SUMMED_PRIMITIVE_COUNT>(first);
}
static inline uint32_t getPrimitiveCount(RenderableSoa const& soa, uint32_t const last) noexcept {
static uint32_t getPrimitiveCount(RenderableSoa const& soa, uint32_t const last) noexcept {
// the caller must guarantee that last is dereferenceable
return soa.elementAt<SUMMED_PRIMITIVE_COUNT>(last);
}
@@ -186,9 +176,6 @@ public:
LightSoa const& getLightData() const noexcept { return mLightData; }
LightSoa& getLightData() noexcept { return mLightData; }
void updateUBOs(utils::Range<uint32_t> visibleRenderables,
backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
bool hasContactShadows() const noexcept;
private:
@@ -230,12 +217,6 @@ private:
RenderableSoa mRenderableData;
LightSoa mLightData;
bool mHasContactShadows = false;
// State shared between Scene and driver callbacks.
struct SharedState {
BufferPoolAllocator<3> mBufferPoolAllocator = {};
};
std::shared_ptr<SharedState> mSharedState;
};
FILAMENT_DOWNCAST(Scene)

View File

@@ -17,6 +17,7 @@
#include "details/View.h"
#include "Allocators.h"
#include "BufferPoolAllocator.h"
#include "Culler.h"
#include "DebugRegistry.h"
#include "FrameHistory.h"
@@ -27,8 +28,11 @@
#include "ShadowMap.h"
#include "ShadowMapManager.h"
#include "components/TransformManager.h"
#include "details/Engine.h"
#include "details/IndirectLight.h"
#include "details/InstanceBuffer.h"
#include "details/RenderTarget.h"
#include "details/Renderer.h"
#include "details/Scene.h"
@@ -54,6 +58,7 @@
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Panic.h>
#include <utils/Range.h>
#include <utils/Slice.h>
#include <utils/Zip2Iterator.h>
@@ -71,6 +76,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <new>
#include <ratio>
#include <utility>
@@ -93,7 +99,8 @@ FView::FView(FEngine& engine)
mUniforms(engine.getDriverApi()),
mColorPassDescriptorSet{
{ engine, false, mUniforms },
{ engine, true, mUniforms } }
{ engine, true, mUniforms } },
mSharedState(std::make_shared<SharedState>())
{
DriverApi& driver = engine.getDriverApi();
@@ -766,7 +773,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
// TODO: should we shrink the underlying UBO at some point?
}
assert_invariant(mRenderableUbh);
scene->updateUBOs(merged, mRenderableUbh);
updateUBOs(driver, renderableData, merged, mRenderableUbh);
mCommonRenderableDescriptorSet.setBuffer(
engine.getPerRenderableDescriptorSetLayout(),
@@ -885,6 +892,65 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
colorPassDescriptorSet.prepareMaterialGlobals(mMaterialGlobals);
}
void FView::updateUBOs(
FEngine::DriverApi& driver,
FScene::RenderableSoa& renderableData,
utils::Range<uint32_t> visibleRenderables,
Handle<HwBufferObject> renderableUbh) noexcept {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
// don't allocate more than 16 KiB directly into the render stream
static constexpr size_t MAX_STREAM_ALLOCATION_COUNT = 64; // 16 KiB
const size_t count = visibleRenderables.size();
PerRenderableData* buffer = [&]{
if (count >= MAX_STREAM_ALLOCATION_COUNT) {
// use the heap allocator
auto& bufferPoolAllocator = mSharedState->mBufferPoolAllocator;
return static_cast<PerRenderableData*>(bufferPoolAllocator.get(count * sizeof(PerRenderableData)));
}
// allocate space into the command stream directly
return driver.allocatePod<PerRenderableData>(count);
}();
PerRenderableData const* const uboData = renderableData.data<FScene::UBO>();
mat4f const* const worldTransformData = renderableData.data<FScene::WORLD_TRANSFORM>();
// prepare each InstanceBuffer.
FRenderableManager::InstancesInfo const* instancesData = renderableData.data<FScene::INSTANCES>();
for (uint32_t const i : visibleRenderables) {
auto& instancesInfo = instancesData[i];
if (UTILS_UNLIKELY(instancesInfo.buffer)) {
instancesInfo.buffer->prepare(driver, worldTransformData[i], uboData[i]);
}
}
// copy our data into the UBO for each visible renderable
for (uint32_t const i : visibleRenderables) {
buffer[i] = uboData[i];
}
// We capture state shared between Scene and the update buffer callback, because the Scene could
// be destroyed before the callback executes.
std::weak_ptr<SharedState>* const weakShared =
new (std::nothrow) std::weak_ptr(mSharedState);
// update the UBO
driver.resetBufferObject(renderableUbh);
driver.updateBufferObjectUnsynchronized(renderableUbh, {
buffer, count * sizeof(PerRenderableData),
+[](void* p, size_t const s, void* user) {
std::weak_ptr<SharedState> const* const weakShared =
static_cast<std::weak_ptr<SharedState>*>(user);
if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof(PerRenderableData)) {
if (auto state = weakShared->lock()) {
state->mBufferPoolAllocator.put(p);
}
}
delete weakShared;
}, weakShared
}, 0);
}
void FView::computeVisibilityMasks(
uint8_t const visibleLayers,
uint8_t const* UTILS_RESTRICT layers,

View File

@@ -20,6 +20,7 @@
#include "downcast.h"
#include "Allocators.h"
#include "BufferPoolAllocator.h"
#include "Culler.h"
#include "FrameHistory.h"
#include "FrameInfo.h"
@@ -29,8 +30,6 @@
#include "ds/ColorPassDescriptorSet.h"
#include "ds/DescriptorSet.h"
#include "ds/PostProcessDescriptorSet.h"
#include "ds/SsrPassDescriptorSet.h"
#include "ds/TypedUniformBuffer.h"
#include "components/LightManager.h"
@@ -41,11 +40,8 @@
#include "details/RenderTarget.h"
#include "details/Scene.h"
#include <private/filament/EngineEnums.h>
#include <private/filament/UibStructs.h>
#include <private/backend/DriverApi.h>
#include <filament/Frustum.h>
#include <filament/Renderer.h>
#include <filament/View.h>
@@ -54,7 +50,6 @@
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utils/Allocator.h>
#include <utils/Entity.h>
#include <utils/StructureOfArrays.h>
#include <utils/Range.h>
@@ -68,8 +63,8 @@ namespace filament::fgviewer {
}
#endif
#include <math/scalar.h>
#include <math/mat4.h>
#include <math/vec4.h>
#include <array>
#include <memory>
@@ -298,7 +293,7 @@ public:
return mGuardBandOptions;
}
void setColorGrading(FColorGrading* colorGrading) noexcept {
void setColorGrading(FColorGrading const* colorGrading) noexcept {
mColorGrading = colorGrading == nullptr ? mDefaultColorGrading : colorGrading;
}
@@ -441,9 +436,8 @@ public:
backend::TargetBufferFlags getRenderTargetAttachmentMask() const noexcept {
if (mRenderTarget == nullptr) {
return backend::TargetBufferFlags::NONE;
} else {
return mRenderTarget->getAttachmentMask();
}
return mRenderTarget->getAttachmentMask();
}
static void cullRenderables(utils::JobSystem& js, FScene::RenderableSoa& renderableData,
@@ -484,7 +478,7 @@ public:
return mFogEntity;
}
TypedUniformBuffer<PerViewUib>& getFrameUniforms() noexcept {
TypedUniformBuffer<PerViewUib>& getFrameUniforms() const noexcept {
return mUniforms;
}
@@ -508,7 +502,7 @@ private:
PickingQueryResultCallback const callback) noexcept {
return new(std::nothrow) FPickingQuery(x, y, handler, callback);
}
static void put(FPickingQuery* pQuery) noexcept {
static void put(FPickingQuery const* pQuery) noexcept {
delete pQuery;
}
mutable FPickingQuery* next = nullptr;
@@ -518,12 +512,17 @@ private:
backend::CallbackHandler* const handler;
PickingQueryResultCallback const callback;
// picking query result
PickingQueryResult result;
PickingQueryResult result{};
};
void prepareVisibleRenderables(utils::JobSystem& js,
Frustum const& frustum, FScene::RenderableSoa& renderableData) const noexcept;
void updateUBOs(backend::DriverApi& driver,
FScene::RenderableSoa& renderableData,
utils::Range<uint32_t> visibleRenderables,
backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
static void prepareVisibleLights(FLightManager const& lcm,
utils::Slice<float> scratch,
math::mat4f const& viewMatrix, Frustum const& frustum,
@@ -620,6 +619,12 @@ private:
mutable bool mHasShadowing = false;
mutable bool mNeedsShadowMap = false;
// State shared between Scene and driver callbacks.
struct SharedState {
BufferPoolAllocator<3> mBufferPoolAllocator = {};
};
std::shared_ptr<SharedState> mSharedState;
std::unique_ptr<ShadowMapManager> mShadowMapManager;
MaterialGlobals mMaterialGlobals = {{