Browse Source

Move Dbg to the new system

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
43cda44095
47 changed files with 699 additions and 1149 deletions
  1. 5 6
      AnKi/Core/GpuMemory/GpuSceneBuffer.cpp
  2. 34 0
      AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h
  3. 10 9
      AnKi/Core/GpuMemory/RebarTransientMemoryPool.cpp
  4. 48 11
      AnKi/Core/GpuMemory/RebarTransientMemoryPool.h
  5. 6 0
      AnKi/Gr/RenderGraph.h
  6. 2 1
      AnKi/Math/Mat.h
  7. 4 1
      AnKi/Math/Transform.h
  8. 3 2
      AnKi/Math/Vec.h
  9. 7 20
      AnKi/Renderer/ClusterBinning2.cpp
  10. 3 5
      AnKi/Renderer/ClusterBinning2.h
  11. 141 151
      AnKi/Renderer/Dbg.cpp
  12. 9 4
      AnKi/Renderer/Dbg.h
  13. 2 0
      AnKi/Renderer/ForwardShading.cpp
  14. 7 0
      AnKi/Renderer/ForwardShading.h
  15. 20 13
      AnKi/Renderer/GBuffer.cpp
  16. 9 0
      AnKi/Renderer/GBuffer.h
  17. 1 6
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  18. 4 9
      AnKi/Renderer/PrimaryNonRenderableVisibility.cpp
  19. 1 1
      AnKi/Renderer/ProbeReflections.cpp
  20. 7 7
      AnKi/Renderer/RendererObject.h
  21. 7 9
      AnKi/Renderer/RtShadows.cpp
  22. 0 305
      AnKi/Renderer/Utils/DebugDrawer.cpp
  23. 0 107
      AnKi/Renderer/Utils/DebugDrawer.h
  24. 3 98
      AnKi/Renderer/Utils/Drawer.cpp
  25. 0 9
      AnKi/Renderer/Utils/Drawer.h
  26. 76 41
      AnKi/Renderer/Utils/GpuVisibility.cpp
  27. 9 4
      AnKi/Renderer/Utils/GpuVisibility.h
  28. 2 2
      AnKi/Renderer/Utils/TraditionalDeferredShading.cpp
  29. 3 5
      AnKi/Scene/Components/LightComponent.cpp
  30. 0 2
      AnKi/Scene/Components/LightComponent.h
  31. 26 100
      AnKi/Scene/Components/ModelComponent.cpp
  32. 2 3
      AnKi/Scene/Components/ModelComponent.h
  33. 11 50
      AnKi/Scene/Components/ParticleEmitterComponent.cpp
  34. 0 4
      AnKi/Scene/Components/ParticleEmitterComponent.h
  35. 6 0
      AnKi/Scene/GpuSceneArray.h
  36. 5 2
      AnKi/Scene/SceneGraph.cpp
  37. 19 2
      AnKi/Scene/SceneGraph.h
  38. 2 72
      AnKi/Scene/Visibility.cpp
  39. 7 13
      AnKi/Shaders/ClusteredShadingFunctions.hlsl
  40. 145 0
      AnKi/Shaders/DbgBillboard.ankiprog
  41. 24 27
      AnKi/Shaders/DbgRenderables.ankiprog
  42. 11 0
      AnKi/Shaders/GpuVisibility.ankiprog
  43. 0 32
      AnKi/Shaders/Include/ClusteredShadingTypes.h
  44. 1 0
      AnKi/Shaders/Intellisense.hlsl
  45. 4 2
      AnKi/Shaders/TonemappingFunctions.hlsl
  46. 7 8
      AnKi/Ui/Canvas.cpp
  47. 6 6
      Tests/Gr/Gr.cpp

+ 5 - 6
AnKi/Core/GpuMemory/GpuSceneBuffer.cpp

@@ -127,16 +127,15 @@ void GpuSceneMicroPatcher::patchGpuScene(CommandBuffer& cmdb)
 	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatches, m_crntFramePatchHeaders.getSize());
 	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatchUploadData, m_crntFramePatchData.getSizeInBytes());
 
-	RebarAllocation headersToken;
-	void* mapped = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchHeaders.getSizeInBytes(), headersToken);
+	void* mapped;
+	const RebarAllocation headersToken = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchHeaders.getSizeInBytes(), mapped);
 	memcpy(mapped, &m_crntFramePatchHeaders[0], m_crntFramePatchHeaders.getSizeInBytes());
 
-	RebarAllocation dataToken;
-	mapped = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchData.getSizeInBytes(), dataToken);
+	const RebarAllocation dataToken = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchData.getSizeInBytes(), mapped);
 	memcpy(mapped, &m_crntFramePatchData[0], m_crntFramePatchData.getSizeInBytes());
 
-	cmdb.bindStorageBuffer(0, 0, &RebarTransientMemoryPool::getSingleton().getBuffer(), headersToken.m_offset, headersToken.m_range);
-	cmdb.bindStorageBuffer(0, 1, &RebarTransientMemoryPool::getSingleton().getBuffer(), dataToken.m_offset, dataToken.m_range);
+	cmdb.bindStorageBuffer(0, 0, headersToken);
+	cmdb.bindStorageBuffer(0, 1, dataToken);
 	cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize);
 
 	cmdb.bindShaderProgram(m_grProgram.get());

+ 34 - 0
AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h

@@ -17,7 +17,35 @@ namespace anki {
 /// @memberof GpuVisibleTransientMemoryPool
 class GpuVisibleTransientMemoryAllocation
 {
+	friend class GpuVisibleTransientMemoryPool;
+
 public:
+	Buffer& getBuffer() const
+	{
+		ANKI_ASSERT(isValid());
+		return *m_buffer;
+	}
+
+	PtrSize getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_offset;
+	}
+
+	PtrSize getRange() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_size;
+	}
+
+	Bool isValid() const
+	{
+		return m_buffer != nullptr;
+	}
+
+	operator BufferOffsetRange() const;
+
+private:
 	Buffer* m_buffer = nullptr;
 	PtrSize m_offset = kMaxPtrSize;
 	PtrSize m_size = 0;
@@ -65,6 +93,12 @@ private:
 
 	~GpuVisibleTransientMemoryPool() = default;
 };
+
+inline GpuVisibleTransientMemoryAllocation::operator BufferOffsetRange() const
+{
+	ANKI_ASSERT(isValid());
+	return {m_buffer, m_offset, m_size};
+}
 /// @}
 
 } // end namespace anki

+ 10 - 9
AnKi/Core/GpuMemory/RebarTransientMemoryPool.cpp

@@ -43,18 +43,18 @@ void RebarTransientMemoryPool::init()
 	m_mappedMem = static_cast<U8*>(m_buffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
 }
 
-void* RebarTransientMemoryPool::allocateFrame(PtrSize size, RebarAllocation& token)
+RebarAllocation RebarTransientMemoryPool::allocateFrame(PtrSize size, void*& mappedMem)
 {
-	void* address = tryAllocateFrame(size, token);
-	if(address == nullptr) [[unlikely]]
+	RebarAllocation out = tryAllocateFrame(size, mappedMem);
+	if(!out.isValid()) [[unlikely]]
 	{
 		ANKI_CORE_LOGF("Out of ReBAR GPU memory");
 	}
 
-	return address;
+	return out;
 }
 
-void* RebarTransientMemoryPool::tryAllocateFrame(PtrSize origSize, RebarAllocation& token)
+RebarAllocation RebarTransientMemoryPool::tryAllocateFrame(PtrSize origSize, void*& mappedMem)
 {
 	const PtrSize size = getAlignedRoundUp(m_alignment, origSize);
 
@@ -69,11 +69,12 @@ void* RebarTransientMemoryPool::tryAllocateFrame(PtrSize origSize, RebarAllocati
 		done = offset < end;
 	} while(!done);
 
-	void* address = m_mappedMem + offset;
-	token.m_offset = offset;
-	token.m_range = origSize;
+	mappedMem = m_mappedMem + offset;
+	RebarAllocation out;
+	out.m_offset = offset;
+	out.m_range = origSize;
 
-	return address;
+	return out;
 }
 
 void RebarTransientMemoryPool::endFrame()

+ 48 - 11
AnKi/Core/GpuMemory/RebarTransientMemoryPool.h

@@ -16,10 +16,9 @@ namespace anki {
 /// Token that gets returned when requesting for memory to write to a resource.
 class RebarAllocation
 {
-public:
-	PtrSize m_offset = 0;
-	PtrSize m_range = 0;
+	friend class RebarTransientMemoryPool;
 
+public:
 	RebarAllocation() = default;
 
 	~RebarAllocation() = default;
@@ -29,15 +28,30 @@ public:
 		return m_offset == b.m_offset && m_range == b.m_range;
 	}
 
-	void markUnused()
+	Bool isValid() const
+	{
+		return m_range != 0;
+	}
+
+	PtrSize getOffset() const
 	{
-		m_offset = m_range = kMaxU32;
+		ANKI_ASSERT(isValid());
+		return m_offset;
 	}
 
-	Bool isUnused() const
+	PtrSize getRange() const
 	{
-		return m_offset == kMaxU32 && m_range == kMaxU32;
+		ANKI_ASSERT(isValid());
+		return m_range;
 	}
+
+	Buffer& getBuffer() const;
+
+	operator BufferOffsetRange() const;
+
+private:
+	PtrSize m_offset = kMaxPtrSize;
+	PtrSize m_range = 0;
 };
 
 /// Manages staging GPU memory.
@@ -56,16 +70,28 @@ public:
 	void endFrame();
 
 	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the N-(kMaxFramesInFlight-1) frame.
-	void* allocateFrame(PtrSize size, RebarAllocation& token);
+	RebarAllocation allocateFrame(PtrSize size, void*& mappedMem);
+
+	template<typename T>
+	RebarAllocation allocateFrame(U32 count, T*& mappedMem)
+	{
+		void* mem;
+		const RebarAllocation out = allocateFrame(count * sizeof(T), mem);
+		mappedMem = static_cast<T*>(mem);
+		return out;
+	}
 
 	template<typename T>
-	T* allocateFrame(U32 count, RebarAllocation& token)
+	RebarAllocation allocateFrame(U32 count, WeakArray<T>& arr)
 	{
-		return static_cast<T*>(allocateFrame(count * sizeof(T), token));
+		void* mem;
+		const RebarAllocation out = allocateFrame(count * sizeof(T), mem);
+		arr = {static_cast<T*>(mem), count};
+		return out;
 	}
 
 	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the N-(kMaxFramesInFlight-1) frame.
-	void* tryAllocateFrame(PtrSize size, RebarAllocation& token);
+	RebarAllocation tryAllocateFrame(PtrSize size, void*& mappedMem);
 
 	ANKI_PURE Buffer& getBuffer() const
 	{
@@ -89,6 +115,17 @@ private:
 
 	~RebarTransientMemoryPool();
 };
+
+inline Buffer& RebarAllocation::getBuffer() const
+{
+	return RebarTransientMemoryPool::getSingleton().getBuffer();
+}
+
+inline RebarAllocation::operator BufferOffsetRange() const
+{
+	ANKI_ASSERT(isValid());
+	return {&RebarTransientMemoryPool::getSingleton().getBuffer(), m_offset, m_range};
+}
 /// @}
 
 } // end namespace anki

+ 6 - 0
AnKi/Gr/RenderGraph.h

@@ -523,6 +523,12 @@ public:
 	/// Import a buffer.
 	BufferHandle importBuffer(Buffer* buff, BufferUsageBit usage, PtrSize offset = 0, PtrSize range = kMaxPtrSize);
 
+	/// Import a buffer.
+	BufferHandle importBuffer(BufferUsageBit usage, const BufferOffsetRange& buff)
+	{
+		return importBuffer(buff.m_buffer, usage, buff.m_offset, buff.m_range);
+	}
+
 	/// Import an AS.
 	AccelerationStructureHandle importAccelerationStructure(AccelerationStructure* as, AccelerationStructureUsageBit usage);
 

+ 2 - 1
AnKi/Math/Mat.h

@@ -45,7 +45,8 @@ public:
 
 	/// @name Constructors
 	/// @{
-	TMat()
+	constexpr TMat()
+		: TMat(T(0))
 	{
 	}
 

+ 4 - 1
AnKi/Math/Transform.h

@@ -19,7 +19,10 @@ class TTransform
 public:
 	/// @name Constructors
 	/// @{
-	TTransform()
+	constexpr TTransform()
+		: m_origin(T(0))
+		, m_rotation(TMat<T, 3, 4>::getIdentity())
+		, m_scale(1.0)
 	{
 	}
 

+ 3 - 2
AnKi/Math/Vec.h

@@ -29,8 +29,9 @@ public:
 	/// @name Constructors
 	/// @{
 
-	/// Defaut constructor. IT WILL NOT INITIALIZE ANYTHING.
-	TVec()
+	/// Defaut constructor. It will zero it.
+	constexpr TVec()
+		: TVec(T(0))
 	{
 	}
 

+ 7 - 20
AnKi/Renderer/ClusterBinning2.cpp

