Browse Source

Refactor and fix the GPU scene arrays

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
4949dc9928
69 changed files with 803 additions and 708 deletions
  1. 2 2
      AnKi/Collision/Aabb.h
  2. 4 4
      AnKi/Collision/Cone.h
  3. 2 2
      AnKi/Collision/ConvexHullShape.h
  4. 2 2
      AnKi/Collision/LineSegment.h
  5. 3 3
      AnKi/Collision/Obb.h
  6. 2 2
      AnKi/Collision/Plane.h
  7. 2 2
      AnKi/Collision/Ray.h
  8. 2 2
      AnKi/Collision/Sphere.h
  9. 1 1
      AnKi/Gr/RenderGraph.h
  10. 2 2
      AnKi/Gr/RenderGraph.inl.h
  11. 2 2
      AnKi/Gr/Vulkan/CommandBufferImpl.h
  12. 1 1
      AnKi/Gr/Vulkan/CommandBufferImpl.inl.h
  13. 2 2
      AnKi/Gr/Vulkan/GrManager.cpp
  14. 1 1
      AnKi/Gr/Vulkan/TextureImpl.cpp
  15. 2 2
      AnKi/Gr/Vulkan/TextureImpl.h
  16. 1 1
      AnKi/Physics/PhysicsWorld.cpp
  17. 2 2
      AnKi/Physics/PhysicsWorld.h
  18. 1 29
      AnKi/Renderer/Common.h
  19. 19 11
      AnKi/Renderer/PackVisibleClusteredObjects.cpp
  20. 22 3
      AnKi/Renderer/PrimaryNonRenderableVisibility.cpp
  21. 1 1
      AnKi/Renderer/Renderer.cpp
  22. 88 42
      AnKi/Renderer/Utils/GpuVisibility.cpp
  23. 1 1
      AnKi/Resource/ModelResource.cpp
  24. 1 1
      AnKi/Resource/ModelResource.h
  25. 1 1
      AnKi/Resource/ShaderProgramResourceSystem.cpp
  26. 1 0
      AnKi/Scene/Components/CameraComponent.h
  27. 4 3
      AnKi/Scene/Components/DecalComponent.cpp
  28. 3 2
      AnKi/Scene/Components/DecalComponent.h
  29. 2 2
      AnKi/Scene/Components/FogDensityComponent.cpp
  30. 3 2
      AnKi/Scene/Components/FogDensityComponent.h
  31. 2 3
      AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp
  32. 2 2
      AnKi/Scene/Components/GlobalIlluminationProbeComponent.h
  33. 12 12
      AnKi/Scene/Components/LightComponent.cpp
  34. 3 3
      AnKi/Scene/Components/LightComponent.h
  35. 36 36
      AnKi/Scene/Components/ModelComponent.cpp
  36. 6 5
      AnKi/Scene/Components/ModelComponent.h
  37. 66 44
      AnKi/Scene/Components/ParticleEmitterComponent.cpp
  38. 6 3
      AnKi/Scene/Components/ParticleEmitterComponent.h
  39. 2 2
      AnKi/Scene/Components/ReflectionProbeComponent.cpp
  40. 2 2
      AnKi/Scene/Components/ReflectionProbeComponent.h
  41. 0 1
      AnKi/Scene/Components/SceneComponent.h
  42. 0 171
      AnKi/Scene/ContiguousArrayAllocator.cpp
  43. 0 230
      AnKi/Scene/ContiguousArrayAllocator.h
  44. 191 0
      AnKi/Scene/GpuSceneArray.h
  45. 156 0
      AnKi/Scene/GpuSceneArray.inl.h
  46. 44 0
      AnKi/Scene/GpuSceneArrays.def.h
  47. 1 1
      AnKi/Scene/Octree.cpp
  48. 3 3
      AnKi/Scene/Octree.h
  49. 29 4
      AnKi/Scene/SceneGraph.cpp
  50. 0 1
      AnKi/Scene/SceneGraph.h
  51. 0 3
      AnKi/Scene/SceneNode.h
  52. 1 1
      AnKi/ShaderCompiler/ShaderProgramReflection.cpp
  53. 6 3
      AnKi/Shaders/GpuVisibility.ankiprog
  54. 1 1
      AnKi/Shaders/GpuVisibilityNonRenderables.ankiprog
  55. 4 0
      AnKi/Shaders/Include/Common.h
  56. 2 2
      AnKi/Shaders/Include/GpuSceneFunctions.h
  57. 24 18
      AnKi/Shaders/Include/GpuSceneTypes.h
  58. 0 5
      AnKi/Shaders/Include/GpuVisibilityTypes.h
  59. 3 0
      AnKi/Shaders/Intellisense.hlsl
  60. 2 2
      AnKi/Util/Assert.h
  61. 1 1
      AnKi/Util/Singleton.cpp
  62. 5 5
      AnKi/Util/Singleton.h
  63. 1 1
      AnKi/Util/ThreadHive.h
  64. 2 2
      AnKi/Window/InputAndroid.cpp
  65. 2 2
      AnKi/Window/InputDummy.cpp
  66. 2 2
      AnKi/Window/InputSdl.cpp
  67. 2 2
      AnKi/Window/NativeWindowAndroid.cpp
  68. 2 2
      AnKi/Window/NativeWindowHeadless.cpp
  69. 2 2
      AnKi/Window/NativeWindowSdl.cpp

+ 2 - 2
AnKi/Collision/Aabb.h

@@ -105,13 +105,13 @@ public:
 
 private:
 	Vec4 m_min
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Vec4 m_max
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMinF32)
 #endif
 		;

+ 4 - 4
AnKi/Collision/Cone.h

@@ -106,25 +106,25 @@ public:
 
 private:
 	Vec4 m_origin
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Vec4 m_dir
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	F32 m_length
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= -1.0f
 #endif
 		;
 
 	F32 m_angle
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= -1.0f
 #endif
 		;

+ 2 - 2
AnKi/Collision/ConvexHullShape.h

@@ -92,13 +92,13 @@ private:
 	Transform m_invTrf;
 
 	const Vec4* m_points
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= nullptr
 #endif
 		;
 
 	U32 m_pointCount
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= 0
 #endif
 		;

+ 2 - 2
AnKi/Collision/LineSegment.h

@@ -77,13 +77,13 @@ public:
 
 private:
 	Vec4 m_origin ///< P0
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Vec4 m_dir ///< P1 = origin+dir so dir = P1-origin
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;

+ 3 - 3
AnKi/Collision/Obb.h

@@ -109,19 +109,19 @@ public:
 
 private:
 	Vec4 m_center
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Vec4 m_extend /// With identity rotation this points to max (front, right, top in our case)
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Mat3x4 m_rotation
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Mat3x4(kMaxF32)
 #endif
 		;

+ 2 - 2
AnKi/Collision/Plane.h

@@ -90,13 +90,13 @@ public:
 
 private:
 	Vec4 m_normal
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	F32 m_offset
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= kMaxF32
 #endif
 		;

+ 2 - 2
AnKi/Collision/Ray.h

@@ -95,13 +95,13 @@ public:
 
 private:
 	Vec4 m_origin
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	Vec4 m_dir
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;

+ 2 - 2
AnKi/Collision/Sphere.h

@@ -111,13 +111,13 @@ public:
 
 private:
 	Vec4 m_center
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 #endif
 		;
 
 	F32 m_radius
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= -1.0f
 #endif
 		;

+ 1 - 1
AnKi/Gr/RenderGraph.h

@@ -188,7 +188,7 @@ public:
 	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, U32 arrayIdx = 0)
 	{
 		Texture* tex;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		tex = &getTexture(handle);
 		ANKI_ASSERT(tex->getLayerCount() == 1 && tex->getMipmapCount() == 1 && tex->getDepthStencilAspect() == DepthStencilAspectBit::kNone);
 #endif

+ 2 - 2
AnKi/Gr/RenderGraph.inl.h

@@ -143,7 +143,7 @@ inline void RenderPassDescriptionBase::newDependency(const RenderPassDependency&
 		m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx].m_usageDerivedByDeps |= dep.m_texture.m_usage;
 
 		// Checks
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		const RenderGraphDescription::RT& rt = m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx];
 		if((!rt.m_importedTex.isCreated() && !!getFormatInfo(rt.m_initInfo.m_format).m_depthStencil)
 		   || (rt.m_importedTex.isCreated() && !!rt.m_importedTex->getDepthStencilAspect()))
@@ -206,7 +206,7 @@ inline void GraphicsRenderPassDescription::setFramebufferInfo(const FramebufferD
 															  RenderTargetHandle shadingRateRenderTargetHandle, U32 minx, U32 miny, U32 maxx,
 															  U32 maxy)
 {
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	ANKI_ASSERT(fbInfo.isBacked() && "Forgot call GraphicsRenderPassFramebufferInfo::bake");
 	for(U32 i = 0; i < colorRenderTargetHandles.getSize(); ++i)
 	{

+ 2 - 2
AnKi/Gr/Vulkan/CommandBufferImpl.h

@@ -421,7 +421,7 @@ public:
 		commandCommon();
 		vkCmdSetLineWidth(m_handle, width);
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		m_lineWidthSet = true;
 #endif
 	}
@@ -507,7 +507,7 @@ private:
 	Array<U32, 2> m_stencilCompareMasks = {0x5A5A5A5A, 0x5A5A5A5A}; ///< Use a stupid number to initialize.
 	Array<U32, 2> m_stencilWriteMasks = {0x5A5A5A5A, 0x5A5A5A5A};
 	Array<U32, 2> m_stencilReferenceMasks = {0x5A5A5A5A, 0x5A5A5A5A};
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	Bool m_lineWidthSet = false;
 #endif
 	Bool m_vrsRateDirty = true;

+ 1 - 1
AnKi/Gr/Vulkan/CommandBufferImpl.inl.h

@@ -366,7 +366,7 @@ ANKI_FORCE_INLINE void CommandBufferImpl::drawcallCommon()
 	}
 
 	// Some checks
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	if(m_state.getPrimitiveTopology() == PrimitiveTopology::kLines || m_state.getPrimitiveTopology() == PrimitiveTopology::kLineStip)
 	{
 		ANKI_ASSERT(m_lineWidthSet == true);

+ 2 - 2
AnKi/Gr/Vulkan/GrManager.cpp

@@ -29,7 +29,7 @@ GrManager& MakeSingletonPtr<GrManager>::allocateSingleton<>()
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new GrManagerImpl;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 
@@ -43,7 +43,7 @@ void MakeSingletonPtr<GrManager>::freeSingleton()
 	{
 		delete static_cast<GrManagerImpl*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 1 - 1
AnKi/Gr/Vulkan/TextureImpl.cpp

@@ -64,7 +64,7 @@ U32 MicroImageView::getOrCreateBindlessIndex(GrManagerImpl& gr) const
 
 TextureImpl::~TextureImpl()
 {
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	if(m_usage != m_usedFor)
 	{
 		ANKI_VK_LOGW("Texture %s hasn't been used in all types of usages", getName().cstr());

+ 2 - 2
AnKi/Gr/Vulkan/TextureImpl.h

@@ -142,7 +142,7 @@ public:
 
 	Bool usageValid(TextureUsageBit usage) const
 	{
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		LockGuard<SpinLock> lock(m_usedForMtx);
 		m_usedFor |= usage;
 #endif
@@ -191,7 +191,7 @@ private:
 	/// the hashmap above.
 	MicroImageView m_singleSurfaceImageView;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	mutable TextureUsageBit m_usedFor = TextureUsageBit::kNone;
 	mutable SpinLock m_usedForMtx;
 #endif

+ 1 - 1
AnKi/Physics/PhysicsWorld.cpp

@@ -210,7 +210,7 @@ void PhysicsWorld::destroyMarkedForDeletion()
 		}
 
 		deleteInstance(PhysicsMemoryPool::getSingleton(), obj);
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		const I32 count = m_objectsCreatedCount.fetchSub(1) - 1;
 		ANKI_ASSERT(count >= 0);
 #endif

+ 2 - 2
AnKi/Physics/PhysicsWorld.h

@@ -54,7 +54,7 @@ public:
 			LockGuard<Mutex> lock(m_markedMtx);
 			m_markedForCreation.pushBack(obj);
 		}
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		const U32 count = m_objectsCreatedCount.fetchAdd(1) + 1;
 		ANKI_ASSERT(count > 0);
 #endif
@@ -118,7 +118,7 @@ private:
 	IntrusiveList<PhysicsObject> m_markedForDeletion;
 	Mutex m_markedMtx; ///< Locks the above
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	Atomic<I32> m_objectsCreatedCount = {0};
 #endif
 

+ 1 - 29
AnKi/Renderer/Common.h

@@ -10,7 +10,7 @@
 #include <AnKi/Core/CVarSet.h>
 #include <AnKi/Shaders/Include/MiscRendererTypes.h>
 #include <AnKi/Shaders/Include/ClusteredShadingTypes.h>
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 
 namespace anki {
 
@@ -116,34 +116,6 @@ inline U32 chooseDirectionalLightShadowCascadeDetail(U32 cascade)
 {
 	return (cascade <= 1) ? 0 : 1;
 }
-
-inline GpuSceneContiguousArrayType gpuSceneNonRenderableObjectTypeToGpuSceneContiguousArrayType(GpuSceneNonRenderableObjectType type)
-{
-	GpuSceneContiguousArrayType out;
-	switch(type)
-	{
-	case GpuSceneNonRenderableObjectType::kLight:
-		out = GpuSceneContiguousArrayType::kLights;
-		break;
-	case GpuSceneNonRenderableObjectType::kDecal:
-		out = GpuSceneContiguousArrayType::kDecals;
-		break;
-	case GpuSceneNonRenderableObjectType::kFogDensityVolume:
-		out = GpuSceneContiguousArrayType::kFogDensityVolumes;
-		break;
-	case GpuSceneNonRenderableObjectType::kReflectionProbe:
-		out = GpuSceneContiguousArrayType::kReflectionProbes;
-		break;
-	case GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe:
-		out = GpuSceneContiguousArrayType::kGlobalIlluminationProbes;
-		break;
-	default:
-		ANKI_ASSERT(1);
-		out = GpuSceneContiguousArrayType::kCount;
-	}
-
-	return out;
-}
 /// @}
 
 } // end namespace anki

+ 19 - 11
AnKi/Renderer/PackVisibleClusteredObjects.cpp

@@ -10,7 +10,7 @@
 #include <AnKi/Shaders/Include/GpuSceneTypes.h>
 #include <AnKi/Shaders/Include/MiscRendererTypes.h>
 #include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 
 namespace anki {
 
@@ -111,32 +111,40 @@ void PackVisibleClusteredObjects::dispatchType(WeakArray<TRenderQueueElement> ar
 		}
 	}
 
-	GpuSceneContiguousArrayType arrayType;
+	PtrSize bufferOffset;
+	PtrSize bufferRange;
 	switch(kType)
 	{
 	case ClusteredObjectType::kPointLight:
 	case ClusteredObjectType::kSpotLight:
-		arrayType = GpuSceneContiguousArrayType::kLights;
+		bufferOffset = GpuSceneArrays::Light::getSingleton().getGpuSceneOffsetOfArrayBase();
+		bufferRange = GpuSceneArrays::Light::getSingleton().getElementSize() * GpuSceneArrays::Light::getSingleton().getElementCount();
 		break;
 	case ClusteredObjectType::kDecal:
-		arrayType = GpuSceneContiguousArrayType::kDecals;
+		bufferOffset = GpuSceneArrays::Decal::getSingleton().getGpuSceneOffsetOfArrayBase();
+		bufferRange = GpuSceneArrays::Decal::getSingleton().getElementSize() * GpuSceneArrays::Decal::getSingleton().getElementCount();
 		break;
 	case ClusteredObjectType::kFogDensityVolume:
-		arrayType = GpuSceneContiguousArrayType::kFogDensityVolumes;
+		bufferOffset = GpuSceneArrays::FogDensityVolume::getSingleton().getGpuSceneOffsetOfArrayBase();
+		bufferRange =
+			GpuSceneArrays::FogDensityVolume::getSingleton().getElementSize() * GpuSceneArrays::FogDensityVolume::getSingleton().getElementCount();
 		break;
 	case ClusteredObjectType::kGlobalIlluminationProbe:
-		arrayType = GpuSceneContiguousArrayType::kGlobalIlluminationProbes;
+		bufferOffset = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
+		bufferRange = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementSize()
+					  * GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount();
 		break;
 	case ClusteredObjectType::kReflectionProbe:
-		arrayType = GpuSceneContiguousArrayType::kReflectionProbes;
+		bufferOffset = GpuSceneArrays::ReflectionProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
+		bufferRange =
+			GpuSceneArrays::ReflectionProbe::getSingleton().getElementSize() * GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount();
 		break;
 	default:
-		arrayType = GpuSceneContiguousArrayType::kCount;
+		bufferOffset = 0;
+		bufferRange = 0;
 	}
 
-	cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), GpuSceneContiguousArrays::getSingleton().getArrayBaseOffset(arrayType),
-						   GpuSceneContiguousArrays::getSingleton().getElementCount(arrayType)
-							   * GpuSceneContiguousArrays::getSingleton().getElementSize(arrayType));
+	cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), bufferOffset, bufferRange);
 
 	cmdb.bindStorageBuffer(0, 1, m_allClustererObjects.get(), m_structureBufferOffsets[kType], array.getSize() * sizeof(TClustererType));
 

