@@ -723,15 +723,15 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
723
723
VISIBLE_RENDERABLE | VISIBLE_DIR_SHADOW_RENDERABLE,
724
724
VISIBLE_RENDERABLE);
725
725
726
- auto beginDirCastersOnly = partition (beginDirCasters, renderableData.end (),
726
+ auto const beginDirCastersOnly = partition (beginDirCasters, renderableData.end (),
727
727
VISIBLE_RENDERABLE | VISIBLE_DIR_SHADOW_RENDERABLE,
728
728
VISIBLE_RENDERABLE | VISIBLE_DIR_SHADOW_RENDERABLE);
729
729
730
- auto endDirCastersOnly = partition (beginDirCastersOnly, renderableData.end (),
730
+ auto const endDirCastersOnly = partition (beginDirCastersOnly, renderableData.end (),
731
731
VISIBLE_RENDERABLE | VISIBLE_DIR_SHADOW_RENDERABLE,
732
732
VISIBLE_DIR_SHADOW_RENDERABLE);
733
733
734
- auto endPotentialSpotCastersOnly = partition (endDirCastersOnly, renderableData.end (),
734
+ auto const endPotentialSpotCastersOnly = partition (endDirCastersOnly, renderableData.end (),
735
735
VISIBLE_DYN_SHADOW_RENDERABLE,
736
736
VISIBLE_DYN_SHADOW_RENDERABLE);
737
737
@@ -759,21 +759,8 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
759
759
scene->prepareVisibleRenderables (merged);
760
760
761
761
// update those UBOs
762
- const size_t size = merged.size () * sizeof (PerRenderableData);
763
- if (size) {
764
- if (mRenderableUBOSize < size) {
765
- // allocate 1/3 extra, with a minimum of 16 objects
766
- const size_t count = std::max (size_t (16u ), (4u * merged.size () + 2u ) / 3u );
767
- mRenderableUBOSize = uint32_t (count * sizeof (PerRenderableData));
768
- driver.destroyBufferObject (mRenderableUbh );
769
- mRenderableUbh = driver.createBufferObject (
770
- mRenderableUBOSize + sizeof (PerRenderableUib),
771
- BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
772
- } else {
773
- // TODO: should we shrink the underlying UBO at some point?
774
- }
775
- assert_invariant (mRenderableUbh );
776
- updateUBOs (driver, renderableData, merged, mRenderableUbh );
762
+ if (!merged.empty ()) {
763
+ updateUBOs (driver, renderableData, merged);
777
764
778
765
mCommonRenderableDescriptorSet .setBuffer (
779
766
engine.getPerRenderableDescriptorSetLayout (),
@@ -893,65 +880,6 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
893
880
colorPassDescriptorSet.prepareMaterialGlobals (mMaterialGlobals );
894
881
}
895
882
896
- void FView::updateUBOs (
897
- FEngine::DriverApi& driver,
898
- FScene::RenderableSoa& renderableData,
899
- utils::Range<uint32_t > visibleRenderables,
900
- Handle<HwBufferObject> renderableUbh) noexcept {
901
- FILAMENT_TRACING_CALL (FILAMENT_TRACING_CATEGORY_FILAMENT);
902
-
903
- // don't allocate more than 16 KiB directly into the render stream
904
- static constexpr size_t MAX_STREAM_ALLOCATION_COUNT = 64 ; // 16 KiB
905
- const size_t count = visibleRenderables.size ();
906
- PerRenderableData* buffer = [&]{
907
- if (count >= MAX_STREAM_ALLOCATION_COUNT) {
908
- // use the heap allocator
909
- auto & bufferPoolAllocator = mSharedState ->mBufferPoolAllocator ;
910
- return static_cast <PerRenderableData*>(bufferPoolAllocator.get (count * sizeof (PerRenderableData)));
911
- }
912
- // allocate space into the command stream directly
913
- return driver.allocatePod <PerRenderableData>(count);
914
- }();
915
-
916
- PerRenderableData const * const uboData = renderableData.data <FScene::UBO>();
917
- mat4f const * const worldTransformData = renderableData.data <FScene::WORLD_TRANSFORM>();
918
-
919
- // prepare each InstanceBuffer.
920
- FRenderableManager::InstancesInfo const * instancesData = renderableData.data <FScene::INSTANCES>();
921
- for (uint32_t const i : visibleRenderables) {
922
- auto & instancesInfo = instancesData[i];
923
- if (UTILS_UNLIKELY (instancesInfo.buffer )) {
924
- instancesInfo.buffer ->prepare (driver, worldTransformData[i], uboData[i]);
925
- }
926
- }
927
-
928
- // copy our data into the UBO for each visible renderable
929
- for (uint32_t const i : visibleRenderables) {
930
- buffer[i] = uboData[i];
931
- }
932
-
933
- // We capture state shared between Scene and the update buffer callback, because the Scene could
934
- // be destroyed before the callback executes.
935
- std::weak_ptr<SharedState>* const weakShared =
936
- new (std::nothrow) std::weak_ptr (mSharedState );
937
-
938
- // update the UBO
939
- driver.resetBufferObject (renderableUbh);
940
- driver.updateBufferObjectUnsynchronized (renderableUbh, {
941
- buffer, count * sizeof (PerRenderableData),
942
- +[](void * p, size_t const s, void * user) {
943
- std::weak_ptr<SharedState> const * const weakShared =
944
- static_cast <std::weak_ptr<SharedState>*>(user);
945
- if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof (PerRenderableData)) {
946
- if (auto state = weakShared->lock ()) {
947
- state->mBufferPoolAllocator .put (p);
948
- }
949
- }
950
- delete weakShared;
951
- }, weakShared
952
- }, 0 );
953
- }
954
-
955
883
void FView::computeVisibilityMasks (
956
884
uint8_t const visibleLayers,
957
885
uint8_t const * UTILS_RESTRICT layers,
@@ -983,6 +911,100 @@ void FView::computeVisibilityMasks(
983
911
}
984
912
}
985
913
914
+ void FView::updateUBOs (
915
+ FEngine::DriverApi& driver,
916
+ FScene::RenderableSoa& renderableData,
917
+ utils::Range<uint32_t > visibleRenderables) noexcept {
918
+ FILAMENT_TRACING_CALL (FILAMENT_TRACING_CATEGORY_FILAMENT);
919
+
920
+ FRenderableManager::InstancesInfo const * instancesData = renderableData.data <FScene::INSTANCES>();
921
+ PerRenderableData const * const uboData = renderableData.data <FScene::UBO>();
922
+ mat4f const * const worldTransformData = renderableData.data <FScene::WORLD_TRANSFORM>();
923
+
924
+ // regular renderables count
925
+ size_t const rcount = visibleRenderables.size ();
926
+
927
+ // instanced renderables count
928
+ size_t icount = 0 ;
929
+ for (uint32_t const i : visibleRenderables) {
930
+ auto & instancesInfo = instancesData[i];
931
+ if (instancesInfo.buffer ) {
932
+ assert_invariant (instancesInfo.count == instancesInfo.buffer ->getInstanceCount ());
933
+ icount += instancesInfo.count ;
934
+ }
935
+ }
936
+
937
+ // total count of PerRenderableData slots we need
938
+ size_t const tcount = rcount + icount;
939
+
940
+ // resize the UBO accordingly
941
+ if (mRenderableUBOElementCount < tcount) {
942
+ // allocate 1/3 extra, with a minimum of 16 objects
943
+ const size_t count = std::max (size_t (16u ), (4u * tcount + 2u ) / 3u );
944
+ mRenderableUBOElementCount = count;
945
+ driver.destroyBufferObject (mRenderableUbh );
946
+ mRenderableUbh = driver.createBufferObject (
947
+ count * sizeof (PerRenderableData) + sizeof (PerRenderableUib),
948
+ BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
949
+ } else {
950
+ // TODO: should we shrink the underlying UBO at some point?
951
+ }
952
+ assert_invariant (mRenderableUbh );
953
+
954
+
955
+ // Allocate a staging CPU buffer:
956
+ // Don't allocate more than 16 KiB directly into the render stream
957
+ static constexpr size_t MAX_STREAM_ALLOCATION_COUNT = 64 ; // 16 KiB
958
+ PerRenderableData* buffer = [&]{
959
+ if (tcount >= MAX_STREAM_ALLOCATION_COUNT) {
960
+ // use the heap allocator
961
+ auto & bufferPoolAllocator = mSharedState ->mBufferPoolAllocator ;
962
+ return static_cast <PerRenderableData*>(bufferPoolAllocator.get (tcount * sizeof (PerRenderableData)));
963
+ }
964
+ // allocate space into the command stream directly
965
+ return driver.allocatePod <PerRenderableData>(tcount);
966
+ }();
967
+
968
+
969
+ // TODO: consider using JobSystem to parallelize this.
970
+ uint32_t j = rcount;
971
+ for (uint32_t const i: visibleRenderables) {
972
+ // even the instanced ones are copied here because we need to maintain the offsets
973
+ // into the buffer currently (we could skip then because it won't be used, but
974
+ // for now it's more trouble than it's worth)
975
+ buffer[i] = uboData[i];
976
+
977
+ auto & instancesInfo = instancesData[i];
978
+ if (instancesInfo.buffer ) {
979
+ instancesInfo.buffer ->prepare (
980
+ mRenderableUbh ,
981
+ buffer, j, instancesInfo.count ,
982
+ worldTransformData[i], uboData[i]);
983
+ j += instancesInfo.count ;
984
+ }
985
+ }
986
+
987
+ // We capture state shared between Scene and the update buffer callback, because the Scene could
988
+ // be destroyed before the callback executes.
989
+ std::weak_ptr<SharedState>* const weakShared = new (std::nothrow) std::weak_ptr (mSharedState );
990
+
991
+ // update the UBO
992
+ driver.resetBufferObject (mRenderableUbh );
993
+ driver.updateBufferObjectUnsynchronized (mRenderableUbh , {
994
+ buffer, tcount * sizeof (PerRenderableData),
995
+ +[](void * p, size_t const s, void * user) {
996
+ std::weak_ptr<SharedState> const * const weakShared =
997
+ static_cast <std::weak_ptr<SharedState>*>(user);
998
+ if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof (PerRenderableData)) {
999
+ if (auto state = weakShared->lock ()) {
1000
+ state->mBufferPoolAllocator .put (p);
1001
+ }
1002
+ }
1003
+ delete weakShared;
1004
+ }, weakShared
1005
+ }, 0 );
1006
+ }
1007
+
986
1008
UTILS_NOINLINE
987
1009
/* static */ FScene::RenderableSoa::iterator FView::partition (
988
1010
FScene::RenderableSoa::iterator const begin,
0 commit comments