@@ -56,10 +56,7 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 	{
 		m_runCtx.m_rctx = &ctx;
 
-		RebarAllocation alloc;
-		m_runCtx.m_uniformsCpu = RebarTransientMemoryPool::getSingleton().allocateFrame<ClusteredShadingUniforms>(1, alloc);
-
-		m_runCtx.m_clusterUniformsOffset = alloc.m_offset;
+		m_runCtx.m_clusterUniformsBuffer = RebarTransientMemoryPool::getSingleton().allocateFrame(1, m_runCtx.m_uniformsCpu);
 
 		CoreThreadHive::getSingleton().submitTask(
 			[](void* userData, [[maybe_unused]] U32 threadId, [[maybe_unused]] ThreadHive& hive,
@@ -72,11 +69,8 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 	// Allocate the clusters buffer
 	{
 		const U32 clusterCount = getRenderer().getTileCounts().x() * getRenderer().getTileCounts().y() + getRenderer().getZSplitCount();
-		const GpuVisibleTransientMemoryAllocation alloc = GpuVisibleTransientMemoryPool::getSingleton().allocate(sizeof(Cluster) * clusterCount);
-		m_runCtx.m_clustersBuffer.m_buffer = alloc.m_buffer;
-		m_runCtx.m_clustersBuffer.m_offset = alloc.m_offset;
-		m_runCtx.m_clustersBuffer.m_range = alloc.m_size;
-		m_runCtx.m_clustersHandle = rgraph.importBuffer(alloc.m_buffer, BufferUsageBit::kNone, alloc.m_offset, alloc.m_size);
+		m_runCtx.m_clustersBuffer = GpuVisibleTransientMemoryPool::getSingleton().allocate(sizeof(Cluster) * clusterCount);
+		m_runCtx.m_clustersHandle = rgraph.importBuffer(BufferUsageBit::kNone, m_runCtx.m_clustersBuffer);
 	}
 
 	// Setup the indirect dispatches and zero the clusters buffer
@@ -85,12 +79,8 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 	{
 		// Allocate memory for the indirect args
 		constexpr U32 dispatchCount = U32(GpuSceneNonRenderableObjectType::kCount) * 2;
-		const GpuVisibleTransientMemoryAllocation alloc =
-			GpuVisibleTransientMemoryPool::getSingleton().allocate(sizeof(DispatchIndirectArgs) * dispatchCount);
-		indirectArgsBuff.m_buffer = alloc.m_buffer;
-		indirectArgsBuff.m_offset = alloc.m_offset;
-		indirectArgsBuff.m_range = alloc.m_size;
-		indirectArgsHandle = rgraph.importBuffer(alloc.m_buffer, BufferUsageBit::kNone, alloc.m_offset, alloc.m_size);
+		indirectArgsBuff = GpuVisibleTransientMemoryPool::getSingleton().allocate(sizeof(DispatchIndirectArgs) * dispatchCount);
+		indirectArgsHandle = rgraph.importBuffer(BufferUsageBit::kNone, indirectArgsBuff);
 
 		// Create the pass
 		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("Cluster binning setup");
@@ -222,12 +212,9 @@ void ClusterBinning2::populateRenderGraph(RenderingContext& ctx)
 		// Allocations
 		for(GpuSceneNonRenderableObjectType type : EnumIterable<GpuSceneNonRenderableObjectType>())
 		{
-			const GpuVisibleTransientMemoryAllocation alloc =
+			m_runCtx.m_packedObjectsBuffers[type] =
 				GpuVisibleTransientMemoryPool::getSingleton().allocate(kClusteredObjectSizes2[type] * kMaxVisibleClusteredObjects2[type]);
-			m_runCtx.m_packedObjectsBuffers[type].m_buffer = alloc.m_buffer;
-			m_runCtx.m_packedObjectsBuffers[type].m_offset = alloc.m_offset;
-			m_runCtx.m_packedObjectsBuffers[type].m_range = alloc.m_size;
-			m_runCtx.m_packedObjectsHandles[type] = rgraph.importBuffer(alloc.m_buffer, BufferUsageBit::kNone, alloc.m_offset, alloc.m_size);
+			m_runCtx.m_packedObjectsHandles[type] = rgraph.importBuffer(BufferUsageBit::kNone, m_runCtx.m_packedObjectsBuffers[type]);
 		}
 
 		// Create the pass

+ 3 - 5
AnKi/Renderer/ClusterBinning2.h

@@ -25,11 +25,9 @@ public:
 	/// Populate the rendergraph.
 	void populateRenderGraph(RenderingContext& ctx);
 
-	BufferOffsetRange getClusteredShadingUniforms() const
+	const BufferOffsetRange& getClusteredShadingUniforms() const
 	{
-		ANKI_ASSERT(m_runCtx.m_clusterUniformsOffset != kMaxPtrSize);
-		return BufferOffsetRange{&RebarTransientMemoryPool::getSingleton().getBuffer(), m_runCtx.m_clusterUniformsOffset,
-								 sizeof(ClusteredShadingUniforms)};
+		return m_runCtx.m_clusterUniformsBuffer;
 	}
 
 	const BufferOffsetRange& getPackedObjectsBuffer(GpuSceneNonRenderableObjectType type) const
@@ -71,7 +69,7 @@ private:
 		Array<BufferHandle, U32(GpuSceneNonRenderableObjectType::kCount)> m_packedObjectsHandles;
 		Array<BufferOffsetRange, U32(GpuSceneNonRenderableObjectType::kCount)> m_packedObjectsBuffers;
 
-		PtrSize m_clusterUniformsOffset = kMaxPtrSize; ///< Offset into the ReBAR buffer.
+		BufferOffsetRange m_clusterUniformsBuffer;
 		ClusteredShadingUniforms* m_uniformsCpu = nullptr;
 		RenderingContext* m_rctx = nullptr;
 	} m_runCtx;

+ 141 - 151
AnKi/Renderer/Dbg.cpp

@@ -9,6 +9,9 @@
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/FinalComposite.h>
 #include <AnKi/Renderer/RenderQueue.h>
+#include <AnKi/Renderer/ForwardShading.h>
+#include <AnKi/Renderer/ClusterBinning2.h>
+#include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
 #include <AnKi/Scene.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Enum.h>
@@ -47,16 +50,109 @@ Error Dbg::init()
 	m_fbDescr.bake();
 
 	ResourceManager& rsrcManager = ResourceManager::getSingleton();
-	ANKI_CHECK(m_drawer.init());
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/GiProbe.ankitex", m_giProbeImage));
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/LightBulb.ankitex", m_pointLightImage));
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/SpotLight.ankitex", m_spotLightImage));
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/GreenDecal.ankitex", m_decalImage));
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/Mirror.ankitex", m_reflectionImage));
 
+	ANKI_CHECK(rsrcManager.loadResource("ShaderBinaries/DbgRenderables.ankiprogbin", m_renderablesProg));
+	ANKI_CHECK(rsrcManager.loadResource("ShaderBinaries/DbgBillboard.ankiprogbin", m_nonRenderablesProg));
+
+	{
+		BufferInitInfo buffInit("Dbg cube verts");
+		buffInit.m_size = sizeof(Vec3) * 8;
+		buffInit.m_usage = BufferUsageBit::kVertex;
+		buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
+		m_cubeVertsBuffer = GrManager::getSingleton().newBuffer(buffInit);
+
+		Vec3* verts = static_cast<Vec3*>(m_cubeVertsBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
+
+		constexpr F32 kSize = 1.0f;
+		verts[0] = Vec3(kSize, kSize, kSize); // front top right
+		verts[1] = Vec3(-kSize, kSize, kSize); // front top left
+		verts[2] = Vec3(-kSize, -kSize, kSize); // front bottom left
+		verts[3] = Vec3(kSize, -kSize, kSize); // front bottom right
+		verts[4] = Vec3(kSize, kSize, -kSize); // back top right
+		verts[5] = Vec3(-kSize, kSize, -kSize); // back top left
+		verts[6] = Vec3(-kSize, -kSize, -kSize); // back bottom left
+		verts[7] = Vec3(kSize, -kSize, -kSize); // back bottom right
+
+		m_cubeVertsBuffer->unmap();
+
+		constexpr U kIndexCount = 12 * 2;
+		buffInit.setName("Dbg cube indices");
+		buffInit.m_usage = BufferUsageBit::kIndex;
+		buffInit.m_size = kIndexCount * sizeof(U16);
+		m_cubeIndicesBuffer = GrManager::getSingleton().newBuffer(buffInit);
+		U16* indices = static_cast<U16*>(m_cubeIndicesBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
+
+		U c = 0;
+		indices[c++] = 0;
+		indices[c++] = 1;
+		indices[c++] = 1;
+		indices[c++] = 2;
+		indices[c++] = 2;
+		indices[c++] = 3;
+		indices[c++] = 3;
+		indices[c++] = 0;
+
+		indices[c++] = 4;
+		indices[c++] = 5;
+		indices[c++] = 5;
+		indices[c++] = 6;
+		indices[c++] = 6;
+		indices[c++] = 7;
+		indices[c++] = 7;
+		indices[c++] = 4;
+
+		indices[c++] = 0;
+		indices[c++] = 4;
+		indices[c++] = 1;
+		indices[c++] = 5;
+		indices[c++] = 2;
+		indices[c++] = 6;
+		indices[c++] = 3;
+		indices[c++] = 7;
+
+		m_cubeIndicesBuffer->unmap();
+
+		ANKI_ASSERT(c == kIndexCount);
+	}
+
 	return Error::kNone;
 }
 
+void Dbg::drawNonRenderable(GpuSceneNonRenderableObjectType type, U32 objCount, const RenderingContext& ctx, const ImageResource& image,
+							CommandBuffer& cmdb)
+{
+	ShaderProgramResourceVariantInitInfo variantInitInfo(m_nonRenderablesProg);
+	variantInitInfo.addMutation("DITHERED_DEPTH_TEST", U32(m_ditheredDepthTestOn != 0));
+	variantInitInfo.addMutation("OBJECT_TYPE", U32(type));
+	const ShaderProgramResourceVariant* variant;
+	m_nonRenderablesProg->getOrCreateVariant(variantInitInfo, variant);
+	cmdb.bindShaderProgram(&variant->getProgram());
+
+	class Uniforms
+	{
+	public:
+		Mat4 m_viewProjMat;
+		Mat3x4 m_camTrf;
+	} unis;
+	unis.m_viewProjMat = ctx.m_matrices.m_viewProjection;
+	unis.m_camTrf = ctx.m_matrices.m_cameraTransform;
+	cmdb.setPushConstants(&unis, sizeof(unis));
+
+	cmdb.bindStorageBuffer(0, 2, getRenderer().getClusterBinning2().getPackedObjectsBuffer(type));
+	cmdb.bindStorageBuffer(0, 3, getRenderer().getPrimaryNonRenderableVisibility().getVisibleIndicesBuffer(type));
+
+	cmdb.bindSampler(0, 4, getRenderer().getSamplers().m_trilinearRepeat.get());
+	cmdb.bindTexture(0, 5, &image.getTextureView());
+	cmdb.bindTexture(0, 6, &m_spotLightImage->getTextureView());
+
+	cmdb.draw(PrimitiveTopology::kTriangles, 6, objCount);
+}
+
 void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 {
 	ANKI_ASSERT(g_dbgCVar.get());
@@ -67,166 +163,61 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	cmdb.setViewport(0, 0, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());
 	cmdb.setDepthWrite(false);
 
-	cmdb.bindSampler(0, 1, getRenderer().getSamplers().m_nearestNearestClamp.get());
-
-	rgraphCtx.bindTexture(0, 2, getRenderer().getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
-
 	cmdb.setBlendFactors(0, BlendFactor::kSrcAlpha, BlendFactor::kOneMinusSrcAlpha);
 	cmdb.setDepthCompareOperation((m_depthTestOn) ? CompareOperation::kLess : CompareOperation::kAlways);
+	cmdb.setLineWidth(2.0f);
 
-	// Draw renderables
-	const U32 threadId = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
-	const U32 threadCount = rgraphCtx.m_secondLevelCommandBufferCount;
-	const U32 problemSize = ctx.m_renderQueue->m_renderables.getSize();
-	U32 start, end;
-	splitThreadedProblem(threadId, threadCount, problemSize, start, end);
+	cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
+	rgraphCtx.bindTexture(0, 1, getRenderer().getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-	// Renderables
-	for(U32 i = start; i < end; ++i)
+	// GBuffer renderables
 	{
-		const RenderableQueueElement& el = ctx.m_renderQueue->m_renderables[i];
-
-		const Vec3 tsl = (el.m_aabbMin + el.m_aabbMax) / 2.0f;
-		constexpr F32 kMargin = 0.1f;
-		const Vec3 scale = (el.m_aabbMax - el.m_aabbMin + kMargin) / 2.0f;
-
-		// Set non uniform scale. Add a margin to avoid flickering
-		Mat3 nonUniScale = Mat3::getZero();
-
-		nonUniScale(0, 0) = scale.x();
-		nonUniScale(1, 1) = scale.y();
-		nonUniScale(2, 2) = scale.z();
+		const U32 allAabbCount = GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getElementCount();
 
-		const Mat4 mvp = ctx.m_matrices.m_viewProjection * Mat4(tsl.xyz1(), Mat3::getIdentity() * nonUniScale, 1.0f);
+		ShaderProgramResourceVariantInitInfo variantInitInfo(m_renderablesProg);
+		variantInitInfo.addMutation("DITHERED_DEPTH_TEST", U32(m_ditheredDepthTestOn != 0));
+		const ShaderProgramResourceVariant* variant;
+		m_renderablesProg->getOrCreateVariant(variantInitInfo, variant);
+		cmdb.bindShaderProgram(&variant->getProgram());
 
-		m_drawer.drawCube(mvp, Vec4(1.0f, 0.0f, 1.0f, 1.0f), 2.0f, m_ditheredDepthTestOn, 2.0f, cmdb);
-	}
-
-	// Forward shaded renderables
-	if(threadId == 0)
-	{
-		for(const RenderableQueueElement& el : ctx.m_renderQueue->m_forwardShadingRenderables)
+		class Uniforms
 		{
-			const Vec3 tsl = (el.m_aabbMin + el.m_aabbMax) / 2.0f;
-			constexpr F32 kMargin = 0.1f;
-			const Vec3 scale = (el.m_aabbMax - el.m_aabbMin + kMargin) / 2.0f;
-
-			// Set non uniform scale. Add a margin to avoid flickering
-			Mat3 nonUniScale = Mat3::getZero();
-
-			nonUniScale(0, 0) = scale.x();
-			nonUniScale(1, 1) = scale.y();
-			nonUniScale(2, 2) = scale.z();
-
-			const Mat4 mvp = ctx.m_matrices.m_viewProjection * Mat4(tsl.xyz1(), Mat3::getIdentity() * nonUniScale, 1.0f);
-
-			m_drawer.drawCube(mvp, Vec4(1.0f, 0.0f, 1.0f, 1.0f), 2.0f, m_ditheredDepthTestOn, 2.0f, cmdb);
-		}
+		public:
+			Vec4 m_color;
+			Mat4 m_viewProjMat;
+		} unis;
+		unis.m_color = Vec4(1.0f, 0.0f, 1.0f, 1.0f);
+		unis.m_viewProjMat = ctx.m_matrices.m_viewProjection;
+
+		cmdb.setPushConstants(&unis, sizeof(unis));
+		cmdb.bindVertexBuffer(0, m_cubeVertsBuffer.get(), 0, sizeof(Vec3));
+		cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
+		cmdb.bindIndexBuffer(m_cubeIndicesBuffer.get(), 0, IndexType::kU16);
+
+		cmdb.bindStorageBuffer(0, 2, GpuSceneArrays::RenderableAabbGBuffer::getSingleton().getBufferOffsetRange());
+		cmdb.bindStorageBuffer(0, 3, getRenderer().getGBuffer().getVisibleAabbsBuffer());
+
+		cmdb.drawIndexed(PrimitiveTopology::kLines, 12 * 2, allAabbCount);
 	}
 
-	// GI probes
-	if(threadId == 0)
+	// Forward shading renderables
 	{
-		for(const GlobalIlluminationProbeQueueElement& el : ctx.m_renderQueue->m_giProbes)
-		{
-			const Vec3 tsl = (el.m_aabbMax + el.m_aabbMin) / 2.0f;
-			const Vec3 scale = (tsl - el.m_aabbMin);
-
-			// Set non uniform scale.
-			Mat3 rot = Mat3::getIdentity();
-			rot(0, 0) *= scale.x();
-			rot(1, 1) *= scale.y();
-			rot(2, 2) *= scale.z();
+		const U32 allAabbCount = GpuSceneArrays::RenderableAabbForward::getSingleton().getElementCount();
 
-			const Mat4 mvp = ctx.m_matrices.m_viewProjection * Mat4(tsl.xyz1(), rot, 1.0f);
+		cmdb.bindStorageBuffer(0, 2, GpuSceneArrays::RenderableAabbForward::getSingleton().getBufferOffsetRange());
+		cmdb.bindStorageBuffer(0, 3, getRenderer().getForwardShading().getVisibleAabbsBuffer());
 
-			m_drawer.drawCubes(ConstWeakArray<Mat4>(&mvp, 1), Vec4(0.729f, 0.635f, 0.196f, 1.0f), 1.0f, m_ditheredDepthTestOn, 2.0f, cmdb);
-
-			m_drawer.drawBillboardTextures(ctx.m_matrices.m_projection, ctx.m_matrices.m_view, ConstWeakArray<Vec3>(&tsl, 1), Vec4(1.0f),
-										   m_ditheredDepthTestOn, &m_giProbeImage->getTextureView(),
-										   getRenderer().getSamplers().m_trilinearRepeatAniso.get(), Vec2(0.75f), cmdb);
-		}
+		cmdb.drawIndexed(PrimitiveTopology::kLines, 12 * 2, allAabbCount);
 	}
 
-	// Lights
-	if(threadId == 0)
-	{
-		for(const PointLightQueueElement& el : ctx.m_renderQueue->m_pointLights)
-		{
-			Vec3 color = el.m_diffuseColor.xyz();
-			color /= max(max(color.x(), color.y()), color.z());
-
-			m_drawer.drawBillboardTexture(ctx.m_matrices.m_projection, ctx.m_matrices.m_view, el.m_worldPosition, color.xyz1(), m_ditheredDepthTestOn,
-										  &m_pointLightImage->getTextureView(), getRenderer().getSamplers().m_trilinearRepeatAniso.get(), Vec2(0.75f),
-										  cmdb);
-		}
-
-		for(const SpotLightQueueElement& el : ctx.m_renderQueue->m_spotLights)
-		{
-			Vec3 color = el.m_diffuseColor.xyz();
-			color /= max(max(color.x(), color.y()), color.z());
-
-			m_drawer.drawBillboardTexture(ctx.m_matrices.m_projection, ctx.m_matrices.m_view, el.m_worldTransform.getTranslationPart().xyz(),
-										  color.xyz1(), m_ditheredDepthTestOn, &m_spotLightImage->getTextureView(),
-										  getRenderer().getSamplers().m_trilinearRepeatAniso.get(), Vec2(0.75f), cmdb);
-		}
-	}
-
-	// Decals
-	if(threadId == 0)
-	{
-		for(const DecalQueueElement& el : ctx.m_renderQueue->m_decals)
-		{
-			const Mat3 rot = el.m_obbRotation;
-			const Vec4 tsl = el.m_obbCenter.xyz1();
-			const Vec3 scale = el.m_obbExtend;
-
-			Mat3 nonUniScale = Mat3::getZero();
-			nonUniScale(0, 0) = scale.x();
-			nonUniScale(1, 1) = scale.y();
-			nonUniScale(2, 2) = scale.z();
-
-			const Mat4 mvp = ctx.m_matrices.m_viewProjection * Mat4(tsl, rot * nonUniScale, 1.0f);
-
-			m_drawer.drawCubes(ConstWeakArray<Mat4>(&mvp, 1), Vec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f, m_ditheredDepthTestOn, 2.0f, cmdb);
-
-			const Vec3 pos = el.m_obbCenter;
-			m_drawer.drawBillboardTextures(ctx.m_matrices.m_projection, ctx.m_matrices.m_view, ConstWeakArray<Vec3>(&pos, 1), Vec4(1.0f),
-										   m_ditheredDepthTestOn, &m_decalImage->getTextureView(),
-										   getRenderer().getSamplers().m_trilinearRepeatAniso.get(), Vec2(0.75f), cmdb);
-		}
-	}
-
-	// Reflection probes
-	if(threadId == 0)
-	{
-		for(const ReflectionProbeQueueElement& el : ctx.m_renderQueue->m_reflectionProbes)
-		{
-			const Vec3 tsl = el.m_worldPosition;
-			const Vec3 scale = (el.m_aabbMax - el.m_aabbMin);
-
-			// Set non uniform scale.
-			Mat3 rot = Mat3::getIdentity();
-			rot(0, 0) *= scale.x();
-			rot(1, 1) *= scale.y();
-			rot(2, 2) *= scale.z();
-
-			const Mat4 mvp = ctx.m_matrices.m_viewProjection * Mat4(tsl.xyz1(), rot, 1.0f);
-
-			m_drawer.drawCubes(ConstWeakArray<Mat4>(&mvp, 1), Vec4(0.0f, 0.0f, 1.0f, 1.0f), 1.0f, m_ditheredDepthTestOn, 2.0f, cmdb);
-
-			m_drawer.drawBillboardTextures(ctx.m_matrices.m_projection, ctx.m_matrices.m_view, ConstWeakArray<Vec3>(&el.m_worldPosition, 1),
-										   Vec4(1.0f), m_ditheredDepthTestOn, &m_reflectionImage->getTextureView(),
-										   getRenderer().getSamplers().m_trilinearRepeatAniso.get(), Vec2(0.75f), cmdb);
-		}
-	}
-
-	if(threadId == (threadCount - 1) && g_dbgPhysicsCVar.get())
-	{
-		m_physicsDrawer.start(ctx.m_matrices.m_viewProjection, cmdb);
-		m_physicsDrawer.drawWorld(PhysicsWorld::getSingleton());
-		m_physicsDrawer.end();
-	}
+	// Draw non-renderables
+	drawNonRenderable(GpuSceneNonRenderableObjectType::kLight, GpuSceneArrays::Light::getSingleton().getElementCount(), ctx, *m_pointLightImage,
+					  cmdb);
+	drawNonRenderable(GpuSceneNonRenderableObjectType::kDecal, GpuSceneArrays::Decal::getSingleton().getElementCount(), ctx, *m_decalImage, cmdb);
+	drawNonRenderable(GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe,
+					  GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount(), ctx, *m_giProbeImage, cmdb);
+	drawNonRenderable(GpuSceneNonRenderableObjectType::kReflectionProbe, GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount(), ctx,
+					  *m_reflectionImage, cmdb);
 
 	// Restore state
 	cmdb.setDepthCompareOperation(CompareOperation::kLess);
@@ -245,12 +236,11 @@ void Dbg::populateRenderGraph(RenderingContext& ctx)
 	m_runCtx.m_rt = rgraph.newRenderTarget(m_rtDescr);
 
 	// Create pass
-	GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("DBG");
+	GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Debug");
 
-	pass.setWork(computeNumberOfSecondLevelCommandBuffers(ctx.m_renderQueue->m_renderables.getSize()),
-				 [this, &ctx](RenderPassWorkContext& rgraphCtx) {
-					 run(rgraphCtx, ctx);
-				 });
+	pass.setWork(1, [this, &ctx](RenderPassWorkContext& rgraphCtx) {
+		run(rgraphCtx, ctx);
+	});
 
 	pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_rt}, getRenderer().getGBuffer().getDepthRt());
 

+ 9 - 4
AnKi/Renderer/Dbg.h

@@ -6,7 +6,6 @@
 #pragma once
 
 #include <AnKi/Renderer/RendererObject.h>
-#include <AnKi/Renderer/Utils/DebugDrawer.h>
 #include <AnKi/Gr.h>
 #include <AnKi/Util/Enum.h>
 #include <AnKi/Renderer/RenderQueue.h>
@@ -71,15 +70,18 @@ private:
 	RenderTargetDescription m_rtDescr;
 	FramebufferDescription m_fbDescr;
 
-	DebugDrawer2 m_drawer;
-	PhysicsDebugDrawer m_physicsDrawer{&m_drawer};
-
 	ImageResourcePtr m_giProbeImage;
 	ImageResourcePtr m_pointLightImage;
 	ImageResourcePtr m_spotLightImage;
 	ImageResourcePtr m_decalImage;
 	ImageResourcePtr m_reflectionImage;
 
+	BufferPtr m_cubeVertsBuffer;
+	BufferPtr m_cubeIndicesBuffer;
+
+	ShaderProgramResourcePtr m_renderablesProg;
+	ShaderProgramResourcePtr m_nonRenderablesProg;
+
 	Bool m_depthTestOn : 1 = false;
 	Bool m_ditheredDepthTestOn : 1 = false;
 
@@ -90,6 +92,9 @@ private:
 	} m_runCtx;
 
 	void run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx);
+
+	void drawNonRenderable(GpuSceneNonRenderableObjectType type, U32 objCount, const RenderingContext& ctx, const ImageResource& image,
+						   CommandBuffer& cmdb);
 };
 /// @}
 

+ 2 - 0
AnKi/Renderer/ForwardShading.cpp

@@ -14,6 +14,7 @@
 #include <AnKi/Renderer/ClusterBinning2.h>
 #include <AnKi/Renderer/LensFlare.h>
 #include <AnKi/Renderer/GBuffer.h>
+#include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
 #include <AnKi/Shaders/Include/MaterialTypes.h>
 #include <AnKi/Core/App.h>
@@ -33,6 +34,7 @@ void ForwardShading::populateRenderGraph(RenderingContext& ctx)
 	visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 	visIn.m_lodDistances = lodDistances;
 	visIn.m_rgraph = &rgraph;
+	visIn.m_gatherAabbIndices = g_dbgCVar.get();
 	RenderTargetHandle hzb = getRenderer().getGBuffer().getHzbRt();
 	visIn.m_hzbRt = &hzb;
 

+ 7 - 0
AnKi/Renderer/ForwardShading.h

@@ -32,6 +32,13 @@ public:
 
 	void run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
 
+	/// Returns a buffer with indices of the visible AABBs. Used in debug drawing.
+	const BufferOffsetRange& getVisibleAabbsBuffer() const
+	{
+		ANKI_ASSERT(m_runCtx.m_visOut.m_visibleAaabbIndicesBuffer.m_buffer != nullptr);
+		return m_runCtx.m_visOut.m_visibleAaabbIndicesBuffer;
+	}
+
 private:
 	class
 	{

+ 20 - 13
AnKi/Renderer/GBuffer.cpp

@@ -8,6 +8,7 @@
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/VrsSriGeneration.h>
 #include <AnKi/Renderer/Scale.h>
+#include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/CVarSet.h>
@@ -159,20 +160,26 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 
-	const CommonMatrices& matrices = (getRenderer().getFrameCount() <= 1) ? ctx.m_matrices : ctx.m_prevMatrices;
-	const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
-
-	FrustumGpuVisibilityInput visIn;
-	visIn.m_passesName = "GBuffer visibility";
-	visIn.m_technique = RenderingTechnique::kGBuffer;
-	visIn.m_viewProjectionMatrix = matrices.m_viewProjection;
-	visIn.m_lodReferencePoint = matrices.m_cameraTransform.getTranslationPart().xyz();
-	visIn.m_lodDistances = lodDistances;
-	visIn.m_rgraph = &rgraph;
-	visIn.m_hzbRt = &m_runCtx.m_hzbRt;
-
+	// Visibility
 	GpuVisibilityOutput visOut;
-	getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
+	{
+		const CommonMatrices& matrices = (getRenderer().getFrameCount() <= 1) ? ctx.m_matrices : ctx.m_prevMatrices;
+		const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
+
+		FrustumGpuVisibilityInput visIn;
+		visIn.m_passesName = "GBuffer visibility";
+		visIn.m_technique = RenderingTechnique::kGBuffer;
+		visIn.m_viewProjectionMatrix = matrices.m_viewProjection;
+		visIn.m_lodReferencePoint = matrices.m_cameraTransform.getTranslationPart().xyz();
+		visIn.m_lodDistances = lodDistances;
+		visIn.m_rgraph = &rgraph;
+		visIn.m_hzbRt = &m_runCtx.m_hzbRt;
+		visIn.m_gatherAabbIndices = g_dbgCVar.get();
+
+		getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
+
+		m_runCtx.m_visibleAabbsBuffer = visOut.m_visibleAaabbIndicesBuffer;
+	}
 
 	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar.get() && g_gbufferVrsCVar.get();
 	const Bool fbDescrHasVrs = m_fbDescr.m_shadingRateAttachmentTexelWidth > 0;

+ 9 - 0
AnKi/Renderer/GBuffer.h

@@ -77,6 +77,13 @@ public:
 		}
 	}
 