+ 22 - 3
AnKi/Renderer/PrimaryNonRenderableVisibility.cpp

@@ -5,7 +5,7 @@
 
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
 #include <AnKi/Renderer/Renderer.h>
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Shaders/Include/GpuSceneFunctions.h>
 
 namespace anki {
@@ -18,8 +18,27 @@ void PrimaryNonRenderableVisibility::populateRenderGraph(RenderingContext& ctx)
 
 	for(GpuSceneNonRenderableObjectType type : EnumIterable<GpuSceneNonRenderableObjectType>())
 	{
-		const GpuSceneContiguousArrayType arrayType = gpuSceneNonRenderableObjectTypeToGpuSceneContiguousArrayType(type);
-		const U32 objCount = GpuSceneContiguousArrays::getSingleton().getElementCount(arrayType);
+		U32 objCount = 0;
+		switch(type)
+		{
+		case GpuSceneNonRenderableObjectType::kLight:
+			objCount = GpuSceneArrays::Light::getSingleton().getElementCount();
+			break;
+		case GpuSceneNonRenderableObjectType::kDecal:
+			objCount = GpuSceneArrays::Decal::getSingleton().getElementCount();
+			break;
+		case GpuSceneNonRenderableObjectType::kFogDensityVolume:
+			objCount = GpuSceneArrays::FogDensityVolume::getSingleton().getElementCount();
+			break;
+		case GpuSceneNonRenderableObjectType::kReflectionProbe:
+			objCount = GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount();
+			break;
+		case GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe:
+			objCount = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount();
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
 
 		if(objCount == 0)
 		{

+ 1 - 1
AnKi/Renderer/Renderer.cpp

@@ -620,7 +620,7 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, Text
 
 void Renderer::registerDebugRenderTarget(RendererObject* obj, CString rtName)
 {
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	for(const DebugRtInfo& inf : m_debugRts)
 	{
 		ANKI_ASSERT(inf.m_rtName != rtName && "Choose different name");

+ 88 - 42
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -6,7 +6,7 @@
 #include <AnKi/Renderer/Utils/GpuVisibility.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Scene/RenderStateBucket.h>
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
 #include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
 #include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
@@ -19,25 +19,6 @@ namespace anki {
 static StatCounter g_visibleObjects(StatCategory::kMisc, "Visible objects", StatFlag::kZeroEveryFrame);
 static StatCounter g_testedObjects(StatCategory::kMisc, "Visbility tested objects", StatFlag::kZeroEveryFrame);
 
-static GpuSceneContiguousArrayType techniqueToArrayType(RenderingTechnique technique)
-{
-	GpuSceneContiguousArrayType arrayType;
-	switch(technique)
-	{
-	case RenderingTechnique::kGBuffer:
-		arrayType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesGBuffer;
-		break;
-	case RenderingTechnique::kDepth:
-		arrayType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesDepth;
-		break;
-	default:
-		ANKI_ASSERT(0);
-		arrayType = GpuSceneContiguousArrayType::kCount;
-	}
-
-	return arrayType;
-}
-
 Error GpuVisibility::init()
 {
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuVisibility.ankiprogbin", m_prog));
@@ -68,7 +49,18 @@ void GpuVisibility::populateRenderGraph(CString passesName, RenderingTechnique t
 										const Array<F32, kMaxLodCount - 1> lodDistances, const RenderTargetHandle* hzbRt,
 										RenderGraphDescription& rgraph, GpuVisibilityOutput& out)
 {
-	const U32 aabbCount = GpuSceneContiguousArrays::getSingleton().getElementCount(techniqueToArrayType(technique));
+	U32 aabbCount = 0;
+	switch(technique)
+	{
+	case RenderingTechnique::kGBuffer:
+		aabbCount = GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getElementCount();
+	case RenderingTechnique::kDepth:
+		aabbCount = GpuSceneArrays::RenderableAabbDepth::getSingleton().getElementCount();
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
 	const U32 bucketCount = RenderStateBucketContainer::getSingleton().getBucketCount(technique);
 
 #if ANKI_STATS_ENABLED
@@ -138,7 +130,7 @@ void GpuVisibility::populateRenderGraph(CString passesName, RenderingTechnique t
 		(hzbRt) ? *hzbRt : RenderTargetHandle(); // Can't pass to the lambda the hzbRt which is a pointer to who knows what
 
 	pass.setWork([this, viewProjectionMat, lodReferencePoint, lodDistances, technique, hzbRtCopy, mdiDrawCountsHandle = out.m_mdiDrawCountsHandle,
-				  instanceRateRenderables, indirectArgs
+				  instanceRateRenderables, indirectArgs, aabbCount
 #if ANKI_STATS_ENABLED
 				  ,
 				  clearStatsBuffer, clearStatsBufferOffset, writeStatsBuffer, writeStatsBufferOffset
@@ -148,16 +140,27 @@ void GpuVisibility::populateRenderGraph(CString passesName, RenderingTechnique t
 
 		cmdb.bindShaderProgram(m_grProgs[hzbRtCopy.isValid()].get());
 
-		const GpuSceneContiguousArrayType type = techniqueToArrayType(technique);
-
-		cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), GpuSceneContiguousArrays::getSingleton().getArrayBaseOffset(type),
-							   GpuSceneContiguousArrays::getSingleton().getElementCount(type)
-								   * GpuSceneContiguousArrays::getSingleton().getElementSize(type));
+		switch(technique)
+		{
+		case RenderingTechnique::kGBuffer:
+			cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(),
+								   GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getGpuSceneOffsetOfArrayBase(),
+								   GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getElementCount()
+									   * GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getElementSize());
+			break;
+		case RenderingTechnique::kDepth:
+			cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(),
+								   GpuSceneArrays::RenderableAabbDepth::getSingleton().getGpuSceneOffsetOfArrayBase(),
+								   GpuSceneArrays::RenderableAabbDepth::getSingleton().getElementCount()
+									   * GpuSceneArrays::RenderableAabbDepth::getSingleton().getElementSize());
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
 
-		cmdb.bindStorageBuffer(0, 1, &GpuSceneBuffer::getSingleton().getBuffer(),
-							   GpuSceneContiguousArrays::getSingleton().getArrayBaseOffset(GpuSceneContiguousArrayType::kRenderables),
-							   GpuSceneContiguousArrays::getSingleton().getElementCount(GpuSceneContiguousArrayType::kRenderables)
-								   * GpuSceneContiguousArrays::getSingleton().getElementSize(GpuSceneContiguousArrayType::kRenderables));
+		cmdb.bindStorageBuffer(
+			0, 1, &GpuSceneBuffer::getSingleton().getBuffer(), GpuSceneArrays::Renderable::getSingleton().getGpuSceneOffsetOfArrayBase(),
+			GpuSceneArrays::Renderable::getSingleton().getElementCount() * GpuSceneArrays::Renderable::getSingleton().getElementSize());
 
 		cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize);
 
@@ -185,9 +188,6 @@ void GpuVisibility::populateRenderGraph(CString passesName, RenderingTechnique t
 			unis->m_clipPlanes[i] = Vec4(planes[i].getNormal().xyz(), planes[i].getOffset());
 		}
 
-		const U32 aabbCount = GpuSceneContiguousArrays::getSingleton().getElementCount(type);
-		unis->m_aabbCount = aabbCount;
-
 		ANKI_ASSERT(kMaxLodCount == 3);
 		unis->m_maxLodDistances[0] = lodDistances[0];
 		unis->m_maxLodDistances[1] = lodDistances[1];
@@ -270,8 +270,27 @@ Error GpuVisibilityNonRenderables::init()
 
 void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderablesInput& in, GpuVisibilityNonRenderablesOutput& out)
 {
-	const GpuSceneContiguousArrayType arrayType = gpuSceneNonRenderableObjectTypeToGpuSceneContiguousArrayType(in.m_objectType);
-	const U32 objCount = GpuSceneContiguousArrays::getSingleton().getElementCount(arrayType);
+	U32 objCount = 0;
+	switch(in.m_objectType)
+	{
+	case GpuSceneNonRenderableObjectType::kLight:
+		objCount = GpuSceneArrays::Light::getSingleton().getElementCount();
+		break;
+	case GpuSceneNonRenderableObjectType::kDecal:
+		objCount = GpuSceneArrays::Decal::getSingleton().getElementCount();
+		break;
+	case GpuSceneNonRenderableObjectType::kFogDensityVolume:
+		objCount = GpuSceneArrays::FogDensityVolume::getSingleton().getElementCount();
+		break;
+	case GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe:
+		objCount = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount();
+		break;
+	case GpuSceneNonRenderableObjectType::kReflectionProbe:
+		objCount = GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount();
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
 
 	if(objCount == 0)
 	{
@@ -317,17 +336,44 @@ void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderable
 	}
 
 	pass.setWork([this, objType = in.m_objectType, feedbackBuffer = in.m_cpuFeedbackBuffer, viewProjectionMat = in.m_viewProjectionMat,
-				  visibleIndicesBuffHandle = out.m_bufferHandle, counterBufferIdx](RenderPassWorkContext& rgraph) {
+				  visibleIndicesBuffHandle = out.m_bufferHandle, counterBufferIdx, objCount](RenderPassWorkContext& rgraph) {
 		CommandBuffer& cmdb = *rgraph.m_commandBuffer;
-		const GpuSceneContiguousArrayType arrayType = gpuSceneNonRenderableObjectTypeToGpuSceneContiguousArrayType(objType);
-		const U32 objCount = GpuSceneContiguousArrays::getSingleton().getElementCount(arrayType);
-		const GpuSceneContiguousArrays& cArrays = GpuSceneContiguousArrays::getSingleton();
+
 		const Bool needsFeedback = feedbackBuffer.m_buffer != nullptr;
 
 		cmdb.bindShaderProgram(m_grProgs[0][objType][needsFeedback].get());
 
-		cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), cArrays.getArrayBaseOffset(arrayType),
-							   cArrays.getElementSize(arrayType) * cArrays.getElementCount(arrayType), 0);
+		PtrSize objBufferOffset = 0;
+		PtrSize objBufferRange = 0;
+		switch(objType)
+		{
+		case GpuSceneNonRenderableObjectType::kLight:
+			objBufferOffset = GpuSceneArrays::Light::getSingleton().getGpuSceneOffsetOfArrayBase();
+			objBufferRange = GpuSceneArrays::Light::getSingleton().getElementCount() * GpuSceneArrays::Light::getSingleton().getElementSize();
+			break;
+		case GpuSceneNonRenderableObjectType::kDecal:
+			objBufferOffset = GpuSceneArrays::Decal::getSingleton().getGpuSceneOffsetOfArrayBase();
+			objBufferRange = GpuSceneArrays::Decal::getSingleton().getElementCount() * GpuSceneArrays::Decal::getSingleton().getElementSize();
+			break;
+		case GpuSceneNonRenderableObjectType::kFogDensityVolume:
+			objBufferOffset = GpuSceneArrays::FogDensityVolume::getSingleton().getGpuSceneOffsetOfArrayBase();
+			objBufferRange = GpuSceneArrays::FogDensityVolume::getSingleton().getElementCount()
+							 * GpuSceneArrays::FogDensityVolume::getSingleton().getElementSize();
+			break;
+		case GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe:
+			objBufferOffset = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
+			objBufferRange = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount()
+							 * GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementSize();
+			break;
+		case GpuSceneNonRenderableObjectType::kReflectionProbe:
+			objBufferOffset = GpuSceneArrays::ReflectionProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
+			objBufferRange =
+				GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount() * GpuSceneArrays::ReflectionProbe::getSingleton().getElementSize();
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
+		cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
 
 		GpuVisibilityNonRenderableUniforms unis;
 		Array<Plane, 6> planes;

+ 1 - 1
AnKi/Resource/ModelResource.cpp

@@ -65,7 +65,7 @@ void ModelPatch::getRayTracingInfo(const RenderingKey& key, ModelRayTracingInfo&
 
 Error ModelPatch::init([[maybe_unused]] ModelResource* model, CString meshFName, const CString& mtlFName, U32 subMeshIndex, Bool async)
 {
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	m_model = model;
 #endif
 

+ 1 - 1
AnKi/Resource/ModelResource.h

@@ -97,7 +97,7 @@ private:
 		Array<PtrSize, U32(VertexStreamId::kMeshRelatedCount)> m_vertexBufferOffsets = {};
 	};
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	ModelResource* m_model = nullptr;
 #endif
 	MaterialResourcePtr m_mtl;

+ 1 - 1
AnKi/Resource/ShaderProgramResourceSystem.cpp

@@ -109,7 +109,7 @@ Error ShaderProgramResourceSystem::createRayTracingPrograms(ResourceDynamicArray
 		void addGroup(CString filename, U64 mutationHash, U32 rayGen, U32 miss, U32 chit, U32 ahit)
 		{
 			const U64 groupHash = ShaderProgramRaytracingLibrary::generateShaderGroupGroupHash(filename, mutationHash);
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 			for(const ShaderGroup& group : m_shaderGroups)
 			{
 				ANKI_ASSERT(group.m_hitGroupHash != groupHash && "Shouldn't find group with the same hash");

+ 1 - 0
AnKi/Scene/Components/CameraComponent.h

@@ -7,6 +7,7 @@
 
 #include <AnKi/Scene/Components/SceneComponent.h>
 #include <AnKi/Scene/Frustum.h>
+#include <AnKi/Core/CVarSet.h>
 
 namespace anki {
 

+ 4 - 3
AnKi/Scene/Components/DecalComponent.cpp

@@ -15,7 +15,7 @@ DecalComponent::DecalComponent(SceneNode* node)
 	: SceneComponent(node, getStaticClassId())
 	, m_spatial(this)
 {
-	m_gpuSceneIndex = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kDecals);
+	m_gpuSceneDecal.allocate();
 }
 
 DecalComponent::~DecalComponent()
@@ -85,9 +85,10 @@ Error DecalComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 
 		gpuDecal.m_obbExtend = m_obb.getExtend().xyz();
 
-		gpuDecal.m_boundingSphere = Vec4(m_obb.getCenter().xyz(), m_obb.getExtend().getLength());
+		gpuDecal.m_sphereCenter = m_obb.getCenter().xyz();
+		gpuDecal.m_sphereRadius = m_obb.getExtend().getLength();
 
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneIndex.getOffsetInGpuScene(), gpuDecal);
+		m_gpuSceneDecal.uploadToGpuScene(gpuDecal);
 	}
 
 	const Bool spatialUpdated = m_spatial.update(SceneGraph::getSingleton().getOctree());

+ 3 - 2
AnKi/Scene/Components/DecalComponent.h

@@ -7,6 +7,7 @@
 
 #include <AnKi/Scene/Components/SceneComponent.h>
 #include <AnKi/Scene/Spatial.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Resource/ImageAtlasResource.h>
 #include <AnKi/Collision/Obb.h>
 #include <AnKi/Renderer/RenderQueue.h>
@@ -67,7 +68,7 @@ public:
 		el.m_obbCenter = m_obb.getCenter().xyz();
 		el.m_obbExtend = m_obb.getExtend().xyz();
 		el.m_obbRotation = m_obb.getRotation().getRotationPart();
-		el.m_index = m_gpuSceneIndex.get();
+		el.m_index = m_gpuSceneDecal.getIndex();
 	}
 
 private:
@@ -93,7 +94,7 @@ private:
 	Vec3 m_boxSize = Vec3(1.0f);
 	Obb m_obb = Obb(Vec4(0.0f), Mat3x4::getIdentity(), Vec4(0.5f, 0.5f, 0.5f, 0.0f));
 
-	GpuSceneContiguousArrayIndex m_gpuSceneIndex;
+	GpuSceneArrays::Decal::Allocation m_gpuSceneDecal;
 
 	Bool m_dirty = true;
 

+ 2 - 2
AnKi/Scene/Components/FogDensityComponent.cpp

@@ -14,7 +14,7 @@ FogDensityComponent::FogDensityComponent(SceneNode* node)
 	: SceneComponent(node, getStaticClassId())
 	, m_spatial(this)
 {
-	m_gpuSceneIndex = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kFogDensityVolumes);
+	m_gpuSceneVolume.allocate();
 }
 
 FogDensityComponent ::~FogDensityComponent()
@@ -58,7 +58,7 @@ Error FogDensityComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		gpuVolume.m_isBox = m_isBox;
 		gpuVolume.m_density = m_density;
 
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneIndex.getOffsetInGpuScene(), gpuVolume);
+		m_gpuSceneVolume.uploadToGpuScene(gpuVolume);
 	}
 
 	const Bool spatialUpdated = m_spatial.update(SceneGraph::getSingleton().getOctree());

+ 3 - 2
AnKi/Scene/Components/FogDensityComponent.h

@@ -7,6 +7,7 @@
 
 #include <AnKi/Scene/Components/SceneComponent.h>
 #include <AnKi/Scene/Spatial.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Collision/Sphere.h>
@@ -92,7 +93,7 @@ public:
 			el.m_sphereCenter = m_worldPos.xyz();
 			el.m_sphereRadius = m_sphereRadius;
 		}
-		el.m_index = m_gpuSceneIndex.get();
+		el.m_index = m_gpuSceneVolume.getIndex();
 	}
 
 private:
@@ -109,7 +110,7 @@ private:
 	Vec3 m_worldPos = Vec3(0.0f);
 	F32 m_density = 1.0f;
 
-	GpuSceneContiguousArrayIndex m_gpuSceneIndex;
+	GpuSceneArrays::FogDensityVolume::Allocation m_gpuSceneVolume;
 
 	Bool m_isBox = true;
 	Bool m_dirty = true;

+ 2 - 3
AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp

@@ -25,7 +25,7 @@ GlobalIlluminationProbeComponent::GlobalIlluminationProbeComponent(SceneNode* no
 		m_frustums[i].update();
 	}
 
-	m_gpuSceneIndex = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kGlobalIlluminationProbes);
+	m_gpuSceneProbe.allocate();
 
 	const Error err = ResourceManager::getSingleton().loadResource("ShaderBinaries/ClearTextureCompute.ankiprogbin", m_clearTextureProg);
 	if(err)
@@ -118,8 +118,7 @@ Error GlobalIlluminationProbeComponent::update(SceneComponentUpdateInfo& info, B
 		gpuProbe.m_halfTexelSizeU = 1.0f / (F32(m_cellCounts.y()) * 6.0f) / 2.0f;
 		gpuProbe.m_fadeDistance = m_fadeDistance;
 		gpuProbe.m_uuid = getUuid();
-
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneIndex.getOffsetInGpuScene(), gpuProbe);
+		m_gpuSceneProbe.uploadToGpuScene(gpuProbe);
 	}
 
 	if(needsRefresh()) [[unlikely]]

+ 2 - 2
AnKi/Scene/Components/GlobalIlluminationProbeComponent.h

@@ -77,7 +77,7 @@ public:
 		el.m_cellSizes = (m_halfSize * 2.0f) / Vec3(m_cellCounts);
 		el.m_fadeDistance = m_fadeDistance;
 		el.m_volumeTextureBindlessIndex = m_volTexBindlessIdx;
-		el.m_index = m_gpuSceneIndex.get();
+		el.m_index = m_gpuSceneProbe.getIndex();
 	}
 
 	void setupGlobalIlluminationProbeQueueElementForRefresh(GlobalIlluminationProbeQueueElementForRefresh& el)
@@ -111,7 +111,7 @@ private:
 	TextureViewPtr m_volView;
 	U32 m_volTexBindlessIdx = 0;
 
-	GpuSceneContiguousArrayIndex m_gpuSceneIndex;
+	GpuSceneArrays::GlobalIlluminationProbe::Allocation m_gpuSceneProbe;
 
 	Array<Frustum, 6> m_frustums;
 

+ 12 - 12
AnKi/Scene/Components/LightComponent.cpp

@@ -50,16 +50,6 @@ void LightComponent::setLightComponentType(LightComponentType type)
 		m_spatial.setUpdatesOctreeBounds(true);
 	}
 
-	if(m_typeChanged)
-	{
-		GpuSceneContiguousArrays::getSingleton().deferredFree(m_gpuSceneLightIndex);
-	}
-
-	if(!m_gpuSceneLightIndex.isValid() && (type == LightComponentType::kPoint || type == LightComponentType::kSpot))
-	{
-		m_gpuSceneLightIndex = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kLights);
-	}
-
 	m_type = type;
 }
 
@@ -131,7 +121,11 @@ Error LightComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		gpuLight.m_squareRadiusOverOne = 1.0f / (m_point.m_radius * m_point.m_radius);
 		gpuLight.m_shadow = m_shadow;
 		gpuLight.m_uuid = (m_shadow) ? getUuid() : 0;
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneLightIndex.getOffsetInGpuScene(), gpuLight);
+		if(!m_gpuSceneLight.isValid())
+		{
+			m_gpuSceneLight.allocate();
+		}
+		m_gpuSceneLight.uploadToGpuScene(gpuLight);
 	}
 	else if(updated && m_type == LightComponentType::kSpot)
 	{
@@ -205,12 +199,18 @@ Error LightComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		gpuLight.m_outerCos = cos(m_spot.m_outerAngle / 2.0f);
 		gpuLight.m_innerCos = cos(m_spot.m_innerAngle / 2.0f);
 		gpuLight.m_uuid = (m_shadow) ? getUuid() : 0;
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneLightIndex.getOffsetInGpuScene(), gpuLight);
+		if(!m_gpuSceneLight.isValid())
+		{
+			m_gpuSceneLight.allocate();
+		}
+		m_gpuSceneLight.uploadToGpuScene(gpuLight);
 	}
 	else if(m_type == LightComponentType::kDirectional)
 	{
 		// Update the scene bounds always
 		SceneGraph::getSingleton().getOctree().getActualSceneBounds(m_dir.m_sceneMin, m_dir.m_sceneMax);
+
+		m_gpuSceneLight.free();
 	}
 
 	const Bool spatialUpdated = m_spatial.update(SceneGraph::getSingleton().getOctree());

+ 3 - 3
AnKi/Scene/Components/LightComponent.h

@@ -124,7 +124,7 @@ public:
 		el.m_radius = m_point.m_radius;
 		el.m_diffuseColor = m_diffColor.xyz();
 		el.m_shadowLayer = kMaxU8;
-		el.m_index = m_gpuSceneLightIndex.get();
+		el.m_index = m_gpuSceneLight.getIndex();
 	}
 
 	void setupSpotLightQueueElement(SpotLightQueueElement& el) const
@@ -139,7 +139,7 @@ public:
 		el.m_diffuseColor = m_diffColor.xyz();
 		el.m_edgePoints = m_spot.m_edgePointsWspace;
 		el.m_shadowLayer = kMaxU8;
-		el.m_index = m_gpuSceneLightIndex.get();
+		el.m_index = m_gpuSceneLight.getIndex();
 	}
 
 	/// Setup a directional queue element.
@@ -183,7 +183,7 @@ private:
 
 	Frustum* m_frustums = nullptr;
 
-	GpuSceneContiguousArrayIndex m_gpuSceneLightIndex;
+	GpuSceneArrays::Light::Allocation m_gpuSceneLight;
 
 	LightComponentType m_type;
 

+ 36 - 36
AnKi/Scene/Components/ModelComponent.cpp

@@ -19,7 +19,7 @@ ModelComponent::ModelComponent(SceneNode* node)
 	, m_node(node)
 	, m_spatial(this)
 {
-	m_gpuSceneIndexTransforms = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kTransformPairs);
+	m_gpuSceneTransforms.allocate();
 }
 
 ModelComponent::~ModelComponent()