+	/// Returns a buffer with indices of the visible AABBs. Used in debug drawing.
+	const BufferOffsetRange& getVisibleAabbsBuffer() const
+	{
+		ANKI_ASSERT(m_runCtx.m_visibleAabbsBuffer.m_buffer != nullptr);
+		return m_runCtx.m_visibleAabbsBuffer;
+	}
+
 private:
 	Array<RenderTargetDescription, kGBufferColorRenderTargetCount> m_colorRtDescrs;
 	Array<TexturePtr, 2> m_depthRts;
@@ -90,6 +97,8 @@ private:
 		RenderTargetHandle m_crntFrameDepthRt;
 		RenderTargetHandle m_prevFrameDepthRt;
 		RenderTargetHandle m_hzbRt;
+
+		BufferOffsetRange m_visibleAabbsBuffer; ///< Optional
 	} m_runCtx;
 
 	Error initInternal();

+ 1 - 6
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -325,11 +325,6 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 				getRenderer().getGpuVisibility().populateRenderGraph(visIn, shadowVisOuts[i]);
 			}
 		}
-		else
-		{
-			zeroMemory(cascadeViewProjMats);
-			zeroMemory(cascadeViewMats);
-		}
 
 		// Shadow pass. Optional
 		if(doShadows)
@@ -377,7 +372,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 			GpuVisibilityNonRenderablesInput in;
 			in.m_passesName = "GI light visibility";
 			in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
-			in.m_viewProjectionMat = cascadeViewProjMats[faceIdx];
+			in.m_viewProjectionMat = frustums[faceIdx].getViewProjectionMatrix();
 			in.m_rgraph = &rgraph;
 			getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
 		}

+ 4 - 9
AnKi/Renderer/PrimaryNonRenderableVisibility.cpp

@@ -77,17 +77,12 @@ void PrimaryNonRenderableVisibility::populateRenderGraph(RenderingContext& ctx)
 		{
 			// No objects, point to a buffer with zeros
 
-			RebarAllocation alloc;
-			void* mem = RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(U32), alloc);
+			void* mem;
+			RebarAllocation alloc = RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(U32), mem);
 			memset(mem, 0, sizeof(U32));
 
-			m_runCtx.m_visibleIndicesBuffers[type].m_buffer = &RebarTransientMemoryPool::getSingleton().getBuffer();
-			m_runCtx.m_visibleIndicesBuffers[type].m_offset = alloc.m_offset;
-			m_runCtx.m_visibleIndicesBuffers[type].m_range = alloc.m_range;
-
-			m_runCtx.m_visibleIndicesHandles[type] =
-				rgraph.importBuffer(m_runCtx.m_visibleIndicesBuffers[type].m_buffer, BufferUsageBit::kNone,
-									m_runCtx.m_visibleIndicesBuffers[type].m_offset, m_runCtx.m_visibleIndicesBuffers[type].m_range);
+			m_runCtx.m_visibleIndicesBuffers[type] = alloc;
+			m_runCtx.m_visibleIndicesHandles[type] = rgraph.importBuffer(BufferUsageBit::kNone, m_runCtx.m_visibleIndicesBuffers[type]);
 		}
 		else
 		{

+ 1 - 1
AnKi/Renderer/ProbeReflections.cpp

@@ -474,7 +474,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		GpuVisibilityNonRenderablesInput in;
 		in.m_passesName = "Cube refl light visibility";
 		in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
-		in.m_viewProjectionMat = cascadeViewProjMats[faceIdx];
+		in.m_viewProjectionMat = frustums[faceIdx].getViewProjectionMatrix();
 		in.m_rgraph = &rgraph;
 		getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
 	}

+ 7 - 7
AnKi/Renderer/RendererObject.h

@@ -66,20 +66,20 @@ protected:
 	template<typename T>
 	static T* allocateAndBindUniforms(CommandBuffer& cmdb, U32 set, U32 binding)
 	{
-		RebarAllocation alloc;
-		T* ptr = static_cast<T*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(T), alloc));
+		T* ptr;
+		const RebarAllocation alloc = RebarTransientMemoryPool::getSingleton().allocateFrame(1, ptr);
 		ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(ptr)));
-		cmdb.bindUniformBuffer(set, binding, &RebarTransientMemoryPool::getSingleton().getBuffer(), alloc.m_offset, alloc.m_range);
+		cmdb.bindUniformBuffer(set, binding, alloc);
 		return ptr;
 	}
 
 	template<typename T>
-	static T* allocateAndBindStorage(CommandBuffer& cmdb, U32 set, U32 binding, PtrSize count = 1)
+	static T* allocateAndBindStorage(CommandBuffer& cmdb, U32 set, U32 binding, U32 count = 1)
 	{
-		RebarAllocation alloc;
-		T* ptr = static_cast<T*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(T) * count, alloc));
+		T* ptr;
+		const RebarAllocation alloc = RebarTransientMemoryPool::getSingleton().allocateFrame(count, ptr);
 		ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(ptr)));
-		cmdb.bindStorageBuffer(set, binding, &RebarTransientMemoryPool::getSingleton().getBuffer(), alloc.m_offset, alloc.m_range);
+		cmdb.bindStorageBuffer(set, binding, alloc);
 		return ptr;
 	}
 

+ 7 - 9
AnKi/Renderer/RtShadows.cpp

@@ -432,14 +432,12 @@ void RtShadows::run(RenderPassWorkContext& rgraphCtx)
 
 	// Allocate, set and bind global uniforms
 	{
-		RebarAllocation globalUniformsToken;
-		MaterialGlobalUniforms* globalUniforms = static_cast<MaterialGlobalUniforms*>(
-			RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(MaterialGlobalUniforms), globalUniformsToken));
+		MaterialGlobalUniforms* globalUniforms;
+		const RebarAllocation globalUniformsToken = RebarTransientMemoryPool::getSingleton().allocateFrame(1, globalUniforms);
 
 		memset(globalUniforms, 0, sizeof(*globalUniforms)); // Don't care for now
 
-		cmdb.bindUniformBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kGlobalUniforms),
-							   &RebarTransientMemoryPool::getSingleton().getBuffer(), globalUniformsToken.m_offset, globalUniformsToken.m_range);
+		cmdb.bindUniformBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kGlobalUniforms), globalUniformsToken);
 	}
 
 	// More globals
@@ -607,12 +605,12 @@ void RtShadows::buildSbt(RenderingContext& ctx)
 	m_runCtx.m_hitGroupCount = instanceCount;
 
 	// Allocate SBT
-	RebarAllocation token;
-	U8* sbt =
-		static_cast<U8*>(RebarTransientMemoryPool::getSingleton().allocateFrame(PtrSize(m_sbtRecordSize) * (instanceCount + extraSbtRecords), token));
+	U8* sbt;
+	const RebarAllocation token =
+		RebarTransientMemoryPool::getSingleton().allocateFrame(PtrSize(m_sbtRecordSize) * (instanceCount + extraSbtRecords), sbt);
 	[[maybe_unused]] const U8* sbtStart = sbt;
 	m_runCtx.m_sbtBuffer.reset(const_cast<Buffer*>(&RebarTransientMemoryPool::getSingleton().getBuffer()));
-	m_runCtx.m_sbtOffset = token.m_offset;
+	m_runCtx.m_sbtOffset = token.getOffset();
 
 	// Set the miss and ray gen handles
 	ConstWeakArray<U8> shaderGroupHandles = m_rtLibraryGrProg->getShaderGroupHandles();

+ 0 - 305
AnKi/Renderer/Utils/DebugDrawer.cpp