@@ -31,18 +31,13 @@ void ModelComponent::freeGpuScene()
 {
 	GpuSceneBuffer::getSingleton().deferredFree(m_gpuSceneUniforms);
 
-	GpuSceneContiguousArrays& arr = GpuSceneContiguousArrays::getSingleton();
-
 	for(PatchInfo& patch : m_patchInfos)
 	{
-		arr.deferredFree(patch.m_gpuSceneIndexMeshLods);
-
-		arr.deferredFree(patch.m_gpuSceneIndexRenderable);
-
-		for(GpuSceneContiguousArrayIndex& idx : patch.m_gpuSceneIndexRenderableAabbs)
-		{
-			arr.deferredFree(idx);
-		}
+		patch.m_gpuSceneMeshLods.free();
+		patch.m_gpuSceneRenderable.free();
+		patch.m_gpuSceneRenderableAabbDepth.free();
+		patch.m_gpuSceneRenderableAabbForward.free();
+		patch.m_gpuSceneRenderableAabbGBuffer.free();
 
 		for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
 		{
@@ -96,9 +91,8 @@ void ModelComponent::loadModelResource(CString filename)
 		out.m_gpuSceneUniformsOffset = m_gpuSceneUniforms.getOffset() + uniformsSize;
 		uniformsSize += U32(in.getMaterial()->getPrefilledLocalUniforms().getSizeInBytes());
 
-		out.m_gpuSceneIndexMeshLods = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kMeshLods);
-
-		out.m_gpuSceneIndexRenderable = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kRenderables);
+		out.m_gpuSceneMeshLods.allocate();
+		out.m_gpuSceneRenderable.allocate();
 
 		for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
 		{
@@ -107,23 +101,20 @@ void ModelComponent::loadModelResource(CString filename)
 				continue;
 			}
 
-			GpuSceneContiguousArrayType allocType = GpuSceneContiguousArrayType::kCount;
 			switch(t)
 			{
 			case RenderingTechnique::kGBuffer:
-				allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesGBuffer;
+				out.m_gpuSceneRenderableAabbGBuffer.allocate();
 				break;
 			case RenderingTechnique::kForward:
-				allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesForward;
+				out.m_gpuSceneRenderableAabbForward.allocate();
 				break;
 			case RenderingTechnique::kDepth:
-				allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesDepth;
+				out.m_gpuSceneRenderableAabbDepth.allocate();
 				break;
 			default:
 				ANKI_ASSERT(0);
 			}
-
-			out.m_gpuSceneIndexRenderableAabbs[t] = GpuSceneContiguousArrays::getSingleton().allocate(allocType);
 		}
 	}
 }
@@ -193,16 +184,15 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 				meshLods[l] = meshLods[l - 1];
 			}
 
-			GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_patchInfos[i].m_gpuSceneIndexMeshLods.getOffsetInGpuScene(), meshLods);
+			m_patchInfos[i].m_gpuSceneMeshLods.uploadToGpuScene(meshLods);
 
 			// Upload the GpuSceneRenderable
 			GpuSceneRenderable gpuRenderable;
-			gpuRenderable.m_worldTransformsOffset = m_gpuSceneIndexTransforms.getOffsetInGpuScene();
+			gpuRenderable.m_worldTransformsOffset = m_gpuSceneTransforms.getGpuSceneOffset();
 			gpuRenderable.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
-			gpuRenderable.m_geometryOffset = m_patchInfos[i].m_gpuSceneIndexMeshLods.getOffsetInGpuScene();
+			gpuRenderable.m_geometryOffset = m_patchInfos[i].m_gpuSceneMeshLods.getGpuSceneOffset();
 			gpuRenderable.m_boneTransformsOffset = (hasSkin) ? m_skinComponent->getBoneTransformsGpuSceneOffset() : 0;
-			GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_patchInfos[i].m_gpuSceneIndexRenderable.getOffsetInGpuScene(),
-														 gpuRenderable);
+			m_patchInfos[i].m_gpuSceneRenderable.uploadToGpuScene(gpuRenderable);
 		}
 
 		// Upload the uniforms
@@ -229,7 +219,7 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		Array<Mat3x4, 2> trfs;
 		trfs[0] = Mat3x4(info.m_node->getWorldTransform());
 		trfs[1] = Mat3x4(info.m_node->getPreviousWorldTransform());
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneIndexTransforms.getOffsetInGpuScene(), trfs);
+		m_gpuSceneTransforms.uploadToGpuScene(trfs);
 	}
 
 	// Spatial update
@@ -302,11 +292,23 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 			{
 				const Vec3 aabbMin = m_spatial.getAabbWorldSpace().getMin().xyz();
 				const Vec3 aabbMax = m_spatial.getAabbWorldSpace().getMax().xyz();
-				const GpuSceneRenderableAabb gpuVolume = initGpuSceneRenderableAabb(aabbMin, aabbMax, m_patchInfos[i].m_gpuSceneIndexRenderable.get(),
+				const GpuSceneRenderableAabb gpuVolume = initGpuSceneRenderableAabb(aabbMin, aabbMax, m_patchInfos[i].m_gpuSceneRenderable.getIndex(),
 																					m_patchInfos[i].m_renderStateBucketIndices[t].get());
 
-				GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool,
-															 m_patchInfos[i].m_gpuSceneIndexRenderableAabbs[t].getOffsetInGpuScene(), gpuVolume);
+				switch(t)
+				{
+				case RenderingTechnique::kGBuffer:
+					m_patchInfos[i].m_gpuSceneRenderableAabbGBuffer.uploadToGpuScene(gpuVolume);
+					break;
+				case RenderingTechnique::kDepth:
+					m_patchInfos[i].m_gpuSceneRenderableAabbDepth.uploadToGpuScene(gpuVolume);
+					break;
+				case RenderingTechnique::kForward:
+					m_patchInfos[i].m_gpuSceneRenderableAabbForward.uploadToGpuScene(gpuVolume);
+					break;
+				default:
+					ANKI_ASSERT(0);
+				}
 			}
 		}
 	}
@@ -369,9 +371,9 @@ void ModelComponent::setupRenderableQueueElements(U32 lod, RenderingTechnique te
 		patch.getRenderingInfo(key, modelInf);
 
 		queueElem.m_program = modelInf.m_program.get();
-		queueElem.m_worldTransformsOffset = m_gpuSceneIndexTransforms.getOffsetInGpuScene();
+		queueElem.m_worldTransformsOffset = m_gpuSceneTransforms.getGpuSceneOffset();
 		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
-		queueElem.m_geometryOffset = m_patchInfos[i].m_gpuSceneIndexMeshLods.getOffsetInGpuScene() + lod * sizeof(GpuSceneMeshLod);
+		queueElem.m_geometryOffset = m_patchInfos[i].m_gpuSceneMeshLods.getGpuSceneOffset() + lod * sizeof(GpuSceneMeshLod);
 		queueElem.m_boneTransformsOffset = (hasSkin) ? m_skinComponent->getBoneTransformsGpuSceneOffset() : 0;
 		queueElem.m_indexCount = modelInf.m_indexCount;
 		queueElem.m_firstIndex = U32(modelInf.m_indexBufferOffset / 2 + modelInf.m_firstIndex);
@@ -433,18 +435,16 @@ void ModelComponent::setupRayTracingInstanceQueueElements(U32 lod, RenderingTech
 
 		const ModelPatch& patch = m_model->getModelPatches()[i];
 
-		GpuSceneContiguousArrays& gpuArrays = GpuSceneContiguousArrays::getSingleton();
-
 		ModelRayTracingInfo modelInf;
 		patch.getRayTracingInfo(key, modelInf);
 
 		queueElem.m_bottomLevelAccelerationStructure = modelInf.m_bottomLevelAccelerationStructure.get();
 		queueElem.m_shaderGroupHandleIndex = modelInf.m_shaderGroupHandleIndex;
-		queueElem.m_worldTransformsOffset = m_gpuSceneIndexTransforms.getOffsetInGpuScene();
+		queueElem.m_worldTransformsOffset = m_gpuSceneTransforms.getGpuSceneOffset();
 		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
 		queueElem.m_geometryOffset =
-			U32(m_patchInfos[i].m_gpuSceneIndexMeshLods.get() * sizeof(GpuSceneMeshLod) * kMaxLodCount + lod * sizeof(GpuSceneMeshLod));
-		queueElem.m_geometryOffset += U32(gpuArrays.getArrayBaseOffset(GpuSceneContiguousArrayType::kMeshLods));
+			U32(m_patchInfos[i].m_gpuSceneMeshLods.getIndex() * sizeof(GpuSceneMeshLod) * kMaxLodCount + lod * sizeof(GpuSceneMeshLod));
+		queueElem.m_geometryOffset += U32(GpuSceneArrays::MeshLod::getSingleton().getGpuSceneOffsetOfArrayBase());
 		queueElem.m_indexBufferOffset = U32(modelInf.m_indexBufferOffset);
 
 		const Transform positionTransform(patch.getMesh()->getPositionsTranslation().xyz0(), Mat3x4::getIdentity(),

+ 6 - 5
AnKi/Scene/Components/ModelComponent.h

@@ -54,10 +54,11 @@ private:
 	public:
 		U32 m_gpuSceneUniformsOffset = kMaxU32;
 
-		GpuSceneContiguousArrayIndex m_gpuSceneIndexMeshLods;
-
-		GpuSceneContiguousArrayIndex m_gpuSceneIndexRenderable;
-		Array<GpuSceneContiguousArrayIndex, U32(RenderingTechnique::kCount)> m_gpuSceneIndexRenderableAabbs;
+		GpuSceneArrays::MeshLod::Allocation m_gpuSceneMeshLods;
+		GpuSceneArrays::Renderable::Allocation m_gpuSceneRenderable;
+		GpuSceneArrays::RenderableAabbGBuffer::Allocation m_gpuSceneRenderableAabbGBuffer;
+		GpuSceneArrays::RenderableAabbDepth::Allocation m_gpuSceneRenderableAabbDepth;
+		GpuSceneArrays::RenderableAabbForward::Allocation m_gpuSceneRenderableAabbForward;
 
 		Array<RenderStateBucketIndex, U32(RenderingTechnique::kCount)> m_renderStateBucketIndices;
 		RenderingTechniqueBit m_techniques;
@@ -70,7 +71,7 @@ private:
 	ModelResourcePtr m_model;
 
 	GpuSceneBufferAllocation m_gpuSceneUniforms;
-	GpuSceneContiguousArrayIndex m_gpuSceneIndexTransforms;
+	GpuSceneArrays::Transform::Allocation m_gpuSceneTransforms;
 	SceneDynamicArray<PatchInfo> m_patchInfos;
 
 	Bool m_resourceChanged : 1 = true;

+ 66 - 44
AnKi/Scene/Components/ParticleEmitterComponent.cpp

@@ -228,13 +228,6 @@ void ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
 	GpuSceneBuffer::getSingleton().deferredFree(m_gpuSceneAlphas);
 	GpuSceneBuffer::getSingleton().deferredFree(m_gpuSceneUniforms);
 
-	GpuSceneContiguousArrays::getSingleton().deferredFree(m_gpuSceneIndexParticleEmitter);
-	GpuSceneContiguousArrays::getSingleton().deferredFree(m_gpuSceneIndexRenderable);
-	for(GpuSceneContiguousArrayIndex& idx : m_gpuSceneIndexAabbs)
-	{
-		GpuSceneContiguousArrays::getSingleton().deferredFree(idx);
-	}
-
 	for(RenderStateBucketIndex& idx : m_renderStateBuckets)
 	{
 		RenderStateBucketContainer::getSingleton().removeUser(idx);
@@ -268,32 +261,6 @@ void ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
 	GpuSceneBuffer::getSingleton().allocate(m_particleEmitterResource->getMaterial()->getPrefilledLocalUniforms().getSizeInBytes(), alignof(U32),
 											m_gpuSceneUniforms);
 
-	m_gpuSceneIndexRenderable = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kRenderables);
-
-	m_gpuSceneIndexParticleEmitter = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kParticleEmitters);
-
-	for(RenderingTechnique t :
-		EnumBitsIterable<RenderingTechnique, RenderingTechniqueBit>(m_particleEmitterResource->getMaterial()->getRenderingTechniques()))
-	{
-		GpuSceneContiguousArrayType allocType = GpuSceneContiguousArrayType::kCount;
-		switch(t)
-		{
-		case RenderingTechnique::kGBuffer:
-			allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesGBuffer;
-			break;
-		case RenderingTechnique::kForward:
-			allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesForward;
-			break;
-		case RenderingTechnique::kDepth:
-			allocType = GpuSceneContiguousArrayType::kRenderableBoundingVolumesDepth;
-			break;
-		default:
-			ANKI_ASSERT(0);
-		}
-
-		m_gpuSceneIndexAabbs[t] = GpuSceneContiguousArrays::getSingleton().allocate(allocType);
-	}
-
 	// Allocate buckets
 	for(RenderingTechnique t :
 		EnumBitsIterable<RenderingTechnique, RenderingTechniqueBit>(m_particleEmitterResource->getMaterial()->getRenderingTechniques()))
@@ -356,7 +323,11 @@ Error ParticleEmitterComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 		particles.m_vertexOffsets[U32(VertexStreamId::kParticlePosition)] = m_gpuScenePositions.getOffset();
 		particles.m_vertexOffsets[U32(VertexStreamId::kParticleColor)] = m_gpuSceneAlphas.getOffset();
 		particles.m_vertexOffsets[U32(VertexStreamId::kParticleScale)] = m_gpuSceneScales.getOffset();
-		patcher.newCopy(*info.m_framePool, m_gpuSceneIndexParticleEmitter.getOffsetInGpuScene(), particles);
+		if(!m_gpuSceneParticleEmitter.isValid())
+		{
+			m_gpuSceneParticleEmitter.allocate();
+		}
+		m_gpuSceneParticleEmitter.uploadToGpuScene(particles);
 
 		// Upload uniforms
 		patcher.newCopy(*info.m_framePool, m_gpuSceneUniforms, m_particleEmitterResource->getMaterial()->getPrefilledLocalUniforms().getSizeInBytes(),
@@ -365,21 +336,72 @@ Error ParticleEmitterComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 		// Upload the GpuSceneRenderable
 		GpuSceneRenderable renderable;
 		renderable.m_boneTransformsOffset = 0;
-		renderable.m_geometryOffset = m_gpuSceneIndexParticleEmitter.getOffsetInGpuScene();
+		renderable.m_geometryOffset = m_gpuSceneParticleEmitter.getGpuSceneOffset();
 		renderable.m_uniformsOffset = m_gpuSceneUniforms.getOffset();
 		renderable.m_worldTransformsOffset = 0;
-		patcher.newCopy(*info.m_framePool, m_gpuSceneIndexRenderable.getOffsetInGpuScene(), renderable);
+		if(!m_gpuSceneRenderable.isValid())
+		{
+			m_gpuSceneRenderable.allocate();
+		}
+		m_gpuSceneRenderable.uploadToGpuScene(renderable);
 	}
 
 	// Upload the GpuSceneRenderableAabb always
-	for(RenderingTechnique t :
-		EnumBitsIterable<RenderingTechnique, RenderingTechniqueBit>(m_particleEmitterResource->getMaterial()->getRenderingTechniques()))
+	for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
 	{
-		const GpuSceneRenderableAabb gpuVolume =
-			initGpuSceneRenderableAabb(m_spatial.getAabbWorldSpace().getMin().xyz(), m_spatial.getAabbWorldSpace().getMax().xyz(),
-									   m_gpuSceneIndexRenderable.get(), m_renderStateBuckets[t].get());
-
-		patcher.newCopy(*info.m_framePool, m_gpuSceneIndexAabbs[t].getOffsetInGpuScene(), gpuVolume);
+		if(!!(RenderingTechniqueBit(1 << t) & m_particleEmitterResource->getMaterial()->getRenderingTechniques()))
+		{
+			const GpuSceneRenderableAabb gpuVolume =
+				initGpuSceneRenderableAabb(m_spatial.getAabbWorldSpace().getMin().xyz(), m_spatial.getAabbWorldSpace().getMax().xyz(),
+										   m_gpuSceneRenderable.getIndex(), m_renderStateBuckets[t].get());
+			switch(t)
+			{
+			case RenderingTechnique::kGBuffer:
+				if(!m_gpuSceneRenderableAabbGBuffer.isValid())
+				{
+					m_gpuSceneRenderableAabbGBuffer.allocate();
+				}
+				m_gpuSceneRenderableAabbGBuffer.uploadToGpuScene(gpuVolume);
+				break;
+			case RenderingTechnique::kDepth:
+				if(!m_gpuSceneRenderableAabbDepth.isValid())
+				{
+					m_gpuSceneRenderableAabbDepth.allocate();
+				}
+				m_gpuSceneRenderableAabbDepth.uploadToGpuScene(gpuVolume);
+				break;
+			case RenderingTechnique::kForward:
+				if(!m_gpuSceneRenderableAabbForward.isValid())
+				{
+					m_gpuSceneRenderableAabbForward.allocate();
+				}
+				m_gpuSceneRenderableAabbForward.uploadToGpuScene(gpuVolume);
+				break;
+			default:
+				ANKI_ASSERT(0);
+			}
+		}
+		else if(!!(RenderingTechniqueBit(1 << t) & RenderingTechniqueBit::kAllRt))
+		{
+			continue;
+		}
+		else
+		{
+			switch(t)
+			{
+			case RenderingTechnique::kGBuffer:
+				m_gpuSceneRenderableAabbGBuffer.free();
+				break;
+			case RenderingTechnique::kDepth:
+				m_gpuSceneRenderableAabbDepth.free();
+				break;
+			case RenderingTechnique::kForward:
+				m_gpuSceneRenderableAabbForward.free();
+				break;
+			default:
+				ANKI_ASSERT(0);
+			}
+		}
 	}
 
 	m_resourceUpdated = false;
@@ -508,7 +530,7 @@ void ParticleEmitterComponent::setupRenderableQueueElements(RenderingTechnique t
 	el->m_program = prog.get();
 	el->m_worldTransformsOffset = 0;
 	el->m_uniformsOffset = m_gpuSceneUniforms.getOffset();
-	el->m_geometryOffset = m_gpuSceneIndexParticleEmitter.getOffsetInGpuScene();
+	el->m_geometryOffset = m_gpuSceneParticleEmitter.getGpuSceneOffset();
 	el->m_boneTransformsOffset = 0;
 	el->m_vertexCount = 6 * m_aliveParticleCount;
 	el->m_firstVertex = 0;

+ 6 - 3
AnKi/Scene/Components/ParticleEmitterComponent.h

@@ -8,6 +8,7 @@
 #include <AnKi/Scene/Components/SceneComponent.h>
 #include <AnKi/Scene/Spatial.h>
 #include <AnKi/Scene/RenderStateBucket.h>
+#include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Resource/ParticleEmitterResource.h>
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Util/WeakArray.h>
@@ -65,9 +66,11 @@ private:
 	GpuSceneBufferAllocation m_gpuSceneAlphas;
 	GpuSceneBufferAllocation m_gpuSceneScales;
 	GpuSceneBufferAllocation m_gpuSceneUniforms;
-	GpuSceneContiguousArrayIndex m_gpuSceneIndexParticleEmitter;
-	GpuSceneContiguousArrayIndex m_gpuSceneIndexRenderable;
-	Array<GpuSceneContiguousArrayIndex, U32(RenderingTechnique::kCount)> m_gpuSceneIndexAabbs;
+	GpuSceneArrays::ParticleEmitter::Allocation m_gpuSceneParticleEmitter;
+	GpuSceneArrays::Renderable::Allocation m_gpuSceneRenderable;
+	GpuSceneArrays::RenderableAabbGBuffer::Allocation m_gpuSceneRenderableAabbGBuffer;
+	GpuSceneArrays::RenderableAabbDepth::Allocation m_gpuSceneRenderableAabbDepth;
+	GpuSceneArrays::RenderableAabbForward::Allocation m_gpuSceneRenderableAabbForward;
 
 	Array<RenderStateBucketIndex, U32(RenderingTechnique::kCount)> m_renderStateBuckets;
 

+ 2 - 2
AnKi/Scene/Components/ReflectionProbeComponent.cpp

@@ -29,7 +29,7 @@ ReflectionProbeComponent::ReflectionProbeComponent(SceneNode* node)
 		m_frustums[i].update();
 	}
 
-	m_gpuSceneIndex = GpuSceneContiguousArrays::getSingleton().allocate(GpuSceneContiguousArrayType::kReflectionProbes);
+	m_gpuSceneProbe.allocate();
 }
 
 ReflectionProbeComponent::~ReflectionProbeComponent()
@@ -102,7 +102,7 @@ Error ReflectionProbeComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 		gpuProbe.m_aabbMin = aabbWorld.getMin().xyz();
 		gpuProbe.m_aabbMax = aabbWorld.getMax().xyz();
 		gpuProbe.m_uuid = getUuid();
-		GpuSceneMicroPatcher::getSingleton().newCopy(*info.m_framePool, m_gpuSceneIndex.getOffsetInGpuScene(), gpuProbe);
+		m_gpuSceneProbe.uploadToGpuScene(gpuProbe);
 	}
 
 	// Update spatial and frustums

+ 2 - 2
AnKi/Scene/Components/ReflectionProbeComponent.h

@@ -54,7 +54,7 @@ public:
 		el.m_aabbMax = m_halfSize + m_worldPos;
 		ANKI_ASSERT(el.m_textureBindlessIndex != kMaxU32);
 		el.m_textureBindlessIndex = m_reflectionTexBindlessIndex;
-		el.m_index = m_gpuSceneIndex.get();
+		el.m_index = m_gpuSceneProbe.getIndex();
 	}
 
 	ANKI_INTERNAL void setupReflectionProbeQueueElementForRefresh(ReflectionProbeQueueElementForRefresh& el) const
@@ -78,7 +78,7 @@ private:
 	Vec3 m_worldPos = Vec3(kMaxF32);
 	Vec3 m_halfSize = Vec3(1.0f);
 
-	GpuSceneContiguousArrayIndex m_gpuSceneIndex;
+	GpuSceneArrays::ReflectionProbe::Allocation m_gpuSceneProbe;
 
 	Spatial m_spatial;
 

+ 0 - 1
AnKi/Scene/Components/SceneComponent.h

@@ -6,7 +6,6 @@
 #pragma once
 
 #include <AnKi/Scene/Common.h>
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
 #include <AnKi/Util/Functions.h>
 #include <AnKi/Util/BitMask.h>
 

+ 0 - 171
AnKi/Scene/ContiguousArrayAllocator.cpp

@@ -1,171 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Scene/ContiguousArrayAllocator.h>
-#include <AnKi/Core/CVarSet.h>
-#include <AnKi/Gr/GrManager.h>
-
-namespace anki {
-
-static NumericCVar<U32> g_minGpuSceneTransformsCVar(CVarSubsystem::kScene, "MinGpuSceneTransforms", 2 * 10 * 1024, 8, 100 * 1024,
-													"The min number of transforms stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneMeshesCVar(CVarSubsystem::kScene, "MinGpuSceneMeshes", 8 * 1024, 8, 100 * 1024,
-												"The min number of meshes stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneParticleEmittersCVar(CVarSubsystem::kScene, "MinGpuSceneParticleEmitters", 1 * 1024, 8, 100 * 1024,
-														  "The min number of particle emitters stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneLightsCVar(CVarSubsystem::kScene, "MinGpuSceneLights", 2 * 1024, 8, 100 * 1024,
-												"The min number of lights stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneReflectionProbesCVar(CVarSubsystem::kScene, "MinGpuSceneReflectionProbes", 128, 8, 100 * 1024,
-														  "The min number of reflection probes stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneGlobalIlluminationProbesCVar(CVarSubsystem::kScene, "MinGpuSceneGlobalIlluminationProbes", 128, 8, 100 * 1024,
-																  "The min number of GI probes stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneDecalsCVar(CVarSubsystem::kScene, "MinGpuSceneDecals", 2 * 1024, 8, 100 * 1024,
-												"The min number of decals stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneFogDensityVolumesCVar(CVarSubsystem::kScene, "MinGpuSceneFogDensityVolumes", 512, 8, 100 * 1024,
-														   "The min number fog density volumes stored in the GPU scene");
-static NumericCVar<U32> g_minGpuSceneRenderablesCVar(CVarSubsystem::kScene, "MinGpuSceneRenderables", 10 * 1024, 8, 100 * 1024,
-													 "The min number of renderables stored in the GPU scene");
-
-void GpuSceneContiguousArrays::ContiguousArrayAllocator::destroy()
-{
-	for(U32 i = 0; i < kMaxFramesInFlight; ++i)
-	{
-		collectGarbage(i);
-	}
-}
-
-U32 GpuSceneContiguousArrays::ContiguousArrayAllocator::allocateObject()
-{
-	LockGuard lock(m_mtx);
-
-	if(!m_allocation.isValid())
-	{
-		// Initialize
-		const U32 alignment = GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment;
-		GpuSceneBuffer::getSingleton().allocate(m_objectSize * m_initialArraySize, alignment, m_allocation);
-		m_nextSlotIndex = 0;
-
-		m_freeSlotStack.resize(m_initialArraySize);
-		for(U32 i = 0; i < m_initialArraySize; ++i)
-		{
-			m_freeSlotStack[i] = i;
-		}
-	}
-	else if(m_nextSlotIndex == m_freeSlotStack.getSize())
-	{
-		// Grow
-		ANKI_ASSERT(!"TODO");
-	}
-
-	const U32 idx = m_freeSlotStack[m_nextSlotIndex];
-	++m_nextSlotIndex;
-
-	ANKI_ASSERT(idx < m_freeSlotStack.getSize());
-	return idx;
-}
-
-void GpuSceneContiguousArrays::ContiguousArrayAllocator::deferredFree(U32 crntFrameIdx, U32 index)
-{
-	LockGuard lock(m_mtx);
-
-	ANKI_ASSERT(index < m_freeSlotStack.getSize());
-	m_garbage[crntFrameIdx].emplaceBack(index);
-}
-
-void GpuSceneContiguousArrays::ContiguousArrayAllocator::collectGarbage(U32 newFrameIdx)
-{
-	LockGuard lock(m_mtx);
-
-	if(m_garbage[newFrameIdx].getSize() == 0) [[likely]]
-	{
-		return;
-	}
-
-	// Release deferred frees
-	for(U32 idx : m_garbage[newFrameIdx])
-	{
-		ANKI_ASSERT(m_nextSlotIndex > 0);
-		--m_nextSlotIndex;
-		m_freeSlotStack[m_nextSlotIndex] = idx;
-	}
-
-	m_garbage[newFrameIdx].destroy();
-
-	// Sort so we can keep memory close to the beginning of the array for better cache behaviour
-	std::sort(m_freeSlotStack.getBegin() + m_nextSlotIndex, m_freeSlotStack.getEnd());
-
-	// Adjust the stack size
-	const U32 allocatedSlots = m_nextSlotIndex;
-	if(U32(F32(allocatedSlots) * m_growRate) < m_freeSlotStack.getSize() && m_freeSlotStack.getSize() > m_initialArraySize)
-	{
-		// Shrink
-		ANKI_ASSERT(!"TODO");
-	}
-	else if(allocatedSlots == 0)
-	{
-		ANKI_ASSERT(m_nextSlotIndex == 0);
-		GpuSceneBuffer::getSingleton().deferredFree(m_allocation);
-		m_freeSlotStack.destroy();
-	}
-}
-
-GpuSceneContiguousArrays::GpuSceneContiguousArrays()
-{
-	constexpr F32 kGrowRate = 2.0;
-
-	const Array<U32, U32(GpuSceneContiguousArrayType::kCount)> minElementCount = {
-		g_minGpuSceneTransformsCVar.get(),       g_minGpuSceneMeshesCVar.get(),
-		g_minGpuSceneParticleEmittersCVar.get(), g_minGpuSceneLightsCVar.get(),
-		g_minGpuSceneReflectionProbesCVar.get(), g_minGpuSceneGlobalIlluminationProbesCVar.get(),
-		g_minGpuSceneDecalsCVar.get(),           g_minGpuSceneFogDensityVolumesCVar.get(),
-		g_minGpuSceneRenderablesCVar.get(),      g_minGpuSceneRenderablesCVar.get(),
-		g_minGpuSceneRenderablesCVar.get(),      g_minGpuSceneRenderablesCVar.get()};
-
-	for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
-	{
-		const U32 initialArraySize = minElementCount[type] / m_componentCount[type];
-		const U16 elementSize = m_componentSize[type] * m_componentCount[type];
-
-		m_allocs[type].init(initialArraySize, elementSize, kGrowRate);
-	}
-}
-
-GpuSceneContiguousArrays::~GpuSceneContiguousArrays()
-{
-	for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
-	{
-		m_allocs[type].destroy();
-	}
-}
-
-GpuSceneContiguousArrayIndex GpuSceneContiguousArrays::allocate(GpuSceneContiguousArrayType type)
-{
-	GpuSceneContiguousArrayIndex out;
-	out.m_index = m_allocs[type].allocateObject();
-	out.m_type = type;
-
-	return out;
-}
-
-void GpuSceneContiguousArrays::deferredFree(GpuSceneContiguousArrayIndex& idx)
-{
-	if(idx.isValid())
-	{
-		m_allocs[idx.m_type].deferredFree(m_frame, idx.m_index);
-		idx.invalidate();
-	}
-}
-
-void GpuSceneContiguousArrays::endFrame()
-{
-	m_frame = (m_frame + 1) % kMaxFramesInFlight;
-
-	for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
-	{
-		m_allocs[type].collectGarbage(m_frame);
-	}
-}
-
-} // end namespace anki