@@ -1,305 +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/Renderer/Utils/DebugDrawer.h>
-#include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Renderer/RenderQueue.h>
-#include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
-#include <AnKi/Physics/PhysicsWorld.h>
-#include <AnKi/Gr/Buffer.h>
-
-namespace anki {
-
-void allocateAndPopulateDebugBox(RebarAllocation& vertsToken, RebarAllocation& indicesToken, U32& indexCount)
-{
-	Vec3* verts = static_cast<Vec3*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Vec3) * 8, vertsToken));
-
-	constexpr F32 kSize = 1.0f;
-	verts[0] = Vec3(kSize, kSize, kSize); // front top right
-	verts[1] = Vec3(-kSize, kSize, kSize); // front top left
-	verts[2] = Vec3(-kSize, -kSize, kSize); // front bottom left
-	verts[3] = Vec3(kSize, -kSize, kSize); // front bottom right
-	verts[4] = Vec3(kSize, kSize, -kSize); // back top right
-	verts[5] = Vec3(-kSize, kSize, -kSize); // back top left
-	verts[6] = Vec3(-kSize, -kSize, -kSize); // back bottom left
-	verts[7] = Vec3(kSize, -kSize, -kSize); // back bottom right
-
-	constexpr U kIndexCount = 12 * 2;
-	U16* indices = static_cast<U16*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(U16) * kIndexCount, indicesToken));
-
-	U c = 0;
-	indices[c++] = 0;
-	indices[c++] = 1;
-	indices[c++] = 1;
-	indices[c++] = 2;
-	indices[c++] = 2;
-	indices[c++] = 3;
-	indices[c++] = 3;
-	indices[c++] = 0;
-
-	indices[c++] = 4;
-	indices[c++] = 5;
-	indices[c++] = 5;
-	indices[c++] = 6;
-	indices[c++] = 6;
-	indices[c++] = 7;
-	indices[c++] = 7;
-	indices[c++] = 4;
-
-	indices[c++] = 0;
-	indices[c++] = 4;
-	indices[c++] = 1;
-	indices[c++] = 5;
-	indices[c++] = 2;
-	indices[c++] = 6;
-	indices[c++] = 3;
-	indices[c++] = 7;
-
-	ANKI_ASSERT(c == kIndexCount);
-	indexCount = kIndexCount;
-}
-
-Error DebugDrawer2::init()
-{
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/SceneDebug.ankiprogbin", m_prog));
-
-	{
-		BufferInitInfo bufferInit("DebugCube");
-		bufferInit.m_usage = BufferUsageBit::kVertex;
-		bufferInit.m_size = sizeof(Vec3) * 8;
-		bufferInit.m_mapAccess = BufferMapAccessBit::kWrite;
-		m_cubePositionsBuffer = GrManager::getSingleton().newBuffer(bufferInit);
-
-		Vec3* verts = static_cast<Vec3*>(m_cubePositionsBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-
-		const F32 size = 1.0f;
-		verts[0] = Vec3(size, size, size); // front top right
-		verts[1] = Vec3(-size, size, size); // front top left
-		verts[2] = Vec3(-size, -size, size); // front bottom left
-		verts[3] = Vec3(size, -size, size); // front bottom right
-		verts[4] = Vec3(size, size, -size); // back top right
-		verts[5] = Vec3(-size, size, -size); // back top left
-		verts[6] = Vec3(-size, -size, -size); // back bottom left
-		verts[7] = Vec3(size, -size, -size); // back bottom right
-
-		m_cubePositionsBuffer->flush(0, kMaxPtrSize);
-		m_cubePositionsBuffer->unmap();
-	}
-
-	{
-		constexpr U kIndexCount = 12 * 2;
-
-		BufferInitInfo bufferInit("DebugCube");
-		bufferInit.m_usage = BufferUsageBit::kVertex;
-		bufferInit.m_size = sizeof(U16) * kIndexCount;
-		bufferInit.m_mapAccess = BufferMapAccessBit::kWrite;
-		m_cubeIndicesBuffer = GrManager::getSingleton().newBuffer(bufferInit);
-
-		U16* indices = static_cast<U16*>(m_cubeIndicesBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-
-		U32 indexCount = 0;
-		indices[indexCount++] = 0;
-		indices[indexCount++] = 1;
-		indices[indexCount++] = 1;
-		indices[indexCount++] = 2;
-		indices[indexCount++] = 2;
-		indices[indexCount++] = 3;
-		indices[indexCount++] = 3;
-		indices[indexCount++] = 0;
-
-		indices[indexCount++] = 4;
-		indices[indexCount++] = 5;
-		indices[indexCount++] = 5;
-		indices[indexCount++] = 6;
-		indices[indexCount++] = 6;
-		indices[indexCount++] = 7;
-		indices[indexCount++] = 7;
-		indices[indexCount++] = 4;
-
-		indices[indexCount++] = 0;
-		indices[indexCount++] = 4;
-		indices[indexCount++] = 1;
-		indices[indexCount++] = 5;
-		indices[indexCount++] = 2;
-		indices[indexCount++] = 6;
-		indices[indexCount++] = 3;
-		indices[indexCount++] = 7;
-
-		m_cubeIndicesBuffer->flush(0, kMaxPtrSize);
-		m_cubeIndicesBuffer->unmap();
-	}
-
-	return Error::kNone;
-}
-
-void DebugDrawer2::drawCubes(ConstWeakArray<Mat4> mvps, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, F32 cubeSideSize,
-							 CommandBuffer& cmdb) const
-{
-	// Set the uniforms
-	RebarAllocation unisToken;
-	Mat4* pmvps = static_cast<Mat4*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Mat4) * mvps.getSize(), unisToken));
-
-	if(cubeSideSize == 2.0f)
-	{
-		memcpy(pmvps, &mvps[0], mvps.getSizeInBytes());
-	}
-	else
-	{
-		ANKI_ASSERT(!"TODO");
-	}
-
-	// Setup state
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addMutation("COLOR_TEXTURE", 0);
-	variantInitInfo.addMutation("DITHERED_DEPTH_TEST", U32(ditherFailedDepth != 0));
-	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(variantInitInfo, variant);
-	cmdb.bindShaderProgram(&variant->getProgram());
-
-	cmdb.setPushConstants(&color, sizeof(color));
-
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
-	cmdb.bindVertexBuffer(0, m_cubePositionsBuffer.get(), 0, sizeof(Vec3));
-	cmdb.bindIndexBuffer(m_cubeIndicesBuffer.get(), 0, IndexType::kU16);
-
-	cmdb.bindStorageBuffer(0, 0, &RebarTransientMemoryPool::getSingleton().getBuffer(), unisToken.m_offset, unisToken.m_range);
-
-	cmdb.setLineWidth(lineSize);
-	constexpr U kIndexCount = 12 * 2;
-	cmdb.drawIndexed(PrimitiveTopology::kLines, kIndexCount, mvps.getSize());
-}
-
-void DebugDrawer2::drawLines(ConstWeakArray<Mat4> mvps, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, ConstWeakArray<Vec3> linePositions,
-							 CommandBuffer& cmdb) const
-{
-	ANKI_ASSERT(mvps.getSize() > 0);
-	ANKI_ASSERT(linePositions.getSize() > 0 && (linePositions.getSize() % 2) == 0);
-
-	// Verts
-	RebarAllocation vertsToken;
-	Vec3* verts = static_cast<Vec3*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Vec3) * linePositions.getSize(), vertsToken));
-	memcpy(verts, linePositions.getBegin(), linePositions.getSizeInBytes());
-
-	// Set the uniforms
-	RebarAllocation unisToken;
-	Mat4* pmvps = static_cast<Mat4*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Mat4) * mvps.getSize(), unisToken));
-	memcpy(pmvps, &mvps[0], mvps.getSizeInBytes());
-
-	// Setup state
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addMutation("COLOR_TEXTURE", 0);
-	variantInitInfo.addMutation("DITHERED_DEPTH_TEST", U32(ditherFailedDepth != 0));
-	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(variantInitInfo, variant);
-	cmdb.bindShaderProgram(&variant->getProgram());
-
-	cmdb.setPushConstants(&color, sizeof(color));
-
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
-	cmdb.bindVertexBuffer(0, &RebarTransientMemoryPool::getSingleton().getBuffer(), vertsToken.m_offset, sizeof(Vec3));
-
-	cmdb.bindStorageBuffer(0, 0, &RebarTransientMemoryPool::getSingleton().getBuffer(), unisToken.m_offset, unisToken.m_range);
-
-	cmdb.setLineWidth(lineSize);
-	cmdb.draw(PrimitiveTopology::kLines, linePositions.getSize(), mvps.getSize());
-}
-
-void DebugDrawer2::drawBillboardTextures(const Mat4& projMat, const Mat3x4& viewMat, ConstWeakArray<Vec3> positions, const Vec4& color,
-										 Bool ditherFailedDepth, TextureView* tex, Sampler* sampler, Vec2 billboardSize, CommandBuffer& cmdb) const
-{
-	RebarAllocation positionsToken;
-	Vec3* verts = static_cast<Vec3*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Vec3) * 4, positionsToken));
-
-	verts[0] = Vec3(-0.5f, -0.5f, 0.0f);
-	verts[1] = Vec3(+0.5f, -0.5f, 0.0f);
-	verts[2] = Vec3(-0.5f, +0.5f, 0.0f);
-	verts[3] = Vec3(+0.5f, +0.5f, 0.0f);
-
-	RebarAllocation uvsToken;
-	Vec2* uvs = static_cast<Vec2*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Vec2) * 4, uvsToken));
-
-	uvs[0] = Vec2(0.0f, 0.0f);
-	uvs[1] = Vec2(1.0f, 0.0f);
-	uvs[2] = Vec2(0.0f, 1.0f);
-	uvs[3] = Vec2(1.0f, 1.0f);
-
-	// Set the uniforms
-	RebarAllocation unisToken;
-	Mat4* pmvps = static_cast<Mat4*>(RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(Mat4) * positions.getSize(), unisToken));
-
-	const Mat4 camTrf = Mat4(viewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f)).getInverse();
-	const Vec3 zAxis = camTrf.getZAxis().xyz().getNormalized();
-	Vec3 yAxis = Vec3(0.0f, 1.0f, 0.0f);
-	const Vec3 xAxis = yAxis.cross(zAxis).getNormalized();
-	yAxis = zAxis.cross(xAxis).getNormalized();
-	Mat3 rot;
-	rot.setColumns(xAxis, yAxis, zAxis);
-
-	for(const Vec3& pos : positions)
-	{
-		Mat3 scale = Mat3::getIdentity();
-		scale(0, 0) *= billboardSize.x();
-		scale(1, 1) *= billboardSize.y();
-
-		*pmvps = projMat * Mat4(viewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f)) * Mat4(pos.xyz1(), rot * scale, 1.0f);
-		++pmvps;
-	}
-
-	Vec4* pcolor = reinterpret_cast<Vec4*>(pmvps);
-	*pcolor = color;
-
-	// Setup state
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addMutation("COLOR_TEXTURE", 1);
-	variantInitInfo.addMutation("DITHERED_DEPTH_TEST", U32(ditherFailedDepth != 0));
-	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(variantInitInfo, variant);
-	cmdb.bindShaderProgram(&variant->getProgram());
-
-	cmdb.setPushConstants(&color, sizeof(color));
-
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
-	cmdb.setVertexAttribute(1, 1, Format::kR32G32_Sfloat, 0);
-	cmdb.bindVertexBuffer(0, &RebarTransientMemoryPool::getSingleton().getBuffer(), positionsToken.m_offset, sizeof(Vec3));
-	cmdb.bindVertexBuffer(1, &RebarTransientMemoryPool::getSingleton().getBuffer(), uvsToken.m_offset, sizeof(Vec2));
-
-	cmdb.bindStorageBuffer(0, 0, &RebarTransientMemoryPool::getSingleton().getBuffer(), unisToken.m_offset, unisToken.m_range);
-	cmdb.bindSampler(0, 3, sampler);
-	cmdb.bindTexture(0, 4, tex);
-
-	cmdb.draw(PrimitiveTopology::kTriangleStrip, 4, positions.getSize());
-}
-
-void PhysicsDebugDrawer::drawLines(const Vec3* lines, const U32 vertCount, const Vec4& color)
-{
-	if(color != m_currentColor)
-	{
-		// Color have changed, flush and change the color
-		flush();
-		m_currentColor = color;
-	}
-
-	for(U32 i = 0; i < vertCount; ++i)
-	{
-		if(m_vertCount == m_vertCache.getSize())
-		{
-			flush();
-		}
-
-		m_vertCache[m_vertCount++] = lines[i];
-	}
-}
-
-void PhysicsDebugDrawer::flush()
-{
-	if(m_vertCount > 0)
-	{
-		m_dbg->drawLines(ConstWeakArray<Mat4>(&m_mvp, 1), m_currentColor, 2.0f, false, ConstWeakArray<Vec3>(&m_vertCache[0], m_vertCount), *m_cmdb);
-
-		m_vertCount = 0;
-	}
-}
-
-} // end namespace anki

+ 0 - 107
AnKi/Renderer/Utils/DebugDrawer.h

@@ -1,107 +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/Renderer/Common.h>
-#include <AnKi/Math.h>
-#include <AnKi/Gr.h>
-#include <AnKi/Physics/PhysicsDrawer.h>
-#include <AnKi/Resource/ShaderProgramResource.h>
-#include <AnKi/Util/Array.h>
-
-namespace anki {
-
-// Forward
-class RebarTransientMemoryPool;
-class RebarAllocation;
-
-/// @addtogroup renderer
-/// @{
-
-/// Allocate memory for a line cube and populate it.
-void allocateAndPopulateDebugBox(RebarAllocation& vertsToken, RebarAllocation& indicesToken, U32& indexCount);
-
-/// Debug drawer.
-class DebugDrawer2
-{
-public:
-	Error init();
-
-	Bool isInitialized() const
-	{
-		return m_prog.isCreated();
-	}
-
-	void drawCubes(ConstWeakArray<Mat4> mvps, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, F32 cubeSideSize, CommandBuffer& cmdb) const;
-
-	void drawCube(const Mat4& mvp, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, F32 cubeSideSize, CommandBuffer& cmdb) const
-	{
-		drawCubes(ConstWeakArray<Mat4>(&mvp, 1), color, lineSize, ditherFailedDepth, cubeSideSize, cmdb);
-	}
-
-	void drawLines(ConstWeakArray<Mat4> mvps, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, ConstWeakArray<Vec3> linePositions,
-				   CommandBuffer& cmdb) const;
-
-	void drawLine(const Mat4& mvp, const Vec4& color, F32 lineSize, Bool ditherFailedDepth, const Vec3& a, const Vec3& b, CommandBuffer& cmdb) const
-	{
-		Array<Vec3, 2> points = {a, b};
-		drawLines(ConstWeakArray<Mat4>(&mvp, 1), color, lineSize, ditherFailedDepth, points, cmdb);
-	}
-
-	void drawBillboardTextures(const Mat4& projMat, const Mat3x4& viewMat, ConstWeakArray<Vec3> positions, const Vec4& color, Bool ditherFailedDepth,
-							   TextureView* tex, Sampler* sampler, Vec2 billboardSize, CommandBuffer& cmdb) const;
-
-	void drawBillboardTexture(const Mat4& projMat, const Mat3x4& viewMat, Vec3 position, const Vec4& color, Bool ditherFailedDepth, TextureView* tex,
-							  Sampler* sampler, Vec2 billboardSize, CommandBuffer& cmdb) const
-	{
-		drawBillboardTextures(projMat, viewMat, ConstWeakArray<Vec3>(&position, 1), color, ditherFailedDepth, tex, sampler, billboardSize, cmdb);
-	}
-
-private:
-	ShaderProgramResourcePtr m_prog;
-	BufferPtr m_cubePositionsBuffer;
-	BufferPtr m_cubeIndicesBuffer;
-};
-
-/// Implement physics debug drawer.
-class PhysicsDebugDrawer : public PhysicsDrawer
-{
-public:
-	PhysicsDebugDrawer(const DebugDrawer2* dbg)
-		: m_dbg(dbg)
-	{
-	}
-
-	void start(const Mat4& mvp, CommandBuffer& cmdb)
-	{
-		ANKI_ASSERT(m_vertCount == 0);
-		m_mvp = mvp;
-		m_cmdb.reset(&cmdb);
-	}
-
-	void drawLines(const Vec3* lines, const U32 vertCount, const Vec4& color) final;
-
-	void end()
-	{
-		flush();
-		m_cmdb.reset(nullptr); // This is essential!!!
-	}
-
-private:
-	const DebugDrawer2* m_dbg; ///< The debug drawer
-	Mat4 m_mvp = Mat4::getIdentity();
-	CommandBufferPtr m_cmdb;
-
-	// Use a vertex cache because drawLines() is practically called for every line
-	Array<Vec3, 32> m_vertCache;
-	U32 m_vertCount = 0;
-	Vec4 m_currentColor = Vec4(-1.0f);
-
-	void flush();
-};
-/// @}
-
-} // end namespace anki

+ 3 - 98
AnKi/Renderer/Utils/Drawer.cpp