+ 0 - 230
AnKi/Scene/ContiguousArrayAllocator.h

@@ -1,230 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Scene/Common.h>
-#include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
-
-namespace anki {
-
-/// @addtogroup scene
-/// @{
-
-/// Some of the GPU scene structures are stored in structured buffers
-enum class GpuSceneContiguousArrayType : U8
-{
-	kTransformPairs,
-	kMeshLods,
-	kParticleEmitters,
-	kLights,
-	kReflectionProbes,
-	kGlobalIlluminationProbes,
-	kDecals,
-	kFogDensityVolumes,
-	kRenderables,
-
-	kRenderableBoundingVolumesGBuffer,
-	kRenderableBoundingVolumesForward,
-	kRenderableBoundingVolumesDepth,
-
-	kCount,
-	kFirst = 0
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(GpuSceneContiguousArrayType)
-
-class GpuSceneContiguousArrayIndex
-{
-	friend class GpuSceneContiguousArrays;
-
-public:
-	GpuSceneContiguousArrayIndex() = default;
-
-	GpuSceneContiguousArrayIndex(const GpuSceneContiguousArrayIndex& b) = delete;
-
-	GpuSceneContiguousArrayIndex(GpuSceneContiguousArrayIndex&& b)
-	{
-		*this = std::move(b);
-	}
-
-	~GpuSceneContiguousArrayIndex();
-
-	GpuSceneContiguousArrayIndex& operator=(const GpuSceneContiguousArrayIndex&) = delete;
-
-	GpuSceneContiguousArrayIndex& operator=(GpuSceneContiguousArrayIndex&& b)
-	{
-		ANKI_ASSERT(!isValid());
-		m_index = b.m_index;
-		m_type = b.m_type;
-		b.invalidate();
-		return *this;
-	}
-
-	U32 get() const
-	{
-		ANKI_ASSERT(m_index != kMaxU32);
-		return m_index;
-	}
-
-	Bool isValid() const
-	{
-		return m_index != kMaxU32;
-	}
-
-	U32 getOffsetInGpuScene() const;
-
-private:
-	U32 m_index = kMaxU32;
-	GpuSceneContiguousArrayType m_type = GpuSceneContiguousArrayType::kCount;
-
-	void invalidate()
-	{
-		m_index = kMaxU32;
-		m_type = GpuSceneContiguousArrayType::kCount;
-	}
-};
-
-/// Contains a number of contiguous array allocators for various GPU scene contiguous objects.
-class GpuSceneContiguousArrays : public MakeSingleton<GpuSceneContiguousArrays>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	/// @note Thread-safe against allocate(), deferredFree() and endFrame()
-	GpuSceneContiguousArrayIndex allocate(GpuSceneContiguousArrayType type);
-
-	/// @note It's not thread-safe
-	PtrSize getArrayBaseOffset(GpuSceneContiguousArrayType type) const
-	{
-		return m_allocs[type].getArrayBase();
-	}
-
-	/// @note It's not thread-safe
-	U32 getElementCount(GpuSceneContiguousArrayType type) const
-	{
-		return m_allocs[type].getElementCount();
-	}
-
-	/// @note It's not thread-safe
-	U32 getElementOffsetInGpuScene(const GpuSceneContiguousArrayIndex& idx) const
-	{
-		ANKI_ASSERT(idx.isValid());
-		return U32(getArrayBaseOffset(idx.m_type) + m_componentCount[idx.m_type] * m_componentSize[idx.m_type] * idx.m_index);
-	}
-
-	constexpr static U32 getElementSize(GpuSceneContiguousArrayType type)
-	{
-		return m_componentSize[type] * m_componentCount[type];
-	}
-
-	/// @note Thread-safe against allocate(), deferredFree() and endFrame()
-	void deferredFree(GpuSceneContiguousArrayIndex& idx);
-
-	/// @note Thread-safe against allocate(), deferredFree() and endFrame()
-	void endFrame();
-
-private:
-	/// GPU scene allocator that emulates a contiguous array of elements. It's an array of objects of the same size.
-	/// This array is a contiguous piece of memory. This helps same, in function, objects be close together.
-	class ContiguousArrayAllocator
-	{
-		friend class GpuSceneContiguousArrays;
-
-	public:
-		~ContiguousArrayAllocator()
-		{
-			ANKI_ASSERT(m_nextSlotIndex == 0 && "Forgot to deallocate");
-			for([[maybe_unused]] const SceneDynamicArray<U32>& arr : m_garbage)
-			{
-				ANKI_ASSERT(arr.getSize() == 0);
-			}
-		}
-
-		void init(U32 initialArraySize, U16 objectSize, F32 arrayGrowRate)
-		{
-			ANKI_ASSERT(initialArraySize > 0);
-			ANKI_ASSERT(objectSize > 0 && objectSize <= 256); // 256 is arbitary
-			ANKI_ASSERT(arrayGrowRate > 1.0);
-			m_objectSize = objectSize;
-			m_growRate = arrayGrowRate;
-			m_initialArraySize = initialArraySize;
-		}
-
-		void destroy();
-
-		/// Allocate a new object and return its index in the array.
-		/// @note It's thread-safe against itself, deferredFree and endFrame.
-		U32 allocateObject();
-
-		/// Safely free an index allocated by allocateObject.
-		/// @note It's thread-safe against itself, allocateObject and endFrame.
-		void deferredFree(U32 crntFrameIdx, U32 index);
-
-		/// Call this every frame.
-		/// @note It's thread-safe against itself, deferredFree and allocateObject.
-		void collectGarbage(U32 newFrameIdx);
-
-		PtrSize getArrayBase() const
-		{
-			return m_allocation.getOffset();
-		}
-
-		U32 getElementCount() const
-		{
-			return m_nextSlotIndex;
-		}
-
-	private:
-		GpuSceneBufferAllocation m_allocation;
-
-		SceneDynamicArray<U32> m_freeSlotStack;
-
-		Array<SceneDynamicArray<U32>, kMaxFramesInFlight> m_garbage;
-
-		mutable SpinLock m_mtx;
-
-		F32 m_growRate = 2.0;
-		U32 m_initialArraySize = 0;
-		U16 m_objectSize = 0;
-
-		U32 m_nextSlotIndex = 0;
-	};
-
-	Array<ContiguousArrayAllocator, U32(GpuSceneContiguousArrayType::kCount)> m_allocs;
-
-	U8 m_frame = 0;
-
-	static constexpr Array<U8, U32(GpuSceneContiguousArrayType::kCount)> m_componentCount = {2, kMaxLodCount, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
-	static constexpr Array<U8, U32(GpuSceneContiguousArrayType::kCount)> m_componentSize = {sizeof(Mat3x4),
-																							sizeof(GpuSceneMeshLod),
-																							sizeof(GpuSceneParticleEmitter),
-																							sizeof(GpuSceneLight),
-																							sizeof(GpuSceneReflectionProbe),
-																							sizeof(GpuSceneGlobalIlluminationProbe),
-																							sizeof(GpuSceneDecal),
-																							sizeof(GpuSceneFogDensityVolume),
-																							sizeof(GpuSceneRenderable),
-																							sizeof(GpuSceneRenderableAabb),
-																							sizeof(GpuSceneRenderableAabb),
-																							sizeof(GpuSceneRenderableAabb)};
-
-	GpuSceneContiguousArrays();
-
-	~GpuSceneContiguousArrays();
-};
-
-inline GpuSceneContiguousArrayIndex::~GpuSceneContiguousArrayIndex()
-{
-	GpuSceneContiguousArrays::getSingleton().deferredFree(*this);
-}
-
-inline U32 GpuSceneContiguousArrayIndex::getOffsetInGpuScene() const
-{
-	return GpuSceneContiguousArrays::getSingleton().getElementOffsetInGpuScene(*this);
-}
-/// @}
-
-} // end namespace anki

+ 191 - 0
AnKi/Scene/GpuSceneArray.h

@@ -0,0 +1,191 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Scene/Common.h>
+#include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
+#include <AnKi/Scene/SceneGraph.h>
+#include <AnKi/Util/Thread.h>
+
+namespace anki {
+
+// Forward
+template<typename TGpuSceneObject, U32 kId>
+class GpuSceneArray;
+
+/// @addtogroup scene
+/// @{
+
+/// @memberof GpuSceneArray
+template<typename TGpuSceneObject, U32 kId>
+class GpuSceneArrayAllocation
+{
+	friend class GpuSceneArray<TGpuSceneObject, kId>;
+
+public:
+	GpuSceneArrayAllocation() = default;
+
+	GpuSceneArrayAllocation(const GpuSceneArrayAllocation& b) = delete;
+
+	GpuSceneArrayAllocation(GpuSceneArrayAllocation&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GpuSceneArrayAllocation()
+	{
+		free();
+	}
+
+	GpuSceneArrayAllocation& operator=(const GpuSceneArrayAllocation&) = delete;
+
+	GpuSceneArrayAllocation& operator=(GpuSceneArrayAllocation&& b)
+	{
+		free();
+		m_index = b.m_index;
+		b.invalidate();
+		return *this;
+	}
+
+	U32 getIndex() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_index;
+	}
+
+	Bool isValid() const
+	{
+		return m_index != kMaxU32;
+	}
+
+	/// Offset in the GPU scene.
+	U32 getGpuSceneOffset() const;
+
+	void uploadToGpuScene(const TGpuSceneObject& data) const
+	{
+		GpuSceneMicroPatcher::getSingleton().newCopy(SceneGraph::getSingleton().getFrameMemoryPool(), getGpuSceneOffset(), data);
+	}
+
+	/// Allocate an element into the appropriate array.
+	void allocate();
+
+	/// Free the allocation.
+	void free();
+
+private:
+	U32 m_index = kMaxU32;
+
+	void invalidate()
+	{
+		m_index = kMaxU32;
+	}
+};
+
+/// Contains a number an array that hold GPU scene objects of a specific type.
+template<typename TGpuSceneObject, U32 kId>
+class GpuSceneArray : public MakeSingleton<GpuSceneArray<TGpuSceneObject, kId>>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+	friend class GpuSceneArrayAllocation<TGpuSceneObject, kId>;
+
+public:
+	using Allocation = GpuSceneArrayAllocation<TGpuSceneObject, kId>;
+
+	/// @note Thread-safe
+	PtrSize getGpuSceneOffsetOfArrayBase() const
+	{
+		return m_gpuSceneAllocation.getOffset();
+	}
+
+	/// @note Thread-safe
+	U32 getElementCount() const
+	{
+		LockGuard lock(m_mtx);
+		return (m_inuUseIndicesCount) ? m_maxInUseIndex + 1 : 0;
+	}
+
+	constexpr static U32 getElementSize()
+	{
+		return sizeof(TGpuSceneObject);
+	}
+
+	/// Some bookeeping. Needs to be called once per frame.
+	/// @note Thread-safe
+	void flush()
+	{
+		flushInternal(true);
+	}
+
+private:
+	using SubMask = BitSet<64, U64>;
+
+	GpuSceneBufferAllocation m_gpuSceneAllocation;
+
+	SceneDynamicArray<SubMask> m_inUseIndicesMask;
+
+	U32 m_inuUseIndicesCount = 0; ///< Doesn't count null elements.
+	U32 m_maxInUseIndex = 0; ///< Counts null elements.
+
+	SceneDynamicArray<U32> m_freedAllocations;
+
+	mutable SpinLock m_mtx;
+
+	GpuSceneArray(U32 maxArraySize);
+
+	~GpuSceneArray();
+
+	void validate() const;
+
+	U32 getGpuSceneOffset(const Allocation& idx) const
+	{
+		ANKI_ASSERT(idx.isValid());
+		return U32(getGpuSceneOffsetOfArrayBase() + sizeof(TGpuSceneObject) * idx.m_index);
+	}
+
+	/// @note Thread-safe
+	Allocation allocate();
+
+	/// The free will not resize the array if an element is somewhere in the middle. Resizing requires moves and will also invalidate pointers.
+	/// Instead, the freed elements will stay as a dangling stale data inside their array. Nevertheless, the class will go and nullify those elements
+	/// so they won't take part in visibility tests.
+	/// @note Thread-safe
+	void free(Allocation& alloc);
+
+	void flushInternal(Bool nullifyElements);
+};
+
+template<typename TGpuSceneObject, U32 kId>
+inline void GpuSceneArrayAllocation<TGpuSceneObject, kId>::free()
+{
+	GpuSceneArray<TGpuSceneObject, kId>::getSingleton().free(*this);
+}
+
+template<typename TGpuSceneObject, U32 kId>
+inline void GpuSceneArrayAllocation<TGpuSceneObject, kId>::allocate()
+{
+	auto newAlloc = GpuSceneArray<TGpuSceneObject, kId>::getSingleton().allocate();
+	*this = std::move(newAlloc);
+}
+
+template<typename TGpuSceneObject, U32 kId>
+inline U32 GpuSceneArrayAllocation<TGpuSceneObject, kId>::getGpuSceneOffset() const
+{
+	return GpuSceneArray<TGpuSceneObject, kId>::getSingleton().getGpuSceneOffset(*this);
+}
+
+class GpuSceneArrays
+{
+public:
+#define ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName) using arrayName = GpuSceneArray<gpuSceneType, id>;
+#include <AnKi/Scene/GpuSceneArrays.def.h>
+};
+/// @}
+
+} // end namespace anki
+
+#include <AnKi/Scene/GpuSceneArray.inl.h>