@@ -18,15 +18,6 @@
 
 namespace anki {
 
-/// Drawer's context
-class RenderableDrawer::Context
-{
-public:
-	Array<const RenderableQueueElement*, kMaxInstanceCount> m_cachedRenderElements;
-	U32 m_cachedRenderElementCount = 0;
-	ShaderProgram* m_lastBoundShaderProgram = nullptr;
-};
-
 RenderableDrawer::~RenderableDrawer()
 {
 }
@@ -35,9 +26,8 @@ void RenderableDrawer::setState(const RenderableDrawerArguments& args, CommandBu
 {
 	// Allocate, set and bind global uniforms
 	{
-		RebarAllocation globalUniformsToken;
-		MaterialGlobalUniforms* globalUniforms = static_cast<MaterialGlobalUniforms*>(
-			RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(MaterialGlobalUniforms), globalUniformsToken));
+		MaterialGlobalUniforms* globalUniforms;
+		const RebarAllocation globalUniformsToken = RebarTransientMemoryPool::getSingleton().allocateFrame(1, globalUniforms);
 
 		globalUniforms->m_viewProjectionMatrix = args.m_viewProjectionMatrix;
 		globalUniforms->m_previousViewProjectionMatrix = args.m_previousViewProjectionMatrix;
@@ -46,8 +36,7 @@ void RenderableDrawer::setState(const RenderableDrawerArguments& args, CommandBu
 		static_assert(sizeof(globalUniforms->m_cameraTransform) == sizeof(args.m_cameraTransform));
 		memcpy(&globalUniforms->m_cameraTransform, &args.m_cameraTransform, sizeof(args.m_cameraTransform));
 
-		cmdb.bindUniformBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kGlobalUniforms),
-							   &RebarTransientMemoryPool::getSingleton().getBuffer(), globalUniformsToken.m_offset, globalUniformsToken.m_range);
+		cmdb.bindUniformBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kGlobalUniforms), globalUniformsToken);
 	}
 
 	// More globals
@@ -65,90 +54,6 @@ void RenderableDrawer::setState(const RenderableDrawerArguments& args, CommandBu
 	cmdb.bindIndexBuffer(&UnifiedGeometryBuffer::getSingleton().getBuffer(), 0, IndexType::kU16);
 }
 
-void RenderableDrawer::drawRange(const RenderableDrawerArguments& args, const RenderableQueueElement* begin, const RenderableQueueElement* end,
-								 CommandBuffer& cmdb)
-{
-	ANKI_ASSERT(begin && end && begin < end);
-
-	setState(args, cmdb);
-
-	Context ctx;
-	for(; begin != end; ++begin)
-	{
-		drawSingle(begin, ctx, cmdb);
-	}
-
-	// Flush the last drawcall
-	flushDrawcall(ctx, cmdb);
-}
-
-void RenderableDrawer::flushDrawcall(Context& ctx, CommandBuffer& cmdb)
-{
-	// Instance buffer
-	RebarAllocation token;
-	GpuSceneRenderableVertex* instances = static_cast<GpuSceneRenderableVertex*>(
-		RebarTransientMemoryPool::getSingleton().allocateFrame(sizeof(GpuSceneRenderableVertex) * ctx.m_cachedRenderElementCount, token));
-	for(U32 i = 0; i < ctx.m_cachedRenderElementCount; ++i)
-	{
-		GpuSceneRenderableVertex renderable = {};
-		renderable.m_worldTransformsOffset = ctx.m_cachedRenderElements[i]->m_worldTransformsOffset;
-		renderable.m_uniformsOffset = ctx.m_cachedRenderElements[i]->m_uniformsOffset;
-		renderable.m_meshLodOffset = ctx.m_cachedRenderElements[i]->m_meshLodOffset;
-		renderable.m_boneTransformsOrParticleEmitterOffset = ctx.m_cachedRenderElements[i]->m_boneTransformsOffset
-																 ? ctx.m_cachedRenderElements[i]->m_boneTransformsOffset
-																 : ctx.m_cachedRenderElements[i]->m_particleEmitterOffset;
-		instances[i] = renderable;
-	}
-
-	cmdb.bindVertexBuffer(0, &RebarTransientMemoryPool::getSingleton().getBuffer(), token.m_offset, sizeof(GpuSceneRenderableVertex),
-						  VertexStepRate::kInstance);
-
-	// Set state
-	const RenderableQueueElement& firstElement = *ctx.m_cachedRenderElements[0];
-
-	if(firstElement.m_program != ctx.m_lastBoundShaderProgram)
-	{
-		cmdb.bindShaderProgram(firstElement.m_program);
-		ctx.m_lastBoundShaderProgram = firstElement.m_program;
-	}
-
-	if(firstElement.m_indexed)
-	{
-		cmdb.drawIndexed(firstElement.m_primitiveTopology, firstElement.m_indexCount, ctx.m_cachedRenderElementCount, firstElement.m_firstIndex);
-	}
-	else
-	{
-		cmdb.draw(firstElement.m_primitiveTopology, firstElement.m_vertexCount, ctx.m_cachedRenderElementCount, firstElement.m_firstVertex);
-	}
-
-	// Rendered something, reset the cached transforms
-	if(ctx.m_cachedRenderElementCount > 1)
-	{
-		ANKI_TRACE_INC_COUNTER(RMergedDrawcalls, ctx.m_cachedRenderElementCount - 1);
-	}
-	ctx.m_cachedRenderElementCount = 0;
-}
-
-void RenderableDrawer::drawSingle(const RenderableQueueElement* renderEl, Context& ctx, CommandBuffer& cmdb)
-{
-	if(ctx.m_cachedRenderElementCount == kMaxInstanceCount)
-	{
-		flushDrawcall(ctx, cmdb);
-	}
-
-	const Bool shouldFlush =
-		ctx.m_cachedRenderElementCount > 0 && !ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount - 1]->canMergeWith(*renderEl);
-
-	if(shouldFlush)
-	{
-		flushDrawcall(ctx, cmdb);
-	}
-
-	// Cache the new one
-	ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount] = renderEl;
-	++ctx.m_cachedRenderElementCount;
-}
-
 void RenderableDrawer::drawMdi(const RenderableDrawerArguments& args, CommandBuffer& cmdb)
 {
 	setState(args, cmdb);

+ 0 - 9
AnKi/Renderer/Utils/Drawer.h

@@ -56,20 +56,11 @@ public:
 
 	~RenderableDrawer();
 
-	void drawRange(const RenderableDrawerArguments& args, const RenderableQueueElement* begin, const RenderableQueueElement* end,
-				   CommandBuffer& cmdb);
-
 	/// Draw using multidraw indirect.
 	void drawMdi(const RenderableDrawerArguments& args, CommandBuffer& cmdb);
 
 private:
-	class Context;
-
 	void setState(const RenderableDrawerArguments& args, CommandBuffer& cmdb);
-
-	void flushDrawcall(Context& ctx, CommandBuffer& cmdb);
-
-	void drawSingle(const RenderableQueueElement* renderEl, Context& ctx, CommandBuffer& cmdb);
 };
 /// @}
 

+ 76 - 41
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -23,14 +23,22 @@ Error GpuVisibility::init()
 {
 	for(MutatorValue hzb = 0; hzb < 2; ++hzb)
 	{
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/GpuVisibility.ankiprogbin",
-									 Array<SubMutation, 3>{{{"HZB_TEST", hzb}, {"STATS", ANKI_STATS_ENABLED}, {"DISTANCE_TEST", 0}}}, m_prog,
-									 m_frustumGrProgs[hzb]));
+		for(MutatorValue gatherAabbs = 0; gatherAabbs < 2; ++gatherAabbs)
+		{
+			ANKI_CHECK(loadShaderProgram(
+				"ShaderBinaries/GpuVisibility.ankiprogbin",
+				Array<SubMutation, 4>{{{"HZB_TEST", hzb}, {"STATS", ANKI_STATS_ENABLED}, {"DISTANCE_TEST", 0}, {"GATHER_AABBS", gatherAabbs}}},
+				m_prog, m_frustumGrProgs[hzb][gatherAabbs]));
+		}
 	}
 
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/GpuVisibility.ankiprogbin",
-								 Array<SubMutation, 3>{{{"HZB_TEST", 0}, {"STATS", ANKI_STATS_ENABLED}, {"DISTANCE_TEST", 1}}}, m_prog,
-								 m_distGrProg));
+	for(MutatorValue gatherAabbs = 0; gatherAabbs < 2; ++gatherAabbs)
+	{
+		ANKI_CHECK(loadShaderProgram(
+			"ShaderBinaries/GpuVisibility.ankiprogbin",
+			Array<SubMutation, 4>{{{"HZB_TEST", 0}, {"STATS", ANKI_STATS_ENABLED}, {"DISTANCE_TEST", 1}, {"GATHER_AABBS", gatherAabbs}}}, m_prog,
+			m_distGrProgs[gatherAabbs]));
+	}
 
 #if ANKI_STATS_ENABLED
 	for(GpuReadbackMemoryAllocation& alloc : m_readbackMemory)
@@ -44,6 +52,8 @@ Error GpuVisibility::init()
 
 void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisibilityInput& in, GpuVisibilityOutput& out)
 {
+	ANKI_ASSERT(in.m_lodReferencePoint.x() != kMaxF32);
+
 	class DistanceTestData
 	{
 	public:
@@ -91,6 +101,28 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 		ANKI_ASSERT(0);
 	}
 
+	if(aabbCount == 0) [[unlikely]]
+	{
+		// Early exit
+
+		out.m_instanceRateRenderablesBuffer = GpuVisibleTransientMemoryPool::getSingleton().allocate(1 * sizeof(GpuSceneRenderable));
+		out.m_drawIndexedIndirectArgsBuffer = GpuVisibleTransientMemoryPool::getSingleton().allocate(1 * sizeof(DrawIndexedIndirectArgs));
+
+		U32* atomics;
+		out.m_mdiDrawCountsBuffer = RebarTransientMemoryPool::getSingleton().allocateFrame<U32>(1, atomics);
+		atomics[0] = 0;
+		out.m_mdiDrawCountsHandle = in.m_rgraph->importBuffer(BufferUsageBit::kNone, out.m_mdiDrawCountsBuffer);
+
+		if(in.m_gatherAabbIndices)
+		{
+			U32* atomic;
+			out.m_visibleAaabbIndicesBuffer = RebarTransientMemoryPool::getSingleton().allocateFrame<U32>(1, atomic);
+			atomic[0] = 0;
+		}
+
+		return;
+	}
+
 	const U32 bucketCount = RenderStateBucketContainer::getSingleton().getBucketCount(in.m_technique);
 
 #if ANKI_STATS_ENABLED
@@ -123,21 +155,28 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 	// Allocate memory for the indirect commands
 	const GpuVisibleTransientMemoryAllocation indirectArgs =
 		GpuVisibleTransientMemoryPool::getSingleton().allocate(aabbCount * sizeof(DrawIndexedIndirectArgs));
-	out.m_drawIndexedIndirectArgsBuffer = {indirectArgs.m_buffer, indirectArgs.m_offset, indirectArgs.m_size};
+	out.m_drawIndexedIndirectArgsBuffer = indirectArgs;
 
 	const GpuVisibleTransientMemoryAllocation instanceRateRenderables =
 		GpuVisibleTransientMemoryPool::getSingleton().allocate(aabbCount * sizeof(GpuSceneRenderable));
-	out.m_instanceRateRenderablesBuffer = {instanceRateRenderables.m_buffer, instanceRateRenderables.m_offset, instanceRateRenderables.m_size};
+	out.m_instanceRateRenderablesBuffer = instanceRateRenderables;
 
 	// Allocate and zero the MDI counts
-	RebarAllocation mdiDrawCounts;
-	U32* atomics = RebarTransientMemoryPool::getSingleton().allocateFrame<U32>(bucketCount, mdiDrawCounts);
-	memset(atomics, 0, mdiDrawCounts.m_range);
-	out.m_mdiDrawCountsBuffer = {&RebarTransientMemoryPool::getSingleton().getBuffer(), mdiDrawCounts.m_offset, mdiDrawCounts.m_range};
+	U32* atomics;
+	RebarAllocation mdiDrawCounts = RebarTransientMemoryPool::getSingleton().allocateFrame(bucketCount, atomics);
+	memset(atomics, 0, mdiDrawCounts.getRange());
+	out.m_mdiDrawCountsBuffer = mdiDrawCounts;
 
 	// Import buffers
-	out.m_mdiDrawCountsHandle = in.m_rgraph->importBuffer(&RebarTransientMemoryPool::getSingleton().getBuffer(), BufferUsageBit::kNone,
-														  mdiDrawCounts.m_offset, mdiDrawCounts.m_range);
+	out.m_mdiDrawCountsHandle = in.m_rgraph->importBuffer(BufferUsageBit::kNone, mdiDrawCounts);
+
+	// Allocate memory for AABB indices
+	if(in.m_gatherAabbIndices)
+	{
+		U32* atomic;
+		out.m_visibleAaabbIndicesBuffer = RebarTransientMemoryPool::getSingleton().allocateFrame(aabbCount + 1, atomic);
+		atomic[0] = 0;
+	}
 
 	// Create the renderpass
 	ComputeRenderPassDescription& pass = in.m_rgraph->newComputeRenderPass(in.m_passesName);
@@ -152,7 +191,8 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 	}
 
 	pass.setWork([this, frustumTestData, distTestData, lodReferencePoint = in.m_lodReferencePoint, lodDistances = in.m_lodDistances,
-				  technique = in.m_technique, mdiDrawCountsHandle = out.m_mdiDrawCountsHandle, instanceRateRenderables, indirectArgs, aabbCount
+				  technique = in.m_technique, mdiDrawCountsHandle = out.m_mdiDrawCountsHandle, instanceRateRenderables, indirectArgs, aabbCount,
+				  visibleAabbsBuffer = out.m_visibleAaabbIndicesBuffer
 #if ANKI_STATS_ENABLED
 				  ,
 				  clearStatsBuffer, clearStatsBufferOffset, writeStatsBuffer, writeStatsBufferOffset
@@ -160,13 +200,15 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 	](RenderPassWorkContext& rpass) {
 		CommandBuffer& cmdb = *rpass.m_commandBuffer;
 
+		const Bool gatherAabbIndices = visibleAabbsBuffer.m_buffer != nullptr;
+
 		if(frustumTestData)
 		{
-			cmdb.bindShaderProgram(m_frustumGrProgs[frustumTestData->m_hzbRt.isValid()].get());
+			cmdb.bindShaderProgram(m_frustumGrProgs[frustumTestData->m_hzbRt.isValid()][gatherAabbIndices].get());
 		}
 		else
 		{
-			cmdb.bindShaderProgram(m_distGrProg.get());
+			cmdb.bindShaderProgram(m_distGrProgs[gatherAabbIndices].get());
 		}
 
 		switch(technique)
@@ -196,8 +238,8 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 
 		cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize);
 
-		cmdb.bindStorageBuffer(0, 3, instanceRateRenderables.m_buffer, instanceRateRenderables.m_offset, instanceRateRenderables.m_size);
-		cmdb.bindStorageBuffer(0, 4, indirectArgs.m_buffer, indirectArgs.m_offset, indirectArgs.m_size);
+		cmdb.bindStorageBuffer(0, 3, instanceRateRenderables);
+		cmdb.bindStorageBuffer(0, 4, indirectArgs);
 
 		U32* offsets = allocateAndBindStorage<U32>(cmdb, 0, 5, RenderStateBucketContainer::getSingleton().getBucketCount(technique));
 		U32 bucketCount = 0;
@@ -258,6 +300,11 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 		cmdb.bindStorageBuffer(0, 11, clearStatsBuffer, clearStatsBufferOffset, sizeof(U32));
 #endif
 
+		if(gatherAabbIndices)
+		{
+			cmdb.bindStorageBuffer(0, 12, visibleAabbsBuffer);
+		}
+
 		dispatchPPCompute(cmdb, 64, 1, aabbCount, 1);
 	});
 }
@@ -297,6 +344,7 @@ Error GpuVisibilityNonRenderables::init()
 
 void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderablesInput& in, GpuVisibilityNonRenderablesOutput& out)
 {
+	ANKI_ASSERT(in.m_viewProjectionMat != Mat4::getZero());
 	RenderGraphDescription& rgraph = *in.m_rgraph;
 
 	U32 objCount = 0;
@@ -371,12 +419,8 @@ void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderable
 	}
 
 	// Allocate memory for the result
-	GpuVisibleTransientMemoryAllocation visibleIndicesAlloc = GpuVisibleTransientMemoryPool::getSingleton().allocate((objCount + 1) * sizeof(U32));
-	out.m_visiblesBuffer.m_buffer = visibleIndicesAlloc.m_buffer;
-	out.m_visiblesBuffer.m_offset = visibleIndicesAlloc.m_offset;
-	out.m_visiblesBuffer.m_range = visibleIndicesAlloc.m_size;
-	out.m_visiblesBufferHandle =
-		rgraph.importBuffer(out.m_visiblesBuffer.m_buffer, BufferUsageBit::kNone, out.m_visiblesBuffer.m_offset, out.m_visiblesBuffer.m_range);
+	out.m_visiblesBuffer = GpuVisibleTransientMemoryPool::getSingleton().allocate((objCount + 1) * sizeof(U32));
+	out.m_visiblesBufferHandle = rgraph.importBuffer(BufferUsageBit::kNone, out.m_visiblesBuffer);
 
 	// Create the renderpass
 	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(in.m_passesName);
@@ -403,37 +447,28 @@ void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderable
 
 		cmdb.bindShaderProgram(m_grProgs[0][objType][needsFeedback].get());
 
-		PtrSize objBufferOffset = 0;
-		PtrSize objBufferRange = 0;
+		BufferOffsetRange objBuffer;
 		switch(objType)
 		{
 		case GpuSceneNonRenderableObjectType::kLight:
-			objBufferOffset = GpuSceneArrays::Light::getSingleton().getGpuSceneOffsetOfArrayBase();
-			objBufferRange = GpuSceneArrays::Light::getSingleton().getElementCount() * GpuSceneArrays::Light::getSingleton().getElementSize();
+			objBuffer = GpuSceneArrays::Light::getSingleton().getBufferOffsetRange();
 			break;
 		case GpuSceneNonRenderableObjectType::kDecal:
-			objBufferOffset = GpuSceneArrays::Decal::getSingleton().getGpuSceneOffsetOfArrayBase();
-			objBufferRange = GpuSceneArrays::Decal::getSingleton().getElementCount() * GpuSceneArrays::Decal::getSingleton().getElementSize();
+			objBuffer = GpuSceneArrays::Decal::getSingleton().getBufferOffsetRange();
 			break;
 		case GpuSceneNonRenderableObjectType::kFogDensityVolume:
-			objBufferOffset = GpuSceneArrays::FogDensityVolume::getSingleton().getGpuSceneOffsetOfArrayBase();
-			objBufferRange = GpuSceneArrays::FogDensityVolume::getSingleton().getElementCount()
-							 * GpuSceneArrays::FogDensityVolume::getSingleton().getElementSize();
+			objBuffer = GpuSceneArrays::FogDensityVolume::getSingleton().getBufferOffsetRange();
 			break;
 		case GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe:
-			objBufferOffset = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
-			objBufferRange = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount()
-							 * GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementSize();
+			objBuffer = GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getBufferOffsetRange();
 			break;
 		case GpuSceneNonRenderableObjectType::kReflectionProbe:
-			objBufferOffset = GpuSceneArrays::ReflectionProbe::getSingleton().getGpuSceneOffsetOfArrayBase();
-			objBufferRange =
-				GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount() * GpuSceneArrays::ReflectionProbe::getSingleton().getElementSize();
+			objBuffer = GpuSceneArrays::ReflectionProbe::getSingleton().getBufferOffsetRange();
 			break;
 		default:
 			ANKI_ASSERT(0);
 		}
-		cmdb.bindStorageBuffer(0, 0, &GpuSceneBuffer::getSingleton().getBuffer(), objBufferOffset, objBufferRange);
+		cmdb.bindStorageBuffer(0, 0, objBuffer);
 
 		GpuVisibilityNonRenderableUniforms unis;
 		Array<Plane, 6> planes;

+ 9 - 4
AnKi/Renderer/Utils/GpuVisibility.h

@@ -20,17 +20,19 @@ public:
 	CString m_passesName;
 	RenderingTechnique m_technique = RenderingTechnique::kCount;
 
-	Vec3 m_lodReferencePoint = Vec3(0.0f);
+	Vec3 m_lodReferencePoint = Vec3(kMaxF32);
 	Array<F32, kMaxLodCount - 1> m_lodDistances = {};
 
 	RenderGraphDescription* m_rgraph = nullptr;
+
+	Bool m_gatherAabbIndices = false; ///< For debug draw.
 };
 
 /// @memberof GpuVisibility
 class FrustumGpuVisibilityInput : public BaseGpuVisibilityInput
 {
 public:
-	Mat4 m_viewProjectionMatrix = Mat4::getIdentity();
+	Mat4 m_viewProjectionMatrix;
 	const RenderTargetHandle* m_hzbRt = nullptr; ///< Optional.
 };
 
@@ -51,6 +53,8 @@ public:
 	BufferOffsetRange m_instanceRateRenderablesBuffer;
 	BufferOffsetRange m_drawIndexedIndirectArgsBuffer;
 	BufferOffsetRange m_mdiDrawCountsBuffer;
+
+	BufferOffsetRange m_visibleAaabbIndicesBuffer; ///< Optional.
 };
 
 /// Performs GPU visibility for some pass.
@@ -62,6 +66,7 @@ public:
 	/// Perform frustum visibility testing.
 	void populateRenderGraph(FrustumGpuVisibilityInput& in, GpuVisibilityOutput& out)
 	{
+		ANKI_ASSERT(in.m_viewProjectionMatrix != Mat4::getZero());
 		populateRenderGraphInternal(false, in, out);
 	}
 
@@ -73,8 +78,8 @@ public:
 
 private:
 	ShaderProgramResourcePtr m_prog;
-	Array<ShaderProgramPtr, 2> m_frustumGrProgs;
-	ShaderProgramPtr m_distGrProg;
+	Array2d<ShaderProgramPtr, 2, 2> m_frustumGrProgs;
+	Array<ShaderProgramPtr, 2> m_distGrProgs;
 
 #if ANKI_STATS_ENABLED
 	Array<GpuReadbackMemoryAllocation, kMaxFramesInFlight> m_readbackMemory;

+ 2 - 2
AnKi/Renderer/Utils/TraditionalDeferredShading.cpp

@@ -144,8 +144,8 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 		}
 		else
 		{
-			// No shadows for the dir light, bind something random
-			rgraphCtx.bindColorTexture(0, 9, info.m_gbufferRenderTargets[0]);
+			// No shadows for the dir light, bind a random depth texture (need depth because validation complains)
+			rgraphCtx.bindTexture(0, 9, info.m_gbufferDepthRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 		}
 
 		cmdb.bindShaderProgram(m_lightGrProg[info.m_computeSpecular].get());

+ 3 - 5
AnKi/Scene/Components/LightComponent.cpp

@@ -166,9 +166,6 @@ Error LightComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 	}
 	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();
 	}
 
@@ -237,8 +234,9 @@ void LightComponent::computeCascadeFrustums(const Frustum& primaryFrustum, Const
 			const Vec3 sphereCenter = sphere.getCenter().xyz();
 			const F32 sphereRadius = sphere.getRadius();
 			const Vec3& lightDir = getDirection();
-			const Vec3 sceneMin = m_dir.m_sceneMin - Vec3(sphereRadius); // Push the bounds a bit
-			const Vec3 sceneMax = m_dir.m_sceneMax + Vec3(sphereRadius);
+			Array<Vec3, 2> sceneBounds = SceneGraph::getSingleton().getSceneBounds();
+			const Vec3 sceneMin = sceneBounds[0] - Vec3(sphereRadius); // Push the bounds a bit
+			const Vec3 sceneMax = sceneBounds[1] + Vec3(sphereRadius);
 
 			// Compute the intersections with the scene bounds
 			Vec3 eye;

+ 0 - 2
AnKi/Scene/Components/LightComponent.h

@@ -172,8 +172,6 @@ private:
 	class Dir
 	{
 	public:
-		Vec3 m_sceneMin = Vec3(-1.0f);
-		Vec3 m_sceneMax = Vec3(1.0f);
 	};
 
 	Point m_point;

+ 26 - 100
AnKi/Scene/Components/ModelComponent.cpp

@@ -17,14 +17,12 @@ namespace anki {
 ModelComponent::ModelComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
 	, m_node(node)
-	, m_spatial(this)
 {
 	m_gpuSceneTransforms.allocate();
 }
 
 ModelComponent::~ModelComponent()
 {
-	m_spatial.removeFromOctree(SceneGraph::getSingleton().getOctree());
 }
 
 void ModelComponent::freeGpuScene()
@@ -222,28 +220,14 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		m_gpuSceneTransforms.uploadToGpuScene(trfs);
 	}
 
-	// Spatial update
-	const Bool spatialNeedsUpdate = moved || resourceUpdated || m_skinComponent;
-	if(spatialNeedsUpdate) [[unlikely]]
+	// Scene bounds update
+	const Bool aabbUpdated = moved || resourceUpdated || m_skinComponent;
+	if(aabbUpdated) [[unlikely]]
 	{
-		Aabb aabbLocal;
-		if(m_skinComponent == nullptr) [[likely]]
-		{
-			aabbLocal = m_model->getBoundingVolume();
-		}
-		else
-		{
-			aabbLocal = m_skinComponent->getBoneBoundingVolumeLocalSpace().getCompoundShape(m_model->getBoundingVolume());
-		}
-
-		const Aabb aabbWorld = aabbLocal.getTransformed(info.m_node->getWorldTransform());
-
-		m_spatial.setBoundingShape(aabbWorld);
+		const Aabb aabbWorld = computeAabbWorldSpace(info.m_node->getWorldTransform());
+		SceneGraph::getSingleton().updateSceneBounds(aabbWorld.getMin().xyz(), aabbWorld.getMax().xyz());
 	}
 
-	const Bool spatialUpdated = m_spatial.update(SceneGraph::getSingleton().getOctree());
-	updated = updated || spatialUpdated;
-
 	// Update the buckets
 	const Bool bucketsNeedUpdate = resourceUpdated || moved != movedLastFrame;
 	if(bucketsNeedUpdate)
@@ -281,19 +265,20 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 	}
 
 	// Upload the AABBs to the GPU scene
-	const Bool gpuSceneAabbsNeedUpdate = spatialNeedsUpdate || bucketsNeedUpdate;
+	const Bool gpuSceneAabbsNeedUpdate = aabbUpdated || bucketsNeedUpdate;
 	if(gpuSceneAabbsNeedUpdate)
 	{
+		const Aabb aabbWorld = computeAabbWorldSpace(info.m_node->getWorldTransform());
+
 		const U32 modelPatchCount = m_model->getModelPatches().getSize();
 		for(U32 i = 0; i < modelPatchCount; ++i)
 		{
 			for(RenderingTechnique t :
 				EnumBitsIterable<RenderingTechnique, RenderingTechniqueBit>(m_patchInfos[i].m_techniques & ~RenderingTechniqueBit::kAllRt))
 			{
-				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_gpuSceneRenderable.getIndex(),
-																					m_patchInfos[i].m_renderStateBucketIndices[t].get());
+				const GpuSceneRenderableAabb gpuVolume =
+					initGpuSceneRenderableAabb(aabbWorld.getMin().xyz(), aabbWorld.getMax().xyz(), m_patchInfos[i].m_gpuSceneRenderable.getIndex(),
+											   m_patchInfos[i].m_renderStateBucketIndices[t].get());
 
 				switch(t)
 				{
@@ -316,80 +301,6 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 	return Error::kNone;
 }
 
-void ModelComponent::setupRenderableQueueElements(U32 lod, RenderingTechnique technique, WeakArray<RenderableQueueElement>& outRenderables) const
-{
-	ANKI_ASSERT(isEnabled());
-
-	outRenderables.setArray(nullptr, 0);
-
-	const RenderingTechniqueBit requestedRenderingTechniqueMask = RenderingTechniqueBit(1 << technique);
-	if(!(m_presentRenderingTechniques & requestedRenderingTechniqueMask))
-	{
-		return;
-	}
-
-	// Allocate renderables
-	U32 renderableCount = 0;
-	for(U32 i = 0; i < m_patchInfos.getSize(); ++i)
-	{
-		renderableCount += !!(m_patchInfos[i].m_techniques & requestedRenderingTechniqueMask);
-	}
-
-	if(renderableCount == 0)
-	{
-		return;
-	}
-
-	RenderableQueueElement* renderables = static_cast<RenderableQueueElement*>(
-		SceneGraph::getSingleton().getFrameMemoryPool().allocate(sizeof(RenderableQueueElement) * renderableCount, alignof(RenderableQueueElement)));
-
-	outRenderables.setArray(renderables, renderableCount);
-
-	// Fill renderables
-	const Bool moved = m_node->movedThisFrame() && technique == RenderingTechnique::kGBuffer;
-	const Bool hasSkin = m_skinComponent != nullptr && m_skinComponent->isEnabled();
-
-	RenderingKey key;
-	key.setLod(lod);
-	key.setRenderingTechnique(technique);
-	key.setVelocity(moved);
-	key.setSkinned(hasSkin);
-
-	renderableCount = 0;
-	for(U32 i = 0; i < m_patchInfos.getSize(); ++i)
-	{
-		if(!(m_patchInfos[i].m_techniques & requestedRenderingTechniqueMask))
-		{
-			continue;
-		}
-
-		RenderableQueueElement& queueElem = renderables[renderableCount];
-
-		const ModelPatch& patch = m_model->getModelPatches()[i];
-
-		ModelRenderingInfo modelInf;
-		patch.getRenderingInfo(key, modelInf);
-
-		queueElem.m_program = modelInf.m_program.get();
-		queueElem.m_worldTransformsOffset = m_gpuSceneTransforms.getGpuSceneOffset();
-		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
-		queueElem.m_meshLodOffset = m_patchInfos[i].m_gpuSceneMeshLods.getGpuSceneOffset() + lod * sizeof(GpuSceneMeshLod);
-		queueElem.m_particleEmitterOffset = 0;
-		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);
-		queueElem.m_indexed = true;
-		queueElem.m_primitiveTopology = PrimitiveTopology::kTriangles;
-
-		queueElem.m_aabbMin = m_spatial.getAabbWorldSpace().getMin().xyz();
-		queueElem.m_aabbMax = m_spatial.getAabbWorldSpace().getMax().xyz();
-
-		queueElem.computeMergeKey();
-
-		++renderableCount;
-	}
-}
-
 void ModelComponent::setupRayTracingInstanceQueueElements(U32 lod, RenderingTechnique technique,
 														  WeakArray<RayTracingInstanceQueueElement>& outInstances) const
 {
@@ -478,4 +389,19 @@ void ModelComponent::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool
 	}
 }
 
+Aabb ModelComponent::computeAabbWorldSpace(const Transform& worldTransform) const
+{
+	Aabb aabbLocal;
+	if(m_skinComponent == nullptr) [[likely]]
+	{
+		aabbLocal = m_model->getBoundingVolume();
+	}
+	else
+	{
+		aabbLocal = m_skinComponent->getBoneBoundingVolumeLocalSpace().getCompoundShape(m_model->getBoundingVolume());
+	}
+
+	return aabbLocal.getTransformed(worldTransform);
+}
+
 } // end namespace anki

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

@@ -44,8 +44,6 @@ public:
 		return m_castsShadow;
 	}
 
-	void setupRenderableQueueElements(U32 lod, RenderingTechnique technique, WeakArray<RenderableQueueElement>& outRenderables) const;
-
 	void setupRayTracingInstanceQueueElements(U32 lod, RenderingTechnique technique, WeakArray<RayTracingInstanceQueueElement>& outRenderables) const;
 
 private:
@@ -66,7 +64,6 @@ private:
 
 	SceneNode* m_node = nullptr;
 	SkinComponent* m_skinComponent = nullptr;
-	Spatial m_spatial;
 
 	ModelResourcePtr m_model;
 
@@ -86,6 +83,8 @@ private:
 	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
 
 	void onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added) override;
+
+	Aabb computeAabbWorldSpace(const Transform& worldTransform) const;
 };
 /// @}
 

+ 11 - 50
AnKi/Scene/Components/ParticleEmitterComponent.cpp

@@ -196,7 +196,6 @@ public:
 
 ParticleEmitterComponent::ParticleEmitterComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
-	, m_spatial(this)
 {
 	// Allocate and populate a quad
 	const U32 vertCount = 4;
@@ -206,24 +205,24 @@ ParticleEmitterComponent::ParticleEmitterComponent(SceneNode* node)
 	m_quadUvs = UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv], vertCount);
 	m_quadIndices = UnifiedGeometryBuffer::getSingleton().allocateFormat(Format::kR16_Uint, indexCount);
 
-	RebarAllocation positionsAlloc;
 	static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition] == Format::kR16G16B16A16_Unorm);
-	U16Vec4* transientPositions = RebarTransientMemoryPool::getSingleton().allocateFrame<U16Vec4>(vertCount, positionsAlloc);
+	WeakArray<U16Vec4> transientPositions;
+	const RebarAllocation positionsAlloc = RebarTransientMemoryPool::getSingleton().allocateFrame(vertCount, transientPositions);
 	transientPositions[0] = U16Vec4(0, 0, 0, 0);
 	transientPositions[1] = U16Vec4(kMaxU16, 0, 0, 0);
 	transientPositions[2] = U16Vec4(kMaxU16, kMaxU16, 0, 0);
 	transientPositions[3] = U16Vec4(0, kMaxU16, 0, 0);
 
-	RebarAllocation uvsAlloc;
 	static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv] == Format::kR32G32_Sfloat);