+ 156 - 0
AnKi/Scene/GpuSceneArray.inl.h

@@ -0,0 +1,156 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Scene/GpuSceneArray.h>
+#include <AnKi/Scene/SceneGraph.h>
+#include <AnKi/Gr/GrManager.h>
+
+namespace anki {
+
+template<typename TGpuSceneObject, U32 kId>
+GpuSceneArray<TGpuSceneObject, kId>::GpuSceneArray(U32 maxArraySize)
+{
+	maxArraySize = getAlignedRoundUp(sizeof(SubMask), maxArraySize);
+	const U32 alignment = GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment;
+	GpuSceneBuffer::getSingleton().allocate(sizeof(TGpuSceneObject) * maxArraySize, alignment, m_gpuSceneAllocation);
+
+	m_inUseIndicesMask.resize(maxArraySize / sizeof(SubMask), false);
+	ANKI_ASSERT(m_inuUseIndicesCount == 0);
+	m_maxInUseIndex = 0;
+}
+
+template<typename TGpuSceneObject, U32 kId>
+GpuSceneArray<TGpuSceneObject, kId>::~GpuSceneArray()
+{
+	flushInternal(false);
+	validate();
+	ANKI_ASSERT(m_inuUseIndicesCount == 0 && "Forgot to free");
+}
+
+template<typename TGpuSceneObject, U32 kId>
+GpuSceneArrayAllocation<TGpuSceneObject, kId> GpuSceneArray<TGpuSceneObject, kId>::allocate()
+{
+	LockGuard lock(m_mtx);
+
+	U32 idx = kMaxU32;
+	if(m_freedAllocations.getSize())
+	{
+		// There are freed indices this frame, use one
+
+		idx = m_freedAllocations[0];
+		m_freedAllocations.erase(m_freedAllocations.getBegin());
+	}
+	else
+	{
+		// No freed indices this frame, get a new one
+
+		for(U maskGroup = 0; maskGroup < m_inUseIndicesMask.getSize(); ++maskGroup)
+		{
+			SubMask submask = m_inUseIndicesMask[maskGroup];
+			submask = ~submask;
+			const U32 bit = submask.getLeastSignificantBit();
+			if(bit != kMaxU32)
+			{
+				// Found an index
+				idx = maskGroup * 64 + bit;
+				break;
+			}
+		}
+	}
+
+	ANKI_ASSERT(idx < m_inUseIndicesMask.getSize() * 64);
+
+	ANKI_ASSERT(m_inUseIndicesMask[idx / 64].get(idx % 64) == false);
+	m_inUseIndicesMask[idx / 64].set(idx % 64);
+
+	m_maxInUseIndex = max(m_maxInUseIndex, idx);
+	++m_inuUseIndicesCount;
+
+	Allocation out;
+	out.m_index = idx;
+	return out;
+}
+
+template<typename TGpuSceneObject, U32 kId>
+void GpuSceneArray<TGpuSceneObject, kId>::free(Allocation& alloc)
+{
+	if(!alloc.isValid()) [[unlikely]]
+	{
+		return;
+	}
+
+	const U32 idx = alloc.m_index;
+	alloc.invalidate();
+
+	LockGuard lock(m_mtx);
+
+	m_freedAllocations.emplaceBack(idx);
+	ANKI_ASSERT(m_inUseIndicesMask[idx / 64].get(idx % 64) == true);
+	m_inUseIndicesMask[idx / 64].unset(idx % 64);
+
+	ANKI_ASSERT(m_inuUseIndicesCount > 0);
+	--m_inuUseIndicesCount;
+
+	// Sort because allocations later on should preferably grab the lowest index possible
+	std::sort(m_freedAllocations.getBegin(), m_freedAllocations.getEnd());
+}
+
+template<typename TGpuSceneObject, U32 kId>
+void GpuSceneArray<TGpuSceneObject, kId>::flushInternal(Bool nullifyElements)
+{
+	LockGuard lock(m_mtx);
+
+	if(m_freedAllocations.getSize())
+	{
+		// Nullify the deleted elements
+		if(nullifyElements)
+		{
+			TGpuSceneObject nullObj = {};
+			for(U32 idx : m_freedAllocations)
+			{
+				const PtrSize offset = idx * sizeof(TGpuSceneObject) + m_gpuSceneAllocation.getOffset();
+				GpuSceneMicroPatcher::getSingleton().newCopy(SceneGraph::getSingleton().getFrameMemoryPool(), offset, nullObj);
+			}
+		}
+
+		// Update the the last index
+		U32 maskGroup = m_maxInUseIndex / 64;
+		m_maxInUseIndex = 0;
+		while(maskGroup--)
+		{
+			const U32 bit = m_inUseIndicesMask[maskGroup].getMostSignificantBit();
+			if(bit != kMaxU32)
+			{
+				m_maxInUseIndex = maskGroup * 64 + bit;
+				break;
+			}
+		}
+
+		m_freedAllocations.destroy();
+	}
+
+	validate();
+}
+
+template<typename TGpuSceneObject, U32 kId>
+void GpuSceneArray<TGpuSceneObject, kId>::validate() const
+{
+#if ANKI_ASSERTIONS_ENABLED
+	U32 count = 0;
+	U32 maxIdx = 0;
+	U32 maskGroupCount = 0;
+	for(const SubMask& mask : m_inUseIndicesMask)
+	{
+		count += mask.getEnabledBitCount();
+		maxIdx = max(maxIdx, (mask.getMostSignificantBit() != kMaxU32) ? (mask.getMostSignificantBit() + maskGroupCount * 64) : 0);
+		++maskGroupCount;
+	}
+
+	ANKI_ASSERT(count == m_inuUseIndicesCount);
+	ANKI_ASSERT(maxIdx == m_maxInUseIndex);
+#endif
+}
+
+} // end namespace anki

+ 44 - 0
AnKi/Scene/GpuSceneArrays.def.h

@@ -0,0 +1,44 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// It's ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName)
+
+#if !defined(ANKI_CAT_SEPARATOR)
+#	define ANKI_CAT_SEPARATOR
+#endif
+
+// Trick because macros are alergic to commas inside templates
+#define ANKI_TRF_ARR Array<Mat3x4, 2>
+#define ANKI_MESH_ARR Array<GpuSceneMeshLod, kMaxLodCount>
+
+ANKI_CAT_TYPE(Transform, ANKI_TRF_ARR, 0, g_minGpuSceneTransformsCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(MeshLod, ANKI_MESH_ARR, 0, g_minGpuSceneMeshesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(ParticleEmitter, GpuSceneParticleEmitter, 0, g_minGpuSceneParticleEmittersCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(Light, GpuSceneLight, 0, g_minGpuSceneLightsCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(ReflectionProbe, GpuSceneReflectionProbe, 0, g_minGpuSceneReflectionProbesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(GlobalIlluminationProbe, GpuSceneGlobalIlluminationProbe, 0, g_minGpuSceneGlobalIlluminationProbesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(Decal, GpuSceneDecal, 0, g_minGpuSceneDecalsCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(FogDensityVolume, GpuSceneFogDensityVolume, 0, g_minGpuSceneFogDensityVolumesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(Renderable, GpuSceneRenderable, 0, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(RenderableAabbGBuffer, GpuSceneRenderableAabb, 0, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(RenderableAabbForward, GpuSceneRenderableAabb, 1, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_SEPARATOR
+ANKI_CAT_TYPE(RenderableAabbDepth, GpuSceneRenderableAabb, 2, g_minGpuSceneRenderablesCVar)
+
+#undef ANKI_TRF_ARR
+#undef ANKI_MESH_ARR
+
+#undef ANKI_CAT_TYPE
+#undef ANKI_CAT_SEPARATOR

+ 1 - 1
AnKi/Scene/Octree.cpp

@@ -140,7 +140,7 @@ void Octree::placeRecursive(const Aabb& volume, OctreePlaceable* placeable, Leaf
 		// Need to stop and bin the placeable to the leaf
 
 		// Checks
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		for(const LeafNode& node : placeable->m_leafs)
 		{
 			ANKI_ASSERT(node.m_leaf != parent && "Already binned. That's wrong");

+ 3 - 3
AnKi/Scene/Octree.h

@@ -102,7 +102,7 @@ private:
 	public:
 		OctreePlaceable* m_placeable = nullptr;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		~PlaceableNode()
 		{
 			m_placeable = nullptr;
@@ -120,7 +120,7 @@ private:
 		Vec3 m_aabbMax;
 		Array<Leaf*, 8> m_children = {};
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		~Leaf()
 		{
 			ANKI_ASSERT(m_placeables.isEmpty());
@@ -142,7 +142,7 @@ private:
 	public:
 		Leaf* m_leaf = nullptr;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		~LeafNode()
 		{
 			m_leaf = nullptr;

+ 29 - 4
AnKi/Scene/SceneGraph.cpp

@@ -29,6 +29,26 @@ NumericCVar<F32> g_probeEffectiveDistanceCVar(CVarSubsystem::kScene, "ProbeEffec
 NumericCVar<F32> g_probeShadowEffectiveDistanceCVar(CVarSubsystem::kScene, "ProbeShadowEffectiveDistance", 32.0f, 1.0f, kMaxF32,
 													"How far to render shadows for the various probes");
 
+// Gpu scene arrays
+static NumericCVar<U32> g_minGpuSceneTransformsCVar(CVarSubsystem::kScene, "MinGpuSceneTransforms", 2 * 10 * 1024, 8, 100 * 1024,
+													"The min number of transforms stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneMeshesCVar(CVarSubsystem::kScene, "MinGpuSceneMeshes", 8 * 1024, 8, 100 * 1024,
+												"The min number of meshes stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneParticleEmittersCVar(CVarSubsystem::kScene, "MinGpuSceneParticleEmitters", 1 * 1024, 8, 100 * 1024,
+														  "The min number of particle emitters stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneLightsCVar(CVarSubsystem::kScene, "MinGpuSceneLights", 2 * 1024, 8, 100 * 1024,
+												"The min number of lights stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneReflectionProbesCVar(CVarSubsystem::kScene, "MinGpuSceneReflectionProbes", 128, 8, 100 * 1024,
+														  "The min number of reflection probes stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneGlobalIlluminationProbesCVar(CVarSubsystem::kScene, "MinGpuSceneGlobalIlluminationProbes", 128, 8, 100 * 1024,
+																  "The min number of GI probes stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneDecalsCVar(CVarSubsystem::kScene, "MinGpuSceneDecals", 2 * 1024, 8, 100 * 1024,
+												"The min number of decals stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneFogDensityVolumesCVar(CVarSubsystem::kScene, "MinGpuSceneFogDensityVolumes", 512, 8, 100 * 1024,
+														   "The min number fog density volumes stored in the GPU scene");
+static NumericCVar<U32> g_minGpuSceneRenderablesCVar(CVarSubsystem::kScene, "MinGpuSceneRenderables", 10 * 1024, 8, 100 * 1024,
+													 "The min number of renderables stored in the GPU scene");
+
 constexpr U32 kUpdateNodeBatchSize = 10;
 
 class SceneGraph::UpdateSceneNodesCtx
@@ -61,7 +81,9 @@ SceneGraph::~SceneGraph()
 		deleteInstance(SceneMemoryPool::getSingleton(), m_octree);
 	}
 
-	GpuSceneContiguousArrays::freeSingleton();
+#define ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName) GpuSceneArrays::arrayName::freeSingleton();
+#include <AnKi/Scene/GpuSceneArrays.def.h>
+
 	RenderStateBucketContainer::freeSingleton();
 }
 
@@ -80,7 +102,9 @@ Error SceneGraph::init(AllocAlignedCallback allocCallback, void* allocCallbackDa
 	camc->setPerspective(0.1f, 1000.0f, toRad(60.0f), (1080.0f / 1920.0f) * toRad(60.0f));
 	m_mainCam = m_defaultMainCam;
 
-	GpuSceneContiguousArrays::allocateSingleton();
+#define ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName) GpuSceneArrays::arrayName::allocateSingleton(cvarName.get());
+#include <AnKi/Scene/GpuSceneArrays.def.h>
+
 	RenderStateBucketContainer::allocateSingleton();
 
 	return Error::kNone;
@@ -175,8 +199,6 @@ Error SceneGraph::update(Second prevUpdateTime, Second crntTime)
 	ANKI_ASSERT(m_mainCam);
 	ANKI_TRACE_SCOPED_EVENT(SceneUpdate);
 
-	GpuSceneContiguousArrays::getSingleton().endFrame();
-
 	const Second startUpdateTime = HighRezTimer::getCurrentTime();
 
 	// Reset the framepool
@@ -228,6 +250,9 @@ Error SceneGraph::update(Second prevUpdateTime, Second crntTime)
 		CoreThreadHive::getSingleton().waitAllTasks();
 	}
 
+#define ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName) GpuSceneArrays::arrayName::getSingleton().flush();
+#include <AnKi/Scene/GpuSceneArrays.def.h>
+
 	g_sceneUpdateTime.set((HighRezTimer::getCurrentTime() - startUpdateTime) * 1000.0);
 	return Error::kNone;
 }

+ 0 - 1
AnKi/Scene/SceneGraph.h

@@ -33,7 +33,6 @@ class SceneGraph : public MakeSingleton<SceneGraph>
 	friend class SceneNode;
 	friend class UpdateSceneNodesTask;
 	friend class Event;
-	friend class GpuSceneContiguousArrays;
 
 public:
 	Error init(AllocAlignedCallback allocCallback, void* allocCallbackData);

+ 0 - 3
AnKi/Scene/SceneNode.h

@@ -14,9 +14,6 @@
 
 namespace anki {
 
-// Forward
-class SceneGraphExternalSubsystems;
-
 /// @addtogroup scene
 /// @{
 

+ 1 - 1
AnKi/ShaderCompiler/ShaderProgramReflection.cpp

@@ -569,7 +569,7 @@ Error SpirvReflector::blockReflection(const spirv_cross::Resource& res, [[maybe_
 		// Store the block
 		blocks.emplaceBack(std::move(newBlock));
 	}
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	else
 	{
 		DynamicArray<Var> vars;

+ 6 - 3
AnKi/Shaders/GpuVisibility.ankiprog

@@ -42,7 +42,10 @@
 [numthreads(64, 1, 1)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID)
 {
 	const U32 aabbIdx = svDispatchThreadId.x;
-	if(aabbIdx >= g_unis.m_aabbCount)
+	U32 aabbCount;
+	U32 unused;
+	g_aabbs.GetDimensions(aabbCount, unused);
+	if(aabbIdx >= aabbCount)
 	{
 		return;
 	}
@@ -58,7 +61,7 @@
 
 	// Frustum test
 	//
-	if(!frustumTest(g_unis.m_clipPlanes, aabb.m_sphereCenter, -aabb.m_negativeSphereRadius))
+	if(!frustumTest(g_unis.m_clipPlanes, aabb.m_sphereCenter, aabb.m_sphereRadius))
 	{
 		return;
 	}
@@ -134,7 +137,7 @@
 
 	// Compute the LOD
 	//
-	const F32 distFromLodPoint = length(aabb.m_sphereCenter - g_unis.m_lodReferencePoint) + aabb.m_negativeSphereRadius;
+	const F32 distFromLodPoint = length(aabb.m_sphereCenter - g_unis.m_lodReferencePoint) - aabb.m_sphereRadius;
 
 	U32 lod;
 	if(distFromLodPoint < g_unis.m_maxLodDistances[0])

+ 1 - 1
AnKi/Shaders/GpuVisibilityNonRenderables.ankiprog

@@ -50,7 +50,7 @@ Vec4 getSphere(GpuSceneLight l)
 
 Vec4 getSphere(GpuSceneDecal l)
 {
-	return l.m_boundingSphere;
+	return Vec4(l.m_sphereCenter, l.m_sphereRadius);
 }
 
 Vec4 getSphere(GpuSceneFogDensityVolume l)

+ 4 - 0
AnKi/Shaders/Include/Common.h

@@ -22,6 +22,8 @@
 
 #	define ANKI_ARRAY(type, size, name) Array<type, U32(size)> name
 
+#	define ANKI_CPP_CODE(...) __VA_ARGS__
+
 ANKI_BEGIN_NAMESPACE
 using Address = U64;
 using ScalarVec4 = Array<F32, 4>;
@@ -50,6 +52,8 @@ ANKI_END_NAMESPACE
 
 #	define ANKI_ARRAY(type, size, name) type name[(U32)size]
 
+#	define ANKI_CPP_CODE(...)
+
 #	define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enum_)
 
 #	define constexpr static const

+ 2 - 2
AnKi/Shaders/Include/GpuSceneFunctions.h

@@ -36,9 +36,9 @@ inline GpuSceneRenderableAabb initGpuSceneRenderableAabb(Vec3 aabbMin, Vec3 aabb
 	gpuVolume.m_sphereCenter = (aabbMin + aabbMax) * 0.5f;
 	gpuVolume.m_aabbExtend = aabbMax - gpuVolume.m_sphereCenter;
 #if defined(__cplusplus)
-	gpuVolume.m_negativeSphereRadius = -gpuVolume.m_aabbExtend.getLength();
+	gpuVolume.m_sphereRadius = gpuVolume.m_aabbExtend.getLength();
 #else
-	gpuVolume.m_negativeSphereRadius = -length(gpuVolume.m_aabbExtend);
+	gpuVolume.m_sphereRadius = length(gpuVolume.m_aabbExtend);
 #endif
 
 	ANKI_ASSERT(renderableIndex <= (1u << 20u) - 1u);

+ 24 - 18
AnKi/Shaders/Include/GpuSceneTypes.h

@@ -3,12 +3,19 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+// This file contains the GPU scene data types.
+// These types have in-place initialization for some members. Members that are used in visibility testing. These default values aim to essentially
+// make these objects not visible.
+
 #pragma once
 
 #include <AnKi/Shaders/Include/MeshTypes.h>
 
 ANKI_BEGIN_NAMESPACE
 
+/// Some far distance that will make objects not visible. Don't use kMaxF32 because this value will be used in math ops and it might overflow.
+constexpr F32 kSomeFarDistance = 100000.0f;
+
 /// @note All offsets in bytes
 struct GpuSceneRenderable
 {
@@ -24,12 +31,11 @@ typedef UVec4 GpuSceneRenderablePacked;
 /// Used in visibility testing.
 struct GpuSceneRenderableAabb
 {
-	Vec3 m_sphereCenter;
-	F32 m_negativeSphereRadius;
+	Vec3 m_sphereCenter ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
+	F32 m_sphereRadius ANKI_CPP_CODE(= 0.0f);
 
-	Vec3 m_aabbExtend;
-	/// High 20bits point to a GpuSceneRenderable. Rest 12bits are the render state bucket idx
-	U32 m_renderableIndexAndRenderStateBucket;
+	Vec3 m_aabbExtend ANKI_CPP_CODE(= Vec3(0.0f));
+	U32 m_renderableIndexAndRenderStateBucket; ///< High 20bits point to a GpuSceneRenderable. Rest 12bits are the render state bucket idx.
 };
 static_assert(sizeof(GpuSceneRenderableAabb) == sizeof(Vec4) * 2);
 
@@ -55,8 +61,8 @@ static_assert(sizeof(GpuSceneParticleEmitter) == sizeof(Vec4) * 2);
 /// Point or spot light.
 struct GpuSceneLight
 {
-	Vec3 m_position; ///< Position in world space.
-	RF32 m_radius; ///< Radius.
+	Vec3 m_position ANKI_CPP_CODE(= Vec3(kSomeFarDistance)); ///< Position in world space.
+	RF32 m_radius ANKI_CPP_CODE(= 0.0f); ///< Radius.
 
 	RVec3 m_diffuseColor;
 	RF32 m_squareRadiusOverOne; ///< 1/(radius^2).
@@ -78,10 +84,10 @@ struct GpuSceneReflectionProbe
 	Vec3 m_position; ///< Position of the probe in world space.
 	U32 m_cubeTexture; ///< Bindless index of the reflection texture.
 
-	Vec3 m_aabbMin;
+	Vec3 m_aabbMin ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
 	U32 m_uuid;
 
-	Vec3 m_aabbMax;
+	Vec3 m_aabbMax ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
 	F32 m_padding1;
 };
 constexpr U32 kSizeof_GpuSceneReflectionProbe = 3u * sizeof(Vec4);
@@ -90,16 +96,15 @@ static_assert(sizeof(GpuSceneReflectionProbe) == kSizeof_GpuSceneReflectionProbe
 /// Global illumination probe
 struct GpuSceneGlobalIlluminationProbe
 {
-	Vec3 m_aabbMin;
+	Vec3 m_aabbMin ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
 	U32 m_uuid;
 
-	Vec3 m_aabbMax;
+	Vec3 m_aabbMax ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
 	F32 m_padding1;
 
 	U32 m_volumeTexture; ///< Bindless index of the irradiance volume texture.
 	F32 m_halfTexelSizeU; ///< (1.0 / textureSize(texArr[textureIndex]).x) / 2.0
-	/// Used to calculate a factor that is zero when fragPos is close to AABB bounds and 1.0 at fadeDistance and less.
-	RF32 m_fadeDistance;
+	RF32 m_fadeDistance; ///< Used to calculate a factor that is zero when fragPos is close to AABB bounds and 1.0 at fadeDistance and less.
 	F32 m_padding2;
 };
 constexpr U32 kSizeof_GpuSceneGlobalIlluminationProbe = 3u * sizeof(Vec4);
@@ -117,10 +122,11 @@ struct GpuSceneDecal
 
 	Mat4 m_invertedTransform;
 
-	Vec3 m_obbExtend;
+	Vec3 m_obbExtend ANKI_CPP_CODE(= Vec3(0.0f));
 	F32 m_padding0;
 
-	Vec4 m_boundingSphere;
+	Vec3 m_sphereCenter ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
+	F32 m_sphereRadius ANKI_CPP_CODE(= 0.0f);
 };
 constexpr U32 kSizeof_GpuSceneDecal = 3u * sizeof(Vec4) + 2u * sizeof(Mat4);
 static_assert(sizeof(GpuSceneDecal) == kSizeof_GpuSceneDecal);
@@ -128,10 +134,10 @@ static_assert(sizeof(GpuSceneDecal) == kSizeof_GpuSceneDecal);
 /// Fog density volume.
 struct GpuSceneFogDensityVolume
 {
-	Vec3 m_aabbMinOrSphereCenter;
-	U32 m_isBox;
+	Vec3 m_aabbMinOrSphereCenter ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
+	U32 m_isBox ANKI_CPP_CODE(= 1);
 
-	Vec3 m_aabbMaxOrSphereRadius;
+	Vec3 m_aabbMaxOrSphereRadius ANKI_CPP_CODE(= Vec3(kSomeFarDistance));
 	RF32 m_density;
 };
 constexpr U32 kSizeof_GpuSceneFogDensityVolume = 2u * sizeof(Vec4);

+ 0 - 5
AnKi/Shaders/Include/GpuVisibilityTypes.h

@@ -13,11 +13,6 @@ struct GpuVisibilityUniforms
 {
 	Vec4 m_clipPlanes[6u];
 
-	U32 m_aabbCount;
-	U32 m_padding0;
-	U32 m_padding1;
-	U32 m_padding2;
-
 	Vec4 m_maxLodDistances;
 
 	Vec3 m_lodReferencePoint;

+ 3 - 0
AnKi/Shaders/Intellisense.hlsl

@@ -150,6 +150,9 @@ T max(T a, T b);
 template<typename T>
 T saturate(T a);
 
+template<typename T>
+float dot(T a, T b);
+
 // Atomics
 
 template<typename T>

+ 2 - 2
AnKi/Util/Assert.h

@@ -10,7 +10,7 @@
 /// Assertion. Print an error and stop the debugger (if it runs through a debugger) and then abort.
 #if !ANKI_EXTRA_CHECKS
 #	define ANKI_ASSERT(x) ((void)0)
-#	define ANKI_ENABLE_ASSERTIONS 0
+#	define ANKI_ASSERTIONS_ENABLED 0
 #else
 
 namespace anki {
@@ -28,6 +28,6 @@ void akassert(const char* exprTxt, const char* file, int line, const char* func)
 				ANKI_UNREACHABLE(); \
 			} \
 		} while(0)
-#	define ANKI_ENABLE_ASSERTIONS 1
+#	define ANKI_ASSERTIONS_ENABLED 1
 
 #endif

+ 1 - 1
AnKi/Util/Singleton.cpp

@@ -7,7 +7,7 @@
 
 namespace anki {
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 I32 g_singletonsAllocated = 0;
 
 class SingletonsAllocatedChecker

+ 5 - 5
AnKi/Util/Singleton.h

@@ -11,7 +11,7 @@
 
 namespace anki {
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 extern I32 g_singletonsAllocated;
 #endif
 
@@ -35,7 +35,7 @@ public:
 		ANKI_ASSERT(!m_initialized);
 		::new(m_global) T(args...);
 		m_initialized = true;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		++g_singletonsAllocated;
 #endif
 
@@ -48,7 +48,7 @@ public:
 		{
 			reinterpret_cast<T*>(m_global)->~T();
 			m_initialized = false;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 			--g_singletonsAllocated;
 #endif
 		}
@@ -83,7 +83,7 @@ public:
 		ANKI_ASSERT(m_global == nullptr);
 		m_global = new T(args...);
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		++g_singletonsAllocated;
 #endif
 
@@ -96,7 +96,7 @@ public:
 		{
 			delete m_global;
 			m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 			--g_singletonsAllocated;
 #endif
 		}

+ 1 - 1
AnKi/Util/ThreadHive.h

@@ -106,7 +106,7 @@ public:
 	{
 		ANKI_ASSERT(size > 0 && alignment > 0);
 		void* out = m_pool.allocate(size, alignment);
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		memset(out, 0, size);
 #endif
 		return out;

+ 2 - 2
AnKi/Window/InputAndroid.cpp

@@ -16,7 +16,7 @@ Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new InputAndroid;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 
@@ -30,7 +30,7 @@ void MakeSingletonPtr<Input>::freeSingleton()
 	{
 		delete static_cast<InputAndroid*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 2 - 2
AnKi/Window/InputDummy.cpp

@@ -15,7 +15,7 @@ Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new Input;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 
@@ -29,7 +29,7 @@ void MakeSingletonPtr<Input>::freeSingleton()
 	{
 		delete static_cast<Input*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 2 - 2
AnKi/Window/InputSdl.cpp

@@ -55,7 +55,7 @@ Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new InputSdl;
 
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 
@@ -69,7 +69,7 @@ void MakeSingletonPtr<Input>::freeSingleton()
 	{
 		delete static_cast<InputSdl*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 2 - 2
AnKi/Window/NativeWindowAndroid.cpp

@@ -13,7 +13,7 @@ NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowAndroid();
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 	return *m_global;
@@ -26,7 +26,7 @@ void MakeSingletonPtr<NativeWindow>::freeSingleton()
 	{
 		delete static_cast<NativeWindowAndroid*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 2 - 2
AnKi/Window/NativeWindowHeadless.cpp

@@ -13,7 +13,7 @@ NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowHeadless();
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 	return *m_global;
@@ -26,7 +26,7 @@ void MakeSingletonPtr<NativeWindow>::freeSingleton()
 	{
 		delete static_cast<NativeWindowHeadless*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}

+ 2 - 2
AnKi/Window/NativeWindowSdl.cpp

@@ -17,7 +17,7 @@ NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowSdl();
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	++g_singletonsAllocated;
 #endif
 	return *m_global;
@@ -30,7 +30,7 @@ void MakeSingletonPtr<NativeWindow>::freeSingleton()
 	{
 		delete static_cast<NativeWindowSdl*>(m_global);
 		m_global = nullptr;
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		--g_singletonsAllocated;
 #endif
 	}