-	Vec2* transientUvs = RebarTransientMemoryPool::getSingleton().allocateFrame<Vec2>(vertCount, uvsAlloc);
+	WeakArray<Vec2> transientUvs;
+	const RebarAllocation uvsAlloc = RebarTransientMemoryPool::getSingleton().allocateFrame(vertCount, transientUvs);
 	transientUvs[0] = Vec2(0.0f);
 	transientUvs[1] = Vec2(1.0f, 0.0f);
 	transientUvs[2] = Vec2(1.0f, 1.0f);
 	transientUvs[3] = Vec2(0.0f, 1.0f);
 
-	RebarAllocation indicesAlloc;
-	U16* transientIndices = RebarTransientMemoryPool::getSingleton().allocateFrame<U16>(indexCount, indicesAlloc);
+	WeakArray<U16> transientIndices;
+	const RebarAllocation indicesAlloc = RebarTransientMemoryPool::getSingleton().allocateFrame(indexCount, transientIndices);
 	transientIndices[0] = 0;
 	transientIndices[1] = 1;
 	transientIndices[2] = 3;
@@ -236,9 +235,9 @@ ParticleEmitterComponent::ParticleEmitterComponent(SceneNode* node)
 	CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
 	Buffer* srcBuff = &RebarTransientMemoryPool::getSingleton().getBuffer();
 	Buffer* dstBuff = &UnifiedGeometryBuffer::getSingleton().getBuffer();
-	cmdb->copyBufferToBuffer(srcBuff, positionsAlloc.m_offset, dstBuff, m_quadPositions.getOffset(), positionsAlloc.m_range);
-	cmdb->copyBufferToBuffer(srcBuff, uvsAlloc.m_offset, dstBuff, m_quadUvs.getOffset(), uvsAlloc.m_range);
-	cmdb->copyBufferToBuffer(srcBuff, indicesAlloc.m_offset, dstBuff, m_quadIndices.getOffset(), indicesAlloc.m_range);
+	cmdb->copyBufferToBuffer(srcBuff, positionsAlloc.getOffset(), dstBuff, m_quadPositions.getOffset(), positionsAlloc.getRange());
+	cmdb->copyBufferToBuffer(srcBuff, uvsAlloc.getOffset(), dstBuff, m_quadUvs.getOffset(), uvsAlloc.getRange());
+	cmdb->copyBufferToBuffer(srcBuff, indicesAlloc.getOffset(), dstBuff, m_quadIndices.getOffset(), indicesAlloc.getRange());
 	BufferBarrierInfo barrier;
 	barrier.m_buffer = dstBuff;
 	barrier.m_offset = 0;
@@ -251,7 +250,6 @@ ParticleEmitterComponent::ParticleEmitterComponent(SceneNode* node)
 
 ParticleEmitterComponent::~ParticleEmitterComponent()
 {
-	m_spatial.removeFromOctree(SceneGraph::getSingleton().getOctree());
 }
 
 void ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
@@ -354,9 +352,6 @@ Error ParticleEmitterComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 				 scales, alphas, aabbWorld);
 	}
 
-	m_spatial.setBoundingShape(aabbWorld);
-	m_spatial.update(SceneGraph::getSingleton().getOctree());
-
 	// Upload particles to the GPU scene
 	GpuSceneMicroPatcher& patcher = GpuSceneMicroPatcher::getSingleton();
 	if(m_aliveParticleCount > 0)
@@ -437,9 +432,8 @@ Error ParticleEmitterComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 	{
 		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());
+			const GpuSceneRenderableAabb gpuVolume = initGpuSceneRenderableAabb(aabbWorld.getMin().xyz(), aabbWorld.getMax().xyz(),
+																				m_gpuSceneRenderable.getIndex(), m_renderStateBuckets[t].get());
 			switch(t)
 			{
 			case RenderingTechnique::kGBuffer:
@@ -596,37 +590,4 @@ void ParticleEmitterComponent::simulate(Second prevUpdateTime, Second crntTime,
 	}
 }
 
-void ParticleEmitterComponent::setupRenderableQueueElements(RenderingTechnique technique, WeakArray<RenderableQueueElement>& outRenderables) const
-{
-	if(!(m_particleEmitterResource->getMaterial()->getRenderingTechniques() & RenderingTechniqueBit(1 << technique)) || m_aliveParticleCount == 0)
-	{
-		outRenderables.setArray(nullptr, 0);
-		return;
-	}
-
-	RenderingKey key;
-	key.setRenderingTechnique(technique);
-	ShaderProgramPtr prog;
-	m_particleEmitterResource->getRenderingInfo(key, prog);
-
-	RenderableQueueElement* el = static_cast<RenderableQueueElement*>(
-		SceneGraph::getSingleton().getFrameMemoryPool().allocate(sizeof(RenderableQueueElement), alignof(RenderableQueueElement)));
-
-	el->m_mergeKey = 0; // Not mergable
-	el->m_program = prog.get();
-	el->m_worldTransformsOffset = 0;
-	el->m_uniformsOffset = m_gpuSceneUniforms.getOffset();
-	el->m_meshLodOffset = m_gpuSceneMeshLods.getGpuSceneOffset();
-	el->m_particleEmitterOffset = m_gpuSceneParticleEmitter.getGpuSceneOffset();
-	el->m_boneTransformsOffset = 0;
-	el->m_vertexCount = 6 * m_aliveParticleCount;
-	el->m_firstVertex = 0;
-	el->m_indexed = false;
-	el->m_primitiveTopology = PrimitiveTopology::kTriangles;
-	el->m_aabbMin = m_spatial.getAabbWorldSpace().getMin().xyz();
-	el->m_aabbMax = m_spatial.getAabbWorldSpace().getMax().xyz();
-
-	outRenderables.setArray(el, 1);
-}
-
 } // end namespace anki

+ 0 - 4
AnKi/Scene/Components/ParticleEmitterComponent.h

@@ -39,8 +39,6 @@ public:
 		return m_particleEmitterResource.isCreated();
 	}
 
-	void setupRenderableQueueElements(RenderingTechnique technique, WeakArray<RenderableQueueElement>& outRenderables) const;
-
 private:
 	class ParticleBase;
 	class SimpleParticle;
@@ -55,8 +53,6 @@ private:
 
 	ParticleEmitterProperties m_props;
 
-	Spatial m_spatial;
-
 	ParticleEmitterResourcePtr m_particleEmitterResource;
 	SceneDynamicArray<SimpleParticle> m_simpleParticles;
 	SceneDynamicArray<PhysicsParticle> m_physicsParticles;

+ 6 - 0
AnKi/Scene/GpuSceneArray.h

@@ -120,6 +120,12 @@ public:
 		return sizeof(TGpuSceneObject);
 	}
 
+	/// @note Thread-safe
+	BufferOffsetRange getBufferOffsetRange() const
+	{
+		return {&GpuSceneBuffer::getSingleton().getBuffer(), getGpuSceneOffsetOfArrayBase(), getBufferRange()};
+	}
+
 	/// Some bookeeping. Needs to be called once per frame.
 	/// @note Thread-safe
 	void flush()

+ 5 - 2
AnKi/Scene/SceneGraph.cpp

@@ -112,7 +112,7 @@ Error SceneGraph::init(AllocAlignedCallback allocCallback, void* allocCallbackDa
 	m_framePool.init(allocCallback, allocCallbackData, 1_MB, 2.0, 0, true, ANKI_SAFE_ALIGNMENT, "SceneGraphFramePool");
 
 	m_octree = newInstance<Octree>(SceneMemoryPool::getSingleton());
-	m_octree->init(m_sceneMin, m_sceneMax, g_octreeMaxDepthCVar.get());
+	m_octree->init(Vec3(-1000.0f, -200.0f, -1000.0f), Vec3(1000.0f, 200.0f, 1000.0f), g_octreeMaxDepthCVar.get());
 
 	// Init the default main camera
 	ANKI_CHECK(newSceneNode<SceneNode>("mainCamera", m_defaultMainCam));
@@ -390,7 +390,10 @@ Error SceneGraph::updateNodes(UpdateSceneNodesCtx& ctx)
 LightComponent* SceneGraph::getDirectionalLight() const
 {
 	LightComponent* out = (m_dirLights.getSize()) ? m_dirLights[0] : nullptr;
-	ANKI_ASSERT(out->getLightComponentType() == LightComponentType::kDirectional);
+	if(out)
+	{
+		ANKI_ASSERT(out->getLightComponentType() == LightComponentType::kDirectional);
+	}
 	return out;
 }
 

+ 19 - 2
AnKi/Scene/SceneGraph.h

@@ -202,6 +202,22 @@ public:
 		return (m_skyboxes.getSize()) ? m_skyboxes[0] : nullptr;
 	}
 
+	/// @note It's thread-safe.
+	void updateSceneBounds(const Vec3& min, const Vec3& max)
+	{
+		LockGuard lock(m_sceneBoundsMtx);
+		m_sceneMin = m_sceneMin.min(min);
+		m_sceneMax = m_sceneMax.max(max);
+	}
+
+	/// @note It's thread-safe.
+	Array<Vec3, 2> getSceneBounds() const
+	{
+		LockGuard lock(m_sceneBoundsMtx);
+		ANKI_ASSERT(m_sceneMin < m_sceneMax);
+		return {m_sceneMin, m_sceneMax};
+	}
+
 private:
 	class UpdateSceneNodesCtx;
 
@@ -228,8 +244,9 @@ private:
 
 	Octree* m_octree = nullptr;
 
-	Vec3 m_sceneMin = Vec3(-1000.0f, -200.0f, -1000.0f);
-	Vec3 m_sceneMax = Vec3(1000.0f, 200.0f, 1000.0f);
+	Vec3 m_sceneMin = Vec3(kMaxF32);
+	Vec3 m_sceneMax = Vec3(kMinF32);
+	mutable SpinLock m_sceneBoundsMtx;
 
 	Atomic<U32> m_objectsMarkedForDeletionCount = {0};
 

+ 2 - 72
AnKi/Scene/Visibility.cpp

@@ -329,81 +329,11 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 
 		if(compType == ModelComponent::kClassType)
 		{
-			const ModelComponent& modelc = static_cast<ModelComponent&>(comp);
-			const Bool isShadowFrustum = frustumFlags.m_gatherShadowCasterModelComponents;
-			if(!modelc.isEnabled() || (isShadowFrustum && !modelc.getCastsShadow()) || !isInside())
-			{
-				continue;
-			}
-
-			const Plane& nearPlane = primaryFrustum.getViewPlanes()[FrustumPlaneType::kNear];
-			const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, aabb));
-			const U8 lod = computeLod(primaryFrustum, distanceFromCamera);
-
-			WeakArray<RenderableQueueElement> elements;
-			modelc.setupRenderableQueueElements(lod, (isShadowFrustum) ? RenderingTechnique::kDepth : RenderingTechnique::kGBuffer, elements);
-			for(RenderableQueueElement& el : elements)
-			{
-				el.m_distanceFromCamera = distanceFromCamera;
-				*result.m_renderables.newElement() = el;
-			}
-
-			modelc.setupRenderableQueueElements(lod, RenderingTechnique::kForward, elements);
-			for(RenderableQueueElement& el : elements)
-			{
-				el.m_distanceFromCamera = distanceFromCamera;
-				*result.m_forwardShadingRenderables.newElement() = el;
-			}
-
-			if(frustumFlags.m_gatherRayTracingModelComponents)
-			{
-				WeakArray<RayTracingInstanceQueueElement> rtElements;
-				modelc.setupRayTracingInstanceQueueElements(lod, RenderingTechnique::kRtShadow, rtElements);
-
-				for(RayTracingInstanceQueueElement& el : rtElements)
-				{
-					*result.m_rayTracingInstances.newElement() = el;
-				}
-			}
-
-			// Update timestamp
-			ANKI_ASSERT(comp.getTimestamp() > 0);
-			m_frcCtx->m_queueViews[taskId].m_timestamp = max(m_frcCtx->m_queueViews[taskId].m_timestamp, comp.getTimestamp());
+			ANKI_ASSERT(0);
 		}
 		else if(compType == ParticleEmitterComponent::kClassType)
 		{
-			const ParticleEmitterComponent& partemitc = static_cast<ParticleEmitterComponent&>(comp);
-			if(!partemitc.isEnabled() || !isInside())
-			{
-				continue;
-			}
-
-			const Plane& nearPlane = primaryFrustum.getViewPlanes()[FrustumPlaneType::kNear];
-			const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, aabb));
-			Bool updateTimestamp = false;
-
-			WeakArray<RenderableQueueElement> elements;
-			partemitc.setupRenderableQueueElements(RenderingTechnique::kGBuffer, elements);
-			for(RenderableQueueElement& el : elements)
-			{
-				el.m_distanceFromCamera = distanceFromCamera;
-				*result.m_renderables.newElement() = el;
-				updateTimestamp = true;
-			}
-
-			partemitc.setupRenderableQueueElements(RenderingTechnique::kForward, elements);
-			for(RenderableQueueElement& el : elements)
-			{
-				el.m_distanceFromCamera = distanceFromCamera;
-				*result.m_forwardShadingRenderables.newElement() = el;
-			}
-
-			// Update timestamp
-			if(updateTimestamp)
-			{
-				ANKI_ASSERT(comp.getTimestamp() > 0);
-				m_frcCtx->m_queueViews[taskId].m_timestamp = max(m_frcCtx->m_queueViews[taskId].m_timestamp, comp.getTimestamp());
-			}
+			ANKI_ASSERT(0);
 		}
 		else if(compType == LightComponent::kClassType)
 		{

+ 7 - 13
AnKi/Shaders/ClusteredShadingFunctions.hlsl

@@ -13,37 +13,31 @@ Vec3 clusterHeatmap(Cluster cluster, U32 objectTypeMask)
 	U32 maxObjects = 0u;
 	I32 count = 0;
 
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kPointLight)) != 0u)
+	if((objectTypeMask & (1u << (U32)GpuSceneNonRenderableObjectType::kLight)) != 0u)
 	{
-		maxObjects += kMaxVisiblePointLights;
-		count += I32(countbits(cluster.m_pointLightsMask));
+		maxObjects += kMaxVisibleLights;
+		count += I32(countbits(cluster.m_pointLightsMask | cluster.m_spotLightsMask));
 	}
 
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kSpotLight)) != 0u)
-	{
-		maxObjects += kMaxVisibleSpotLights;
-		count += I32(countbits(cluster.m_spotLightsMask));
-	}
-
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kDecal)) != 0u)
+	if((objectTypeMask & (1u << (U32)GpuSceneNonRenderableObjectType::kDecal)) != 0u)
 	{
 		maxObjects += kMaxVisibleDecals;
 		count += I32(countbits(cluster.m_decalsMask));
 	}
 
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kFogDensityVolume)) != 0u)
+	if((objectTypeMask & (1u << (U32)GpuSceneNonRenderableObjectType::kFogDensityVolume)) != 0u)
 	{
 		maxObjects += kMaxVisibleFogDensityVolumes;
 		count += countbits(cluster.m_fogDensityVolumesMask);
 	}
 
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kReflectionProbe)) != 0u)
+	if((objectTypeMask & (1u << (U32)GpuSceneNonRenderableObjectType::kReflectionProbe)) != 0u)
 	{
 		maxObjects += kMaxVisibleReflectionProbes;
 		count += countbits(cluster.m_reflectionProbesMask);
 	}
 
-	if((objectTypeMask & (1u << (U32)ClusteredObjectType::kGlobalIlluminationProbe)) != 0u)
+	if((objectTypeMask & (1u << (U32)GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe)) != 0u)
 	{
 		maxObjects += kMaxVisibleGlobalIlluminationProbes;
 		count += countbits(cluster.m_giProbesMask);

+ 145 - 0
AnKi/Shaders/DbgBillboard.ankiprog

@@ -0,0 +1,145 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki mutator DITHERED_DEPTH_TEST 0 1
+#pragma anki mutator OBJECT_TYPE 0 1 2 3 4 // Same as GpuSceneNonRenderableObjectType
+
+#include <AnKi/Shaders/Common.hlsl>
+#include <AnKi/Shaders/ClusteredShadingFunctions.hlsl>
+#include <AnKi/Shaders/TonemappingFunctions.hlsl>
+
+constexpr F32 kAlpha = 0.95f;
+constexpr F32 kBillboardScale = 0.25f;
+
+struct Uniforms
+{
+	Mat4 m_viewProjMat;
+	Mat3x4 m_camTrf;
+};
+
+[[vk::push_constant]] ConstantBuffer<Uniforms> g_unis;
+
+#if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
+typedef LightUnion ClusteredType;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
+typedef Decal ClusteredType;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
+typedef FogDensityVolume ClusteredType;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
+typedef ReflectionProbe ClusteredType;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
+typedef GlobalIlluminationProbe ClusteredType;
+#else
+#	error See file
+#endif
+
+[[vk::binding(2)]] StructuredBuffer<ClusteredType> g_visibleObjects;
+[[vk::binding(3)]] StructuredBuffer<U32> g_visibleObjectCount;
+
+struct VertOut
+{
+	Vec4 m_svPosition : SV_POSITION;
+	Vec2 m_uv : TEXCOORD;
+	Vec4 m_colorScale : COLOR;
+	nointerpolation U32 m_textureIndex : TEX_INDEX;
+};
+
+#pragma anki start vert
+
+struct VertIn
+{
+	U32 m_svInstanceId : SV_INSTANCEID;
+	U32 m_svVertexId : SV_VERTEXID;
+};
+
+VertOut main(VertIn input)
+{
+	VertOut output;
+
+	output.m_colorScale = Vec4(1.0f, 1.0f, 1.0f, kAlpha);
+	output.m_textureIndex = 0;
+
+	output.m_uv = Vec2(input.m_svVertexId & 1u, ((input.m_svVertexId + 1u) / 3u) & 1u);
+
+	const U32 objCount = g_visibleObjectCount[0];
+
+	if(input.m_svInstanceId < objCount)
+	{
+#if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
+		output.m_colorScale.xyz = reinhardTonemap(g_visibleObjects[input.m_svInstanceId].m_diffuseColor);
+		output.m_textureIndex = g_visibleObjects[input.m_svInstanceId].m_lightType;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_sphereCenter;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
+		const ClusteredType obj = g_visibleObjects[input.m_svInstanceId];
+		const Vec3 localPos = (obj.m_isBox) ? (obj.m_aabbMinOrSphereCenter + obj.m_aabbMaxOrSphereRadius) / 2.0f : obj.m_aabbMinOrSphereCenter;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
+#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
+		const Vec3 localPos = (g_visibleObjects[input.m_svInstanceId].m_aabbMin + g_visibleObjects[input.m_svInstanceId].m_aabbMax) / 2.0f;
+#else
+#	error See file
+#endif
+
+		// Rotate towards the camera and apply translation
+		const Vec3 worldPos = mul(g_unis.m_camTrf, Vec4((output.m_uv * 2.0 - 1.0) * kBillboardScale, 0.0, 0.0)) + localPos;
+
+		output.m_svPosition = mul(g_unis.m_viewProjMat, Vec4(worldPos, 1.0));
+	}
+	else
+	{
+		// Skip this instance by making the vertex degenerate
+		output.m_svPosition = 0.0f;
+	}
+
+	return output;
+}
+#pragma anki end
+
+#pragma anki start frag
+#include <AnKi/Shaders/ImportanceSampling.hlsl>
+
+[[vk::binding(4)]] SamplerState g_trilinearRepeatSampler;
+[[vk::binding(5)]] Texture2D g_tex;
+[[vk::binding(6)]] Texture2D g_tex2;
+
+// NOTE: Don't eliminate the binding because it confuses the descriptor set creation
+#if DITHERED_DEPTH_TEST == 1
+[[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
+[[vk::binding(1)]] Texture2D g_depthRt;
+#endif
+
+Vec4 main(VertOut input) : SV_TARGET0
+{
+	ANKI_MAYBE_UNUSED(input);
+
+	// Check if we should skip the frag
+#if DITHERED_DEPTH_TEST == 1
+	const UVec2 random = rand3DPCG16(UVec3(UVec2(input.m_svPosition.xy), 1)).xy;
+	const Vec2 noise = Vec2(random) / 65536.0;
+	const F32 factor = noise.x * noise.y;
+	Vec2 texSize;
+	g_depthRt.GetDimensions(texSize.x, texSize.y);
+	const Vec2 uv = input.m_svPosition.xy / texSize;
+	const F32 depthRef = g_depthRt.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
+	const Bool depthTestFailed = input.m_svPosition.z >= depthRef;
+	if(depthTestFailed && factor < 0.5)
+	{
+		discard;
+	}
+#endif
+
+	// Write the color
+	if(input.m_textureIndex == 0)
+	{
+		return g_tex.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale;
+	}
+	else
+	{
+		return g_tex2.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale;
+	}
+}
+#pragma anki end

+ 24 - 27
AnKi/Shaders/SceneDebug.ankiprog → AnKi/Shaders/DbgRenderables.ankiprog

@@ -3,45 +3,51 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#pragma anki mutator COLOR_TEXTURE 0 1
 #pragma anki mutator DITHERED_DEPTH_TEST 0 1
 
 #include <AnKi/Shaders/Common.hlsl>
+#include <AnKi/Shaders/Include/GpuSceneTypes.h>
 
 struct Uniforms
 {
 	Vec4 m_color;
+	Mat4 m_viewProjMat;
 };
 
 [[vk::push_constant]] ConstantBuffer<Uniforms> g_uniforms;
 
-[[vk::binding(0)]] StructuredBuffer<Mat4> g_mvps;
-
-struct VertIn
-{
-	[[vk::location(0)]] Vec3 m_position : POSITION;
-#if COLOR_TEXTURE == 1
-	[[vk::location(1)]] Vec2 m_uv : TEXCOORD;
-#endif
-	U32 m_svInstanceId : SV_INSTANCEID;
-};
+[[vk::binding(2)]] StructuredBuffer<GpuSceneRenderableAabb> g_aabbs;
+[[vk::binding(3)]] StructuredBuffer<U32> g_visibleAabbIndices;
 
 struct VertOut
 {
 	Vec4 m_svPosition : SV_POSITION;
-	Vec2 m_uv : TEXCOORD;
 };
 
 #pragma anki start vert
+struct VertIn
+{
+	[[vk::location(0)]] Vec3 m_position : POSITION;
+	U32 m_svInstanceId : SV_INSTANCEID;
+};
 
 VertOut main(VertIn input)
 {
 	VertOut output;
 
-#if COLOR_TEXTURE == 1
-	output.m_uv = input.m_uv;
-#endif
-	output.m_svPosition = mul(g_mvps[input.m_svInstanceId], Vec4(input.m_position, 1.0));
+	const U32 aabbCount = g_visibleAabbIndices[0];
+
+	if(input.m_svInstanceId < aabbCount)
+	{
+		const GpuSceneRenderableAabb aabb = g_aabbs[g_visibleAabbIndices[input.m_svInstanceId + 1]];
+		Vec3 localPos = input.m_position * aabb.m_aabbExtend + aabb.m_sphereCenter;
+		output.m_svPosition = mul(g_uniforms.m_viewProjMat, Vec4(localPos, 1.0));
+	}
+	else
+	{
+		// Skip this instance by making the vertex degenerate
+		output.m_svPosition = 0.0f;
+	}
 
 	return output;
 }
@@ -50,15 +56,10 @@ VertOut main(VertIn input)
 #pragma anki start frag
 #include <AnKi/Shaders/ImportanceSampling.hlsl>
 
-#if COLOR_TEXTURE == 1
-[[vk::binding(3)]] SamplerState g_trilinearRepeatSampler;
-[[vk::binding(4)]] Texture2D g_tex;
-#endif
-
 // NOTE: Don't eliminate the binding because it confuses the descriptor set creation
 #if DITHERED_DEPTH_TEST == 1
-[[vk::binding(1)]] SamplerState g_nearestAnyClampSampler;
-[[vk::binding(2)]] Texture2D g_depthRt;
+[[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
+[[vk::binding(1)]] Texture2D g_depthRt;
 #endif
 
 Vec4 main(VertOut input) : SV_TARGET0
@@ -82,10 +83,6 @@ Vec4 main(VertOut input) : SV_TARGET0
 #endif
 
 	// Write the color
-#if COLOR_TEXTURE == 1
-	return g_tex.Sample(g_trilinearRepeatSampler, input.m_uv) * g_uniforms.m_color;
-#else
 	return g_uniforms.m_color;
-#endif
 }
 #pragma anki end

+ 11 - 0
AnKi/Shaders/GpuVisibility.ankiprog

@@ -6,6 +6,7 @@
 #pragma anki mutator HZB_TEST 0 1
 #pragma anki mutator STATS 0 1
 #pragma anki mutator DISTANCE_TEST 0 1
+#pragma anki mutator GATHER_AABBS 0 1
 
 #pragma anki skip_mutation DISTANCE_TEST 1 HZB_TEST 1
 
@@ -56,6 +57,10 @@ struct DrawIndirectArgsWithPadding
 [[vk::binding(11)]] RWStructuredBuffer<U32> g_testsPassedClear; ///< Some previous value. Will be cleared this frame
 #endif
 
+#if GATHER_AABBS
+[[vk::binding(12)]] RWStructuredBuffer<U32> g_visibleAabbIndices; ///< Indices of the visible AABBs. The 1st element is the count.
+#endif
+
 [numthreads(64, 1, 1)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID)
 {
 	const U32 aabbIdx = svDispatchThreadId.x;
@@ -233,6 +238,12 @@ struct DrawIndirectArgsWithPadding
 		g_instanceRateRenderables[indirectIdx] = instanceVertex;
 	}
 
+#if GATHER_AABBS
+	U32 index;
+	InterlockedAdd(g_visibleAabbIndices[0], 1, index);
+	g_visibleAabbIndices[index + 1] = aabbIdx;
+#endif
+
 	// Now update the stats
 #if STATS
 	const U32 activeLanes = WaveActiveCountBits(true);

+ 0 - 32
AnKi/Shaders/Include/ClusteredShadingTypes.h

@@ -11,31 +11,12 @@
 
 ANKI_BEGIN_NAMESPACE
 
-// Enum of clusterer object types
-enum class ClusteredObjectType : U32
-{
-	kPointLight,
-	kSpotLight,
-	kDecal,
-	kFogDensityVolume,
-	kReflectionProbe,
-	kGlobalIlluminationProbe,
-
-	kCount,
-	kFirst = 0
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ClusteredObjectType)
-
 // Limits
 #if ANKI_CLUSTERED_SHADING_USE_64BIT
 constexpr U32 kMaxVisibleLights = 64u;
-constexpr U32 kMaxVisiblePointLights = 64u;
-constexpr U32 kMaxVisibleSpotLights = 64u;
 constexpr U32 kMaxVisibleDecals = 64u;
 #else
 constexpr U32 kMaxVisibleLights = 32u;
-constexpr U32 kMaxVisiblePointLights = 32u;
-constexpr U32 kMaxVisibleSpotLights = 32u;
 constexpr U32 kMaxVisibleDecals = 32u;
 #endif
 constexpr U32 kMaxVisibleFogDensityVolumes = 16u;
@@ -254,19 +235,6 @@ constexpr U32 kSizeof_Cluster = 2u * sizeof(Vec4);
 static_assert(sizeof(Cluster) == kSizeof_Cluster);
 #endif
 
-// TODO rm
-constexpr ANKI_ARRAY(U32, ClusteredObjectType::kCount, kClusteredObjectSizes) = {
-	sizeof(PointLight), sizeof(SpotLight), sizeof(Decal), sizeof(FogDensityVolume), sizeof(ReflectionProbe), sizeof(GlobalIlluminationProbe)};
-
-// TODO rm
-constexpr ANKI_ARRAY(U32, ClusteredObjectType::kCount, kMaxVisibleClusteredObjects) = {
-#if ANKI_CLUSTERED_SHADING_USE_64BIT
-	64, 64, 64,
-#else
-	32, 32, 32,
-#endif
-	16, 16, 16};
-
 constexpr ANKI_ARRAY(U32, GpuSceneNonRenderableObjectType::kCount, kClusteredObjectSizes2) = {
 	sizeof(LightUnion), sizeof(Decal), sizeof(FogDensityVolume), sizeof(ReflectionProbe), sizeof(GlobalIlluminationProbe)};
 

+ 1 - 0
AnKi/Shaders/Intellisense.hlsl

@@ -7,6 +7,7 @@
 
 #define groupshared
 #define globallycoherent
+#define nointerpolation
 #define SV_DISPATCHTHREADID // gl_GlobalInvocationID
 #define SV_GROUPINDEX // gl_LocalInvocationIndex
 #define SV_GROUPID // gl_WorkGroupID

+ 4 - 2
AnKi/Shaders/TonemappingFunctions.hlsl

@@ -89,13 +89,15 @@ RVec3 tonemap(RVec3 color, RF32 avgLum, RF32 threshold)
 }
 
 // https://graphicrants.blogspot.com/2013/12/tone-mapping.html
-RVec3 reinhardTonemap(RVec3 colour)
+template<typename TVec3>
+TVec3 reinhardTonemap(TVec3 colour)
 {
 	// rgb / (1 + max(rgb))
 	return colour / (1.0 + max(max(colour.r, colour.g), colour.b));
 }
 
-RVec3 invertReinhardTonemap(RVec3 colour)
+template<typename TVec3>
+TVec3 invertReinhardTonemap(TVec3 colour)
 {
 	// rgb / (1 - max(rgb))
 	return colour / max(1.0 / 32768.0, 1.0 - max(max(colour.r, colour.g), colour.b));

+ 7 - 8
AnKi/Ui/Canvas.cpp

@@ -192,16 +192,15 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 	// Allocate index and vertex buffers
 	RebarAllocation vertsToken, indicesToken;
 	{
-		const U32 verticesSize = U32(drawData.TotalVtxCount) * sizeof(ImDrawVert);
-		const U32 indicesSize = U32(drawData.TotalIdxCount) * sizeof(ImDrawIdx);
-
-		if(verticesSize == 0 || indicesSize == 0)
+		if(drawData.TotalVtxCount == 0 || drawData.TotalIdxCount == 0)
 		{
 			return;
 		}
 
-		ImDrawVert* verts = static_cast<ImDrawVert*>(RebarTransientMemoryPool::getSingleton().allocateFrame(verticesSize, vertsToken));
-		ImDrawIdx* indices = static_cast<ImDrawIdx*>(RebarTransientMemoryPool::getSingleton().allocateFrame(indicesSize, indicesToken));
+		ImDrawVert* verts;
+		vertsToken = RebarTransientMemoryPool::getSingleton().allocateFrame(drawData.TotalVtxCount, verts);
+		ImDrawIdx* indices;
+		indicesToken = RebarTransientMemoryPool::getSingleton().allocateFrame(drawData.TotalIdxCount, indices);
 
 		for(I n = 0; n < drawData.CmdListsCount; ++n)
 		{
@@ -220,12 +219,12 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 	const F32 fbHeight = drawData.DisplaySize.y * drawData.FramebufferScale.y;
 	cmdb.setViewport(0, 0, U32(fbWidth), U32(fbHeight));
 
-	cmdb.bindVertexBuffer(0, &RebarTransientMemoryPool::getSingleton().getBuffer(), vertsToken.m_offset, sizeof(ImDrawVert));
+	cmdb.bindVertexBuffer(0, &vertsToken.getBuffer(), vertsToken.getOffset(), sizeof(ImDrawVert));
 	cmdb.setVertexAttribute(0, 0, Format::kR32G32_Sfloat, 0);
 	cmdb.setVertexAttribute(1, 0, Format::kR8G8B8A8_Unorm, sizeof(Vec2) * 2);
 	cmdb.setVertexAttribute(2, 0, Format::kR32G32_Sfloat, sizeof(Vec2));
 
-	cmdb.bindIndexBuffer(&RebarTransientMemoryPool::getSingleton().getBuffer(), indicesToken.m_offset, IndexType::kU16);
+	cmdb.bindIndexBuffer(&indicesToken.getBuffer(), indicesToken.getOffset(), IndexType::kU16);
 
 	// Will project scissor/clipping rectangles into framebuffer space
 	const Vec2 clipOff = drawData.DisplayPos; // (0,0) unless using multi-viewports

+ 6 - 6
Tests/Gr/Gr.cpp

@@ -264,17 +264,17 @@ static Input* input = nullptr;
 
 static void* setUniforms(PtrSize size, CommandBufferPtr& cmdb, U32 set, U32 binding)
 {
-	RebarAllocation token;
-	void* ptr = stagingMem->allocateFrame(size, token);
-	cmdb->bindUniformBuffer(set, binding, &stagingMem->getBuffer(), token.m_offset, token.m_range);
+	void* ptr;
+	const RebarAllocation token = stagingMem->allocateFrame(size, ptr);
+	cmdb->bindUniformBuffer(set, binding, token);
 	return ptr;
 }
 
 static void* setStorage(PtrSize size, CommandBufferPtr& cmdb, U32 set, U32 binding)
 {
-	RebarAllocation token;
-	void* ptr = stagingMem->allocateFrame(size, token);
-	cmdb->bindStorageBuffer(set, binding, &stagingMem->getBuffer(), token.m_offset, token.m_range);
+	void* ptr;
+	const RebarAllocation token = stagingMem->allocateFrame(size, ptr);
+	cmdb->bindStorageBuffer(set, binding, token);
 	return ptr;
 }