Browse Source

Optimize the GPU scene and nuke RenderComponent (good riddance)

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
3ddfd1f390
38 changed files with 421 additions and 926 deletions
  1. 18 0
      AnKi/Config.h.cmake
  2. 4 1
      AnKi/Renderer/Dbg.cpp
  3. 38 59
      AnKi/Renderer/Drawer.cpp
  4. 3 6
      AnKi/Renderer/Drawer.h
  5. 1 2
      AnKi/Renderer/ForwardShading.cpp
  6. 2 4
      AnKi/Renderer/GBuffer.cpp
  7. 2 6
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  8. 2 6
      AnKi/Renderer/ProbeReflections.cpp
  9. 36 7
      AnKi/Renderer/RenderQueue.h
  10. 1 2
      AnKi/Renderer/ShadowMapping.cpp
  11. 14 26
      AnKi/Resource/RenderingKey.h
  12. 0 1
      AnKi/Scene.h
  13. 2 1
      AnKi/Scene/CameraNode.cpp
  14. 3 1
      AnKi/Scene/Components/GpuParticleEmitterComponent.cpp
  15. 120 17
      AnKi/Scene/Components/ModelComponent.cpp
  16. 21 16
      AnKi/Scene/Components/ModelComponent.h
  17. 38 56
      AnKi/Scene/Components/ParticleEmitterComponent.cpp
  18. 6 30
      AnKi/Scene/Components/ParticleEmitterComponent.h
  19. 0 123
      AnKi/Scene/Components/RenderComponent.cpp
  20. 0 127
      AnKi/Scene/Components/RenderComponent.h
  21. 0 1
      AnKi/Scene/Forward.h
  22. 0 18
      AnKi/Scene/GpuParticleEmitterNode.cpp
  23. 0 2
      AnKi/Scene/GpuParticleEmitterNode.h
  24. 1 282
      AnKi/Scene/ModelNode.cpp
  25. 0 11
      AnKi/Scene/ModelNode.h
  26. 1 26
      AnKi/Scene/ParticleEmitterNode.cpp
  27. 0 2
      AnKi/Scene/ParticleEmitterNode.h
  28. 5 1
      AnKi/Scene/PhysicsDebugNode.cpp
  29. 8 2
      AnKi/Scene/SceneNode.h
  30. 56 35
      AnKi/Scene/Visibility.cpp
  31. 1 8
      AnKi/Scene/VisibilityInternal.h
  32. 3 6
      AnKi/Shaders/ForwardShadingGenericTransparent.ankiprog
  33. 2 4
      AnKi/Shaders/ForwardShadingParticles.ankiprog
  34. 3 6
      AnKi/Shaders/GBufferGeneric.ankiprog
  35. 13 8
      AnKi/Shaders/Include/GpuSceneFunctions.h
  36. 3 13
      AnKi/Shaders/Include/GpuSceneTypes.h
  37. 1 1
      AnKi/Shaders/IndirectDiffuse.hlsl
  38. 13 9
      Tools/FormatSource.py

+ 18 - 0
AnKi/Config.h.cmake

@@ -232,6 +232,24 @@ inline int __builtin_ctzll(unsigned long long x)
 #	define ANKI_INTERNAL [[deprecated("This is an AnKi internal interface. Don't use it")]]
 #endif
 
+// Macro that temporarily disable the ANKI_INTERNAL. It's needed in some cases where an ANKI_INTERNAL is called in a
+// header
+#if ANKI_COMPILER_MSVC
+#	define ANKI_CALL_INTERNAL(...) \
+	__pragma(warning(push)) \
+	__pragma(warning(disable:4996)) \
+	__VA_ARGS__ \
+	__pragma(warning(pop))
+#elif ANKI_COMPILER_GCC_COMPATIBLE
+#	define ANKI_CALL_INTERNAL(...) \
+	_Pragma("GCC diagnostic push") \
+	_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+	__VA_ARGS__ \
+	_Pragma("GCC diagnostic pop")
+#else
+#	define ANKI_CALL_INTERNAL(...)
+#endif
+
 // Define the main() function.
 namespace anki {
 void preMainInit();

+ 4 - 1
AnKi/Renderer/Dbg.cpp

@@ -72,7 +72,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	dctx.m_framePool = ctx.m_tempPool;
 	dctx.m_commandBuffer = cmdb;
 	dctx.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
-	dctx.m_key = RenderingKey(RenderingTechnique::kForward, 0, 1, false, false);
+	dctx.m_key = RenderingKey(RenderingTechnique::kForward, 0, false, false);
 	dctx.m_debugDraw = true;
 	dctx.m_debugDrawFlags = m_debugDrawFlags;
 
@@ -83,6 +83,8 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	U32 start, end;
 	splitThreadedProblem(threadId, threadCount, problemSize, start, end);
 
+	// TODO
+#if 0
 	for(U32 i = start; i < end; ++i)
 	{
 		const RenderableQueueElement& el = ctx.m_renderQueue->m_renderables[i];
@@ -99,6 +101,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 			el.m_callback(dctx, a);
 		}
 	}
+#endif
 
 	// Draw probes
 	if(threadId == 0)

+ 38 - 59
AnKi/Renderer/Drawer.cpp

@@ -18,31 +18,20 @@ namespace anki {
 class RenderableDrawer::Context
 {
 public:
-	RenderQueueDrawContext m_queueCtx;
+	CommandBufferPtr m_commandBuffer;
 
-	const RenderableQueueElement* m_renderableElement = nullptr;
+	RebarStagingGpuMemoryPool* m_rebarStagingPool = nullptr;
 
-	Array<RenderableQueueElement, kMaxInstanceCount> m_cachedRenderElements;
-	Array<U8, kMaxInstanceCount> m_cachedRenderElementLods;
-	Array<const void*, kMaxInstanceCount> m_userData;
+	Array<const RenderableQueueElement*, kMaxInstanceCount> m_cachedRenderElements;
 	U32 m_cachedRenderElementCount = 0;
-	U8 m_minLod = 0;
-	U8 m_maxLod = 0;
 };
 
-/// Check if the drawcalls can be merged.
-static Bool canMergeRenderableQueueElements(const RenderableQueueElement& a, const RenderableQueueElement& b)
-{
-	return a.m_callback == b.m_callback && a.m_mergeKey != 0 && a.m_mergeKey == b.m_mergeKey;
-}
-
 RenderableDrawer::~RenderableDrawer()
 {
 }
 
-void RenderableDrawer::drawRange(RenderingTechnique technique, const RenderableDrawerArguments& args,
-								 const RenderableQueueElement* begin, const RenderableQueueElement* end,
-								 CommandBufferPtr& cmdb)
+void RenderableDrawer::drawRange(const RenderableDrawerArguments& args, const RenderableQueueElement* begin,
+								 const RenderableQueueElement* end, CommandBufferPtr& cmdb)
 {
 	ANKI_ASSERT(begin && end && begin < end);
 
@@ -86,30 +75,17 @@ void RenderableDrawer::drawRange(RenderingTechnique technique, const RenderableD
 #undef _ANKI_BIND_TEXTURE_BUFFER
 
 	// Misc
-	cmdb->setVertexAttribute(0, 0, Format::kR32_Uint, 0);
+	cmdb->setVertexAttribute(0, 0, Format::kR32G32B32A32_Uint, 0);
+	cmdb->bindIndexBuffer(args.m_unifiedGeometryBuffer, 0, IndexType::kU16);
 
 	// Set a few things
 	Context ctx;
-	ctx.m_queueCtx.m_viewMatrix = args.m_viewMatrix;
-	ctx.m_queueCtx.m_viewProjectionMatrix = args.m_viewProjectionMatrix;
-	ctx.m_queueCtx.m_projectionMatrix = Mat4::getIdentity(); // TODO
-	ctx.m_queueCtx.m_previousViewProjectionMatrix = args.m_previousViewProjectionMatrix;
-	ctx.m_queueCtx.m_cameraTransform = args.m_cameraTransform;
-	ctx.m_queueCtx.m_rebarStagingPool = m_r->getExternalSubsystems().m_rebarStagingPool;
-	ctx.m_queueCtx.m_commandBuffer = cmdb;
-	ctx.m_queueCtx.m_key = RenderingKey(technique, 0, 1, false, false);
-	ctx.m_queueCtx.m_debugDraw = false;
-	ctx.m_queueCtx.m_sampler = args.m_sampler;
-
-	ANKI_ASSERT(args.m_minLod < kMaxLodCount && args.m_maxLod < kMaxLodCount && args.m_minLod <= args.m_maxLod);
-	ctx.m_minLod = U8(args.m_minLod);
-	ctx.m_maxLod = U8(args.m_maxLod);
+	ctx.m_rebarStagingPool = m_r->getExternalSubsystems().m_rebarStagingPool;
+	ctx.m_commandBuffer = cmdb;
 
 	for(; begin != end; ++begin)
 	{
-		ctx.m_renderableElement = begin;
-
-		drawSingle(ctx);
+		drawSingle(begin, ctx);
 	}
 
 	// Flush the last drawcall
@@ -118,29 +94,39 @@ void RenderableDrawer::drawRange(RenderingTechnique technique, const RenderableD
 
 void RenderableDrawer::flushDrawcall(Context& ctx)
 {
-	ctx.m_queueCtx.m_key.setLod(ctx.m_cachedRenderElementLods[0]);
-	ctx.m_queueCtx.m_key.setInstanceCount(ctx.m_cachedRenderElementCount);
+	CommandBufferPtr cmdb = ctx.m_commandBuffer;
 
 	// Instance buffer
 	RebarGpuMemoryToken token;
-	PackedGpuSceneRenderableInstance* instances =
-		static_cast<PackedGpuSceneRenderableInstance*>(ctx.m_queueCtx.m_rebarStagingPool->allocateFrame(
-			sizeof(PackedGpuSceneRenderableInstance) * ctx.m_cachedRenderElementCount, token));
+	GpuSceneRenderablePacked* instances = static_cast<GpuSceneRenderablePacked*>(ctx.m_rebarStagingPool->allocateFrame(
+		sizeof(GpuSceneRenderablePacked) * ctx.m_cachedRenderElementCount, token));
 	for(U32 i = 0; i < ctx.m_cachedRenderElementCount; ++i)
 	{
-		UnpackedGpuSceneRenderableInstance instance;
-		instance.m_lod = ctx.m_cachedRenderElementLods[0];
-		instance.m_renderableOffset = ctx.m_cachedRenderElements[i].m_renderableOffset;
-		instances[i] = packGpuSceneRenderableInstance(instance);
+		GpuSceneRenderable renderable = {};
+		renderable.m_worldTransformsOffset = ctx.m_cachedRenderElements[i]->m_worldTransformsOffset;
+		renderable.m_uniformsOffset = ctx.m_cachedRenderElements[i]->m_uniformsOffset;
+		renderable.m_geometryOffset = ctx.m_cachedRenderElements[i]->m_geometryOffset;
+		renderable.m_boneTransformsOffset = ctx.m_cachedRenderElements[i]->m_boneTransformsOffset;
+		instances[i] = packGpuSceneRenderable(renderable);
 	}
 
-	ctx.m_queueCtx.m_commandBuffer->bindVertexBuffer(0, ctx.m_queueCtx.m_rebarStagingPool->getBuffer(), token.m_offset,
-													 sizeof(PackedGpuSceneRenderableInstance),
-													 VertexStepRate::kInstance);
+	cmdb->bindVertexBuffer(0, ctx.m_rebarStagingPool->getBuffer(), token.m_offset, sizeof(GpuSceneRenderablePacked),
+						   VertexStepRate::kInstance);
 
-	// Draw
-	ctx.m_cachedRenderElements[0].m_callback(
-		ctx.m_queueCtx, ConstWeakArray<void*>(const_cast<void**>(&ctx.m_userData[0]), ctx.m_cachedRenderElementCount));
+	// Set state
+	const RenderableQueueElement& firstElement = *ctx.m_cachedRenderElements[0];
+	cmdb->bindShaderProgram(ShaderProgramPtr(firstElement.m_program));
+
+	if(firstElement.m_indexed)
+	{
+		cmdb->drawElements(firstElement.m_primitiveTopology, firstElement.m_indexCount, ctx.m_cachedRenderElementCount,
+						   firstElement.m_firstIndex);
+	}
+	else
+	{
+		cmdb->drawArrays(firstElement.m_primitiveTopology, firstElement.m_vertexCount, ctx.m_cachedRenderElementCount,
+						 firstElement.m_firstVertex);
+	}
 
 	// Rendered something, reset the cached transforms
 	if(ctx.m_cachedRenderElementCount > 1)
@@ -150,21 +136,16 @@ void RenderableDrawer::flushDrawcall(Context& ctx)
 	ctx.m_cachedRenderElementCount = 0;
 }
 
-void RenderableDrawer::drawSingle(Context& ctx)
+void RenderableDrawer::drawSingle(const RenderableQueueElement* renderEl, Context& ctx)
 {
 	if(ctx.m_cachedRenderElementCount == kMaxInstanceCount)
 	{
 		flushDrawcall(ctx);
 	}
 
-	const RenderableQueueElement& rqel = *ctx.m_renderableElement;
-
-	const U8 overridenLod = clamp(rqel.m_lod, ctx.m_minLod, ctx.m_maxLod);
-
 	const Bool shouldFlush =
 		ctx.m_cachedRenderElementCount > 0
-		&& (!canMergeRenderableQueueElements(ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount - 1], rqel)
-			|| ctx.m_cachedRenderElementLods[ctx.m_cachedRenderElementCount - 1] != overridenLod);
+		&& !ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount - 1]->canMergeWith(*renderEl);
 
 	if(shouldFlush)
 	{
@@ -172,9 +153,7 @@ void RenderableDrawer::drawSingle(Context& ctx)
 	}
 
 	// Cache the new one
-	ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount] = rqel;
-	ctx.m_cachedRenderElementLods[ctx.m_cachedRenderElementCount] = overridenLod;
-	ctx.m_userData[ctx.m_cachedRenderElementCount] = rqel.m_userData;
+	ctx.m_cachedRenderElements[ctx.m_cachedRenderElementCount] = renderEl;
 	++ctx.m_cachedRenderElementCount;
 }
 

+ 3 - 6
AnKi/Renderer/Drawer.h

@@ -30,9 +30,6 @@ public:
 	SamplerPtr m_sampler;
 	BufferPtr m_gpuSceneBuffer;
 	BufferPtr m_unifiedGeometryBuffer;
-
-	U32 m_minLod = 0;
-	U32 m_maxLod = kMaxLodCount - 1;
 };
 
 /// It uses the render queue to batch and render.
@@ -48,8 +45,8 @@ public:
 
 	~RenderableDrawer();
 
-	void drawRange(RenderingTechnique technique, const RenderableDrawerArguments& args,
-				   const RenderableQueueElement* begin, const RenderableQueueElement* end, CommandBufferPtr& cmdb);
+	void drawRange(const RenderableDrawerArguments& args, const RenderableQueueElement* begin,
+				   const RenderableQueueElement* end, CommandBufferPtr& cmdb);
 
 private:
 	class Context;
@@ -58,7 +55,7 @@ private:
 
 	void flushDrawcall(Context& ctx);
 
-	void drawSingle(Context& ctx);
+	void drawSingle(const RenderableQueueElement* renderEl, Context& ctx);
 };
 /// @}
 

+ 1 - 2
AnKi/Renderer/ForwardShading.cpp

@@ -61,8 +61,7 @@ void ForwardShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgr
 		args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
 		// Start drawing
-		m_r->getSceneDrawer().drawRange(RenderingTechnique::kForward, args,
-										ctx.m_renderQueue->m_forwardShadingRenderables.getBegin() + start,
+		m_r->getSceneDrawer().drawRange(args, ctx.m_renderQueue->m_forwardShadingRenderables.getBegin() + start,
 										ctx.m_renderQueue->m_forwardShadingRenderables.getBegin() + end, cmdb);
 
 		// Restore state

+ 2 - 4
AnKi/Renderer/GBuffer.cpp

@@ -140,8 +140,7 @@ void GBuffer::runInThread(const RenderingContext& ctx, RenderPassWorkContext& rg
 		}
 
 		ANKI_ASSERT(earlyZStart < earlyZEnd && earlyZEnd <= I32(earlyZCount));
-		m_r->getSceneDrawer().drawRange(RenderingTechnique::kGBufferEarlyZ, args,
-										ctx.m_renderQueue->m_earlyZRenderables.getBegin() + earlyZStart,
+		m_r->getSceneDrawer().drawRange(args, ctx.m_renderQueue->m_earlyZRenderables.getBegin() + earlyZStart,
 										ctx.m_renderQueue->m_earlyZRenderables.getBegin() + earlyZEnd, cmdb);
 
 		// Restore state for the color write
@@ -160,8 +159,7 @@ void GBuffer::runInThread(const RenderingContext& ctx, RenderPassWorkContext& rg
 		cmdb->setDepthCompareOperation(CompareOperation::kLessEqual);
 
 		ANKI_ASSERT(colorStart < colorEnd && colorEnd <= I32(ctx.m_renderQueue->m_renderables.getSize()));
-		m_r->getSceneDrawer().drawRange(RenderingTechnique::kGBuffer, args,
-										ctx.m_renderQueue->m_renderables.getBegin() + colorStart,
+		m_r->getSceneDrawer().drawRange(args, ctx.m_renderQueue->m_renderables.getBegin() + colorStart,
 										ctx.m_renderQueue->m_renderables.getBegin() + colorEnd, cmdb);
 	}
 }

+ 2 - 6
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -583,12 +583,10 @@ void IndirectDiffuseProbes::runGBufferInThread(RenderPassWorkContext& rgraphCtx,
 			args.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
 			args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
 			args.m_sampler = m_r->getSamplers().m_trilinearRepeat;
-			args.m_minLod = args.m_maxLod = kMaxLodCount - 1;
 			args.m_gpuSceneBuffer = getExternalSubsystems().m_gpuScenePool->getBuffer();
 			args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
-			m_r->getSceneDrawer().drawRange(RenderingTechnique::kGBuffer, args,
-											rqueue.m_renderables.getBegin() + localStart,
+			m_r->getSceneDrawer().drawRange(args, rqueue.m_renderables.getBegin() + localStart,
 											rqueue.m_renderables.getBegin() + localEnd, cmdb);
 		}
 
@@ -643,12 +641,10 @@ void IndirectDiffuseProbes::runShadowmappingInThread(RenderPassWorkContext& rgra
 			args.m_viewProjectionMatrix = cascadeRenderQueue.m_viewProjectionMatrix;
 			args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
 			args.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
-			args.m_maxLod = args.m_minLod = kMaxLodCount - 1;
 			args.m_gpuSceneBuffer = getExternalSubsystems().m_gpuScenePool->getBuffer();
 			args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
-			m_r->getSceneDrawer().drawRange(RenderingTechnique::kShadow, args,
-											cascadeRenderQueue.m_renderables.getBegin() + localStart,
+			m_r->getSceneDrawer().drawRange(args, cascadeRenderQueue.m_renderables.getBegin() + localStart,
 											cascadeRenderQueue.m_renderables.getBegin() + localEnd, cmdb);
 		}
 	}

+ 2 - 6
AnKi/Renderer/ProbeReflections.cpp

@@ -356,12 +356,10 @@ void ProbeReflections::runGBuffer(RenderPassWorkContext& rgraphCtx)
 			args.m_viewProjectionMatrix = rqueue.m_viewProjectionMatrix;
 			args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care about prev mats
 			args.m_sampler = m_r->getSamplers().m_trilinearRepeat;
-			args.m_minLod = args.m_maxLod = kMaxLodCount - 1;
 			args.m_gpuSceneBuffer = getExternalSubsystems().m_gpuScenePool->getBuffer();
 			args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
-			m_r->getSceneDrawer().drawRange(RenderingTechnique::kGBuffer, args,
-											rqueue.m_renderables.getBegin() + localStart,
+			m_r->getSceneDrawer().drawRange(args, rqueue.m_renderables.getBegin() + localStart,
 											rqueue.m_renderables.getBegin() + localEnd, cmdb);
 		}
 	}
@@ -742,12 +740,10 @@ void ProbeReflections::runShadowMapping(RenderPassWorkContext& rgraphCtx)
 			args.m_viewProjectionMatrix = cascadeRenderQueue.m_viewProjectionMatrix;
 			args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
 			args.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
-			args.m_minLod = args.m_maxLod = kMaxLodCount - 1;
 			args.m_gpuSceneBuffer = getExternalSubsystems().m_gpuScenePool->getBuffer();
 			args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
-			m_r->getSceneDrawer().drawRange(RenderingTechnique::kShadow, args,
-											cascadeRenderQueue.m_renderables.getBegin() + localStart,
+			m_r->getSceneDrawer().drawRange(args, cascadeRenderQueue.m_renderables.getBegin() + localStart,
 											cascadeRenderQueue.m_renderables.getBegin() + localEnd, cmdb);
 		}
 	}

+ 36 - 7
AnKi/Renderer/RenderQueue.h

@@ -54,22 +54,51 @@ using RenderQueueDrawCallback = void (*)(RenderQueueDrawContext& ctx, ConstWeakA
 class RenderableQueueElement final
 {
 public:
-	RenderQueueDrawCallback m_callback;
-	const void* m_userData;
-
-	/// Elements with the same m_mergeKey and same m_callback may be merged and the m_callback will be called once.
-	/// Unless m_mergeKey is zero.
 	U64 m_mergeKey;
 
-	U32 m_renderableOffset;
+	ShaderProgram* m_program;
+
+	U32 m_worldTransformsOffset;
+	U32 m_uniformsOffset;
+	U32 m_geometryOffset;
+	U32 m_boneTransformsOffset;
+
+	union
+	{
+		U32 m_indexCount;
+		U32 m_vertexCount;
+	};
+
+	union
+	{
+		U32 m_firstIndex;
+		U32 m_firstVertex;
+	};
 
 	F32 m_distanceFromCamera; ///< Don't set this. Visibility will.
 
-	U8 m_lod; ///< Don't set this. Visibility will.
+	Bool m_indexed;
+	PrimitiveTopology m_primitiveTopology;
 
 	RenderableQueueElement()
 	{
 	}
+
+	void computeMergeKey()
+	{
+		Array<U64, 5> toHash;
+		toHash[0] = ptrToNumber(m_program);
+		toHash[1] = m_indexed;
+		toHash[2] = m_indexCount;
+		toHash[3] = m_firstIndex;
+		toHash[4] = U64(m_primitiveTopology);
+		m_mergeKey = computeHash(toHash.getBegin(), toHash.getSizeInBytes());
+	}
+
+	Bool canMergeWith(const RenderableQueueElement& b) const
+	{
+		return m_mergeKey != 0 && m_mergeKey == b.m_mergeKey;
+	}
 };
 static_assert(std::is_trivially_destructible<RenderableQueueElement>::value == true);
 

+ 1 - 2
AnKi/Renderer/ShadowMapping.cpp

@@ -615,11 +615,10 @@ void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
 		args.m_viewProjectionMatrix = work.m_renderQueue->m_viewProjectionMatrix;
 		args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
 		args.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
-		args.m_minLod = args.m_maxLod = work.m_renderQueueElementsLod;
 		args.m_gpuSceneBuffer = getExternalSubsystems().m_gpuScenePool->getBuffer();
 		args.m_unifiedGeometryBuffer = getExternalSubsystems().m_unifiedGometryMemoryPool->getBuffer();
 
-		m_r->getSceneDrawer().drawRange(RenderingTechnique::kShadow, args,
+		m_r->getSceneDrawer().drawRange(args,
 										work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement,
 										work.m_renderQueue->m_renderables.getBegin() + work.m_firstRenderableElement
 											+ work.m_renderableElementCount,

+ 14 - 26
AnKi/Resource/RenderingKey.h

@@ -41,24 +41,22 @@ ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(RenderingTechniqueBit)
 class RenderingKey
 {
 public:
-	RenderingKey(RenderingTechnique technique, U32 lod, U32 instanceCount, Bool skinned, Bool velocity)
+	RenderingKey(RenderingTechnique technique, U32 lod, Bool skinned, Bool velocity)
 		: m_technique(technique)
-		, m_lod(U8(lod))
-		, m_instanceCount(U8(instanceCount))
+		, m_lod(lod & 0b11)
 		, m_skinned(skinned)
 		, m_velocity(velocity)
 	{
-		ANKI_ASSERT(instanceCount <= kMaxInstanceCount && instanceCount != 0);
-		ANKI_ASSERT(lod <= kMaxLodCount);
+		ANKI_ASSERT(lod < kMaxLodCount);
 	}
 
 	RenderingKey()
-		: RenderingKey(RenderingTechnique::kFirst, 0, 1, false, false)
+		: RenderingKey(RenderingTechnique::kFirst, 0, false, false)
 	{
 	}
 
 	RenderingKey(const RenderingKey& b)
-		: RenderingKey(b.m_technique, b.m_lod, b.m_instanceCount, b.m_skinned, b.m_velocity)
+		: RenderingKey(b.m_technique, b.m_lod, b.m_skinned, b.m_velocity)
 	{
 	}
 
@@ -70,8 +68,8 @@ public:
 
 	Bool operator==(const RenderingKey& b) const
 	{
-		return m_technique == b.m_technique && m_lod == b.m_lod && m_instanceCount == b.m_instanceCount
-			   && m_skinned == b.m_skinned && m_velocity == b.m_velocity;
+		return m_technique == b.m_technique && m_lod == b.m_lod && m_skinned == b.m_skinned
+			   && m_velocity == b.m_velocity;
 	}
 
 	RenderingTechnique getRenderingTechnique() const
@@ -92,18 +90,7 @@ public:
 	void setLod(U32 lod)
 	{
 		ANKI_ASSERT(lod < kMaxLodCount);
-		m_lod = U8(lod);
-	}
-
-	U32 getInstanceCount() const
-	{
-		return m_instanceCount;
-	}
-
-	void setInstanceCount(U32 instanceCount)
-	{
-		ANKI_ASSERT(instanceCount <= kMaxInstanceCount && instanceCount > 0);
-		m_instanceCount = U8(instanceCount);
+		m_lod = lod & 0b11;
 	}
 
 	Bool getSkinned() const
@@ -128,12 +115,13 @@ public:
 
 private:
 	RenderingTechnique m_technique;
-	U8 m_lod;
-	U8 m_instanceCount;
-	Bool m_skinned;
-	Bool m_velocity;
+	U8 m_lod : 2;
+	Bool m_skinned : 1;
+	Bool m_velocity : 1;
+
+	static_assert(kMaxLodCount <= 3, "m_lod only reserves 2 bits so make sure all LODs will fit");
 };
 
-static_assert(sizeof(RenderingKey) == sizeof(U8) * 5, "RenderingKey needs to be packed because of hashing");
+static_assert(sizeof(RenderingKey) == sizeof(U8) * 2, "RenderingKey needs to be packed because of hashing");
 
 } // end namespace anki

+ 0 - 1
AnKi/Scene.h

@@ -24,7 +24,6 @@
 #include <AnKi/Scene/SkyboxNode.h>
 
 #include <AnKi/Scene/Components/MoveComponent.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 #include <AnKi/Scene/Components/LensFlareComponent.h>
 #include <AnKi/Scene/Components/PlayerControllerComponent.h>
 #include <AnKi/Scene/Components/SkinComponent.h>

+ 2 - 1
AnKi/Scene/CameraNode.cpp

@@ -61,7 +61,8 @@ void CameraNode::initCommon(FrustumType frustumType)
 	FrustumComponent* frc = newComponent<FrustumComponent>();
 	frc->setFrustumType(frustumType);
 	frc->setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::kAll
-								   ^ FrustumComponentVisibilityTestFlag::kAllRayTracing);
+								   ^ (FrustumComponentVisibilityTestFlag::kAllRayTracing
+									  | FrustumComponentVisibilityTestFlag::kShadowCasterRenderComponents));
 	frc->setLodDistance(0, getExternalSubsystems().m_config->getLod0MaxDistance());
 	frc->setLodDistance(1, getExternalSubsystems().m_config->getLod1MaxDistance());
 	frc->setShadowCascadeCount(getExternalSubsystems().m_config->getSceneShadowCascadeCount());

+ 3 - 1
AnKi/Scene/Components/GpuParticleEmitterComponent.cpp

@@ -6,7 +6,6 @@
 #include <AnKi/Scene/Components/GpuParticleEmitterComponent.h>
 #include <AnKi/Scene/SceneNode.h>
 #include <AnKi/Scene/SceneGraph.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Shaders/Include/ParticleTypes.h>
 
@@ -192,6 +191,8 @@ void GpuParticleEmitterComponent::simulate(GenericGpuComputeJobQueueElementConte
 
 void GpuParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
 {
+	// TODO
+#if 0
 	if(ANKI_UNLIKELY(!m_particleEmitterResource.isCreated()))
 	{
 		return;
@@ -258,6 +259,7 @@ void GpuParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
 			cmdb->setDepthCompareOperation(CompareOperation::kLess);
 		}
 	}
+#endif
 }
 
 Error GpuParticleEmitterComponent::update(SceneComponentUpdateInfo& info, Bool& updated)

+ 120 - 17
AnKi/Scene/Components/ModelComponent.cpp

@@ -6,6 +6,8 @@
 #include <AnKi/Scene/Components/ModelComponent.h>
 #include <AnKi/Scene/SceneNode.h>
 #include <AnKi/Scene/SceneGraph.h>
+#include <AnKi/Scene/Components/MoveComponent.h>
+#include <AnKi/Scene/Components/SkinComponent.h>
 #include <AnKi/Resource/ModelResource.h>
 #include <AnKi/Resource/ResourceManager.h>
 
@@ -21,13 +23,11 @@ ModelComponent::ModelComponent(SceneNode* node)
 
 ModelComponent::~ModelComponent()
 {
-	m_modelPatchMergeKeys.destroy(m_node->getMemoryPool());
-
 	GpuSceneMemoryPool& gpuScene = *getExternalSubsystems(*m_node).m_gpuSceneMemoryPool;
 	gpuScene.free(m_gpuSceneMeshLods);
 	gpuScene.free(m_gpuSceneUniforms);
 
-	m_gpuSceneUniformsOffsetPerPatch.destroy(m_node->getMemoryPool());
+	m_patchInfos.destroy(m_node->getMemoryPool());
 }
 
 Error ModelComponent::loadModelResource(CString filename)
@@ -39,28 +39,19 @@ Error ModelComponent::loadModelResource(CString filename)
 	m_model = std::move(rsrc);
 	const U32 modelPatchCount = m_model->getModelPatches().getSize();
 
-	m_modelPatchMergeKeys.destroy(m_node->getMemoryPool());
-	m_modelPatchMergeKeys.create(m_node->getMemoryPool(), modelPatchCount);
-
-	for(U32 i = 0; i < modelPatchCount; ++i)
-	{
-		Array<U64, 2> toHash;
-		toHash[0] = i;
-		toHash[1] = m_model->getUuid();
-		m_modelPatchMergeKeys[i] = computeHash(&toHash[0], sizeof(toHash));
-	}
+	m_castsShadow = false;
 
 	// GPU scene allocations
 	GpuSceneMemoryPool& gpuScene = *getExternalSubsystems(*m_node).m_gpuSceneMemoryPool;
 
 	gpuScene.free(m_gpuSceneMeshLods);
-	gpuScene.allocate(sizeof(GpuSceneMeshLod) * kMaxLodCount * m_modelPatchMergeKeys.getSize(), 4, m_gpuSceneMeshLods);
+	gpuScene.allocate(sizeof(GpuSceneMeshLod) * kMaxLodCount * modelPatchCount, 4, m_gpuSceneMeshLods);
 
 	U32 uniformsSize = 0;
-	m_gpuSceneUniformsOffsetPerPatch.resize(m_node->getMemoryPool(), modelPatchCount);
+	m_patchInfos.resize(m_node->getMemoryPool(), modelPatchCount);
 	for(U32 i = 0; i < modelPatchCount; ++i)
 	{
-		m_gpuSceneUniformsOffsetPerPatch[i] = uniformsSize;
+		m_patchInfos[i].m_gpuSceneUniformsOffset = uniformsSize;
 
 		const U32 size = U32(m_model->getModelPatches()[i].getMaterial()->getPrefilledLocalUniforms().getSizeInBytes());
 		ANKI_ASSERT((size % 4) == 0);
@@ -72,7 +63,18 @@ Error ModelComponent::loadModelResource(CString filename)
 
 	for(U32 i = 0; i < modelPatchCount; ++i)
 	{
-		m_gpuSceneUniformsOffsetPerPatch[i] += U32(m_gpuSceneUniforms.m_offset);
+		m_patchInfos[i].m_gpuSceneUniformsOffset += U32(m_gpuSceneUniforms.m_offset);
+	}
+
+	// Some other per-patch init
+	m_presentRenderingTechniques = RenderingTechniqueBit::kNone;
+	for(U32 i = 0; i < modelPatchCount; ++i)
+	{
+		m_patchInfos[i].m_techniques = m_model->getModelPatches()[i].getMaterial()->getRenderingTechniques();
+
+		m_castsShadow = m_castsShadow || m_model->getModelPatches()[i].getMaterial()->castsShadow();
+
+		m_presentRenderingTechniques |= m_model->getModelPatches()[i].getMaterial()->getRenderingTechniques();
 	}
 
 	return Error::kNone;
@@ -157,4 +159,105 @@ Error ModelComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 	return Error::kNone;
 }
 
+void ModelComponent::setupRenderableQueueElements(U32 lod, RenderingTechnique technique, StackMemoryPool& tmpPool,
+												  WeakArray<RenderableQueueElement>& outRenderables) const
+{
+	ANKI_ASSERT(isEnabled());
+	ANKI_ASSERT(m_moveComponent);
+
+	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*>(
+		tmpPool.allocate(sizeof(RenderableQueueElement) * renderableCount, alignof(RenderableQueueElement)));
+
+	outRenderables.setArray(renderables, renderableCount);
+
+	// Fill renderables
+	const Bool moved = m_moveComponent->wasDirtyThisFrame() && 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_moveComponent->getTransformsGpuSceneOffset();
+		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
+		queueElem.m_geometryOffset =
+			U32(m_gpuSceneMeshLods.m_offset + sizeof(GpuSceneMeshLod) * (kMaxLodCount * i + lod));
+		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.computeMergeKey();
+
+		++renderableCount;
+	}
+}
+
+void ModelComponent::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added)
+{
+	ANKI_ASSERT(other);
+
+	if(added)
+	{
+		if(other->getClassId() == MoveComponent::getStaticClassId())
+		{
+			m_moveComponent = static_cast<MoveComponent*>(other);
+		}
+		else if(other->getClassId() == SkinComponent::getStaticClassId())
+		{
+			m_skinComponent = static_cast<SkinComponent*>(other);
+		}
+	}
+	else
+	{
+		if(other == m_moveComponent)
+		{
+			m_moveComponent = nullptr;
+		}
+		else if(other == m_skinComponent)
+		{
+			m_skinComponent = nullptr;
+		}
+	}
+}
+
 } // end namespace anki

+ 21 - 16
AnKi/Scene/Components/ModelComponent.h

@@ -8,6 +8,7 @@
 #include <AnKi/Scene/Components/SceneComponent.h>
 #include <AnKi/Resource/Forward.h>
 #include <AnKi/Util/WeakArray.h>
+#include <AnKi/Renderer/RenderQueue.h>
 
 namespace anki {
 
@@ -31,39 +32,43 @@ public:
 		return m_model;
 	}
 
-	ConstWeakArray<U64> getRenderMergeKeys() const
-	{
-		return m_modelPatchMergeKeys;
-	}
-
 	Bool isEnabled() const
 	{
 		return m_model.isCreated();
 	}
 
-	U32 getGpuSceneMeshLodsOffset() const
+	Bool getCastsShadow() const
 	{
-		ANKI_ASSERT((m_gpuSceneMeshLods.m_offset % 4) == 0);
-		return U32(m_gpuSceneMeshLods.m_offset);
+		return m_castsShadow;
 	}
 
-	U32 getUniformsGpuSceneOffset(U32 meshPatchIdx) const
-	{
-		return m_gpuSceneUniformsOffsetPerPatch[meshPatchIdx];
-	}
+	void setupRenderableQueueElements(U32 lod, RenderingTechnique technique, StackMemoryPool& tmpPool,
+									  WeakArray<RenderableQueueElement>& outRenderables) const;
 
 private:
+	class PatchInfo
+	{
+	public:
+		U32 m_gpuSceneUniformsOffset;
+		RenderingTechniqueBit m_techniques;
+	};
+
 	SceneNode* m_node = nullptr;
+	MoveComponent* m_moveComponent = nullptr;
+	SkinComponent* m_skinComponent = nullptr;
 	ModelResourcePtr m_model;
 
-	DynamicArray<U64> m_modelPatchMergeKeys;
-	Bool m_dirty = true;
-
 	SegregatedListsGpuMemoryPoolToken m_gpuSceneMeshLods;
 	SegregatedListsGpuMemoryPoolToken m_gpuSceneUniforms;
-	DynamicArray<U32> m_gpuSceneUniformsOffsetPerPatch;
+	DynamicArray<PatchInfo> m_patchInfos;
+
+	Bool m_dirty = true;
+	Bool m_castsShadow = false;
+	RenderingTechniqueBit m_presentRenderingTechniques = RenderingTechniqueBit::kNone;
 
 	Error update(SceneComponentUpdateInfo& info, Bool& updated);
+
+	void onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added);
 };
 /// @}
 

+ 38 - 56
AnKi/Scene/Components/ParticleEmitterComponent.cpp

@@ -6,7 +6,7 @@
 #include <AnKi/Scene/Components/ParticleEmitterComponent.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Scene/SceneNode.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
+#include <AnKi/Scene/Components/MoveComponent.h>
 #include <AnKi/Resource/ParticleEmitterResource.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Physics/PhysicsBody.h>
@@ -216,13 +216,6 @@ ParticleEmitterComponent::~ParticleEmitterComponent()
 
 Error ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
 {
-	// Create the debug drawer
-	if(!m_dbgImage.isCreated())
-	{
-		ANKI_CHECK(getExternalSubsystems(*m_node).m_resourceManager->loadResource(
-			"EngineAssets/ParticleEmitter.ankitex", m_dbgImage));
-	}
-
 	// Load
 	ANKI_CHECK(getExternalSubsystems(*m_node).m_resourceManager->loadResource(filename, m_particleEmitterResource));
 	m_props = m_particleEmitterResource->getProperties();
@@ -411,7 +404,8 @@ void ParticleEmitterComponent::simulate(Second prevUpdateTime, Second crntTime,
 				continue;
 			}
 
-			particle.revive(m_props, m_transform, crntTime);
+			particle.revive(
+				m_props, (m_moveComponent) ? m_moveComponent->getWorldTransform() : Transform::getIdentity(), crntTime);
 
 			// do the rest
 			++particleCount;
@@ -429,64 +423,52 @@ void ParticleEmitterComponent::simulate(Second prevUpdateTime, Second crntTime,
 	}
 }
 
-void ParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
+void ParticleEmitterComponent::setupRenderableQueueElements(RenderingTechnique technique, StackMemoryPool& tmpPool,
+															WeakArray<RenderableQueueElement>& outRenderables) const
 {
-	// Early exit
-	if(ANKI_UNLIKELY(m_aliveParticleCount == 0))
+	if(!(m_particleEmitterResource->getMaterial()->getRenderingTechniques() & RenderingTechniqueBit(1 << technique))
+	   || m_aliveParticleCount == 0)
 	{
+		outRenderables.setArray(nullptr, 0);
 		return;
 	}
 
-	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
+	RenderingKey key;
+	key.setRenderingTechnique(technique);
+	ShaderProgramPtr prog;
+	m_particleEmitterResource->getRenderingInfo(key, prog);
+
+	RenderableQueueElement* el = static_cast<RenderableQueueElement*>(
+		tmpPool.allocate(sizeof(RenderableQueueElement), alignof(RenderableQueueElement)));
+
+	el->m_mergeKey = 0; // Not mergable
+	el->m_program = prog.get();
+	el->m_worldTransformsOffset = m_moveComponent->getTransformsGpuSceneOffset();
+	el->m_uniformsOffset = U32(m_gpuSceneUniforms.m_offset);
+	el->m_geometryOffset = U32(m_gpuSceneParticles.m_offset);
+	el->m_boneTransformsOffset = 0;
+	el->m_vertexCount = 6 * m_aliveParticleCount;
+	el->m_firstVertex = 0;
+	el->m_indexed = false;
+	el->m_primitiveTopology = PrimitiveTopology::kTriangles;
+
+	outRenderables.setArray(el, 1);
+}
 
-	if(!ctx.m_debugDraw)
+void ParticleEmitterComponent::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added)
+{
+	if(added)
 	{
-		// Program
-		ShaderProgramPtr prog;
-		m_particleEmitterResource->getRenderingInfo(ctx.m_key, prog);
-		cmdb->bindShaderProgram(prog);
-
-		// Draw
-		cmdb->drawArrays(PrimitiveTopology::kTriangles, 6 * m_aliveParticleCount);
+		if(other->getClassId() == MoveComponent::getStaticClassId())
+		{
+			m_moveComponent = static_cast<MoveComponent*>(other);
+		}
 	}
 	else
 	{
-		const Vec4 tsl = (m_worldBoundingVolume.getMin() + m_worldBoundingVolume.getMax()) / 2.0f;
-		const Vec4 scale = (m_worldBoundingVolume.getMax() - m_worldBoundingVolume.getMin()) / 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_viewProjectionMatrix * Mat4(tsl.xyz1(), Mat3::getIdentity() * nonUniScale, 1.0f);
-
-		const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDepthTestOn);
-		if(enableDepthTest)
-		{
-			cmdb->setDepthCompareOperation(CompareOperation::kLess);
-		}
-		else
-		{
-			cmdb->setDepthCompareOperation(CompareOperation::kAlways);
-		}
-
-		m_node->getSceneGraph().getDebugDrawer().drawCubes(
-			ConstWeakArray<Mat4>(&mvp, 1), Vec4(1.0f, 0.0f, 1.0f, 1.0f), 2.0f,
-			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDitheredDepthTestOn), 2.0f, *ctx.m_rebarStagingPool,
-			cmdb);
-
-		const Vec3 pos = m_transform.getOrigin().xyz();
-		m_node->getSceneGraph().getDebugDrawer().drawBillboardTextures(
-			ctx.m_projectionMatrix, ctx.m_viewMatrix, ConstWeakArray<Vec3>(&pos, 1), Vec4(1.0f),
-			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDitheredDepthTestOn), m_dbgImage->getTextureView(),
-			ctx.m_sampler, Vec2(0.75f), *ctx.m_rebarStagingPool, ctx.m_commandBuffer);
-
-		// Restore state
-		if(!enableDepthTest)
+		if(m_moveComponent == other)
 		{
-			cmdb->setDepthCompareOperation(CompareOperation::kLess);
+			m_moveComponent = nullptr;
 		}
 	}
 }

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

@@ -14,6 +14,7 @@ namespace anki {
 
 // Forward
 class RenderQueueDrawContext;
+class RenderableQueueElement;
 
 /// @addtogroup scene
 /// @{
@@ -30,42 +31,18 @@ public:
 
 	Error loadParticleEmitterResource(CString filename);
 
-	void setWorldTransform(const Transform& transform)
-	{
-		m_transform = transform;
-	}
-
 	const Aabb& getAabbWorldSpace() const
 	{
 		return m_worldBoundingVolume;
 	}
 
-	ParticleEmitterResourcePtr getParticleEmitterResource() const
-	{
-		return m_particleEmitterResource;
-	}
-
-	/// RenderComponent callback. The userData is the component.
-	static void drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		ANKI_ASSERT(userData.getSize() == 1);
-		static_cast<const ParticleEmitterComponent*>(userData[0])->draw(ctx);
-	}
-
 	Bool isEnabled() const
 	{
 		return m_particleEmitterResource.isCreated();
 	}
 
-	U32 getGpuSceneParticlesOffset() const
-	{
-		return U32(m_gpuSceneParticles.m_offset);
-	}
-
-	U32 getGpuSceneUniforms() const
-	{
-		return U32(m_gpuSceneUniforms.m_offset);
-	}
+	void setupRenderableQueueElements(RenderingTechnique technique, StackMemoryPool& tmpPool,
+									  WeakArray<RenderableQueueElement>& outRenderables) const;
 
 private:
 	class ParticleBase;
@@ -81,6 +58,8 @@ private:
 
 	SceneNode* m_node = nullptr;
 
+	MoveComponent* m_moveComponent = nullptr;
+
 	ParticleEmitterProperties m_props;
 
 	ParticleEmitterResourcePtr m_particleEmitterResource;
@@ -90,11 +69,8 @@ private:
 	U32 m_aliveParticleCount = 0;
 	Bool m_resourceUpdated = true;
 
-	Transform m_transform = Transform::getIdentity();
 	Aabb m_worldBoundingVolume = Aabb(Vec3(-1.0f), Vec3(1.0f));
 
-	ImageResourcePtr m_dbgImage;
-
 	SegregatedListsGpuMemoryPoolToken m_gpuScenePositions;
 	SegregatedListsGpuMemoryPoolToken m_gpuSceneAlphas;
 	SegregatedListsGpuMemoryPoolToken m_gpuSceneScales;
@@ -109,7 +85,7 @@ private:
 	void simulate(Second prevUpdateTime, Second crntTime, WeakArray<TParticle> particles, Vec3*& positions,
 				  F32*& scales, F32*& alphas);
 
-	void draw(RenderQueueDrawContext& ctx) const;
+	void onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added);
 };
 /// @}
 

+ 0 - 123
AnKi/Scene/Components/RenderComponent.cpp

@@ -1,123 +0,0 @@
-// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Scene/Components/RenderComponent.h>
-#include <AnKi/Scene/SceneNode.h>
-#include <AnKi/Resource/ImageResource.h>
-#include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Util/Logger.h>
-
-namespace anki {
-
-ANKI_SCENE_COMPONENT_STATICS(RenderComponent, 100.0f)
-
-RenderComponent::RenderComponent(SceneNode* node)
-	: SceneComponent(node, getStaticClassId())
-{
-	getExternalSubsystems(*node).m_gpuSceneMemoryPool->allocate(sizeof(GpuSceneRenderable), sizeof(U32),
-																m_gpuSceneRenderable);
-}
-
-void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, const RenderQueueDrawContext& ctx,
-											   ConstWeakArray<Mat3x4> transforms, ConstWeakArray<Mat3x4> prevTransforms,
-											   RebarStagingGpuMemoryPool& alloc,
-											   const Vec4& positionScaleAndTranslation)
-{
-	ANKI_ASSERT(transforms.getSize() <= kMaxInstanceCount);
-	ANKI_ASSERT(prevTransforms.getSize() == transforms.getSize());
-
-	CommandBufferPtr cmdb = ctx.m_commandBuffer;
-
-	const U32 set = kMaterialSetLocal;
-
-	// Fill the RenderableGpuView
-	const U32 renderableGpuViewsUboSize = sizeof(RenderableGpuView) * transforms.getSize();
-	if(renderableGpuViewsUboSize)
-	{
-		RebarGpuMemoryToken token;
-		RenderableGpuView* renderableGpuViews =
-			static_cast<RenderableGpuView*>(alloc.allocateFrame(renderableGpuViewsUboSize, token));
-		ANKI_ASSERT(isAligned(alignof(RenderableGpuView), renderableGpuViews));
-
-		cmdb->bindStorageBuffer(set, kMaterialBindingRenderableGpuView, alloc.getBuffer(), token.m_offset,
-								token.m_range);
-
-		for(U32 i = 0; i < transforms.getSize(); ++i)
-		{
-			renderableGpuViews->m_worldTransform = transforms[i];
-			renderableGpuViews->m_previousWorldTransform = prevTransforms[i];
-			renderableGpuViews->m_positionScaleF32AndTranslationVec3 = positionScaleAndTranslation;
-
-			++renderableGpuViews;
-		}
-	}
-
-	// Local uniforms
-	const U32 localUniformsUboSize = U32(mtl->getPrefilledLocalUniforms().getSizeInBytes());
-
-	RebarGpuMemoryToken token;
-	U8* const localUniformsBegin =
-		(localUniformsUboSize != 0) ? static_cast<U8*>(alloc.allocateFrame(localUniformsUboSize, token)) : nullptr;
-
-	if(localUniformsUboSize)
-	{
-		cmdb->bindStorageBuffer(set, kMaterialBindingLocalUniforms, alloc.getBuffer(), token.m_offset, token.m_range);
-	}
-
-	// Iterate variables
-	for(const MaterialVariable& mvar : mtl->getVariables())
-	{
-		switch(mvar.getDataType())
-		{
-		case ShaderVariableDataType::kU32:
-		{
-			const U32 val = mvar.getValue<U32>();
-			memcpy(localUniformsBegin + mvar.getOffsetInLocalUniforms(), &val, sizeof(val));
-			break;
-		}
-		case ShaderVariableDataType::kF32:
-		{
-			const F32 val = mvar.getValue<F32>();
-			memcpy(localUniformsBegin + mvar.getOffsetInLocalUniforms(), &val, sizeof(val));
-			break;
-		}
-		case ShaderVariableDataType::kVec2:
-		{
-			const Vec2 val = mvar.getValue<Vec2>();
-			memcpy(localUniformsBegin + mvar.getOffsetInLocalUniforms(), &val, sizeof(val));
-			break;
-		}
-		case ShaderVariableDataType::kVec3:
-		{
-			const Vec3 val = mvar.getValue<Vec3>();
-			memcpy(localUniformsBegin + mvar.getOffsetInLocalUniforms(), &val, sizeof(val));
-			break;
-		}
-		case ShaderVariableDataType::kVec4:
-		{
-			const Vec4 val = mvar.getValue<Vec4>();
-			memcpy(localUniformsBegin + mvar.getOffsetInLocalUniforms(), &val, sizeof(val));
-			break;
-		}
-		case ShaderVariableDataType::kTexture2D:
-		case ShaderVariableDataType::kTexture2DArray:
-		case ShaderVariableDataType::kTexture3D:
-		case ShaderVariableDataType::kTextureCube:
-		{
-			cmdb->bindTexture(set, mvar.getTextureBinding(), mvar.getValue<ImageResourcePtr>()->getTextureView());
-			break;
-		}
-		default:
-			ANKI_ASSERT(0);
-		} // end switch
-	}
-}
-
-void RenderComponent::onDestroy(SceneNode& node)
-{
-	getExternalSubsystems(node).m_gpuSceneMemoryPool->free(m_gpuSceneRenderable);
-}
-
-} // end namespace anki

+ 0 - 127
AnKi/Scene/Components/RenderComponent.h

@@ -1,127 +0,0 @@
-// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Resource/MaterialResource.h>
-#include <AnKi/Core/GpuMemoryPools.h>
-#include <AnKi/Renderer/RenderQueue.h>
-
-namespace anki {
-
-/// @addtogroup scene
-/// @{
-
-enum class RenderComponentFlag : U8
-{
-	kNone = 0,
-	kCastsShadow = 1 << 0,
-	kForwardShading = 1 << 1,
-	kSortLast = 1 << 2, ///< Push it last when sorting the visibles.
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(RenderComponentFlag)
-
-using FillRayTracingInstanceQueueElementCallback = void (*)(U32 lod, const void* userData,
-															RayTracingInstanceQueueElement& el);
-
-/// Render component interface. Implemented by renderable scene nodes
-class RenderComponent : public SceneComponent
-{
-	ANKI_SCENE_COMPONENT(RenderComponent)
-
-public:
-	RenderComponent(SceneNode* node);
-
-	Bool isEnabled() const
-	{
-		return m_callback != nullptr;
-	}
-
-	RenderComponentFlag getFlags() const
-	{
-		return m_flags;
-	}
-
-	void setFlags(RenderComponentFlag flags)
-	{
-		m_flags = flags;
-	}
-
-	void setFlagsFromMaterial(const MaterialResourcePtr& mtl)
-	{
-		RenderComponentFlag flags = !!(mtl->getRenderingTechniques() & RenderingTechniqueBit::kForward)
-										? RenderComponentFlag::kForwardShading
-										: RenderComponentFlag::kNone;
-		flags |= (mtl->castsShadow()) ? RenderComponentFlag::kCastsShadow : RenderComponentFlag::kNone;
-		setFlags(flags);
-	}
-
-	void initRaster(RenderQueueDrawCallback callback, const void* userData, U64 mergeKey)
-	{
-		ANKI_ASSERT(callback != nullptr);
-		ANKI_ASSERT(userData != nullptr);
-		ANKI_ASSERT(mergeKey != kMaxU64);
-		m_callback = callback;
-		m_userData = userData;
-		m_mergeKey = mergeKey;
-	}
-
-	void initRayTracing(FillRayTracingInstanceQueueElementCallback callback, const void* userData)
-	{
-		m_rtCallback = callback;
-		m_rtCallbackUserData = userData;
-	}
-
-	void setupRenderableQueueElement(RenderableQueueElement& el) const
-	{
-		ANKI_ASSERT(m_callback != nullptr);
-		el.m_callback = m_callback;
-		ANKI_ASSERT(m_userData != nullptr);
-		el.m_userData = m_userData;
-		ANKI_ASSERT(m_mergeKey != kMaxU64);
-		el.m_mergeKey = m_mergeKey;
-		el.m_distanceFromCamera = -1.0f;
-		el.m_lod = kMaxU8;
-		el.m_renderableOffset = U32(m_gpuSceneRenderable.m_offset);
-	}
-
-	void setupRayTracingInstanceQueueElement(U32 lod, RayTracingInstanceQueueElement& el) const
-	{
-		ANKI_ASSERT(m_rtCallback);
-		m_rtCallback(lod, m_rtCallbackUserData, el);
-	}
-
-	Bool getSupportsRayTracing() const
-	{
-		return m_rtCallback != nullptr;
-	}
-
-	/// Helper function.
-	static void allocateAndSetupUniforms(const MaterialResourcePtr& mtl, const RenderQueueDrawContext& ctx,
-										 ConstWeakArray<Mat3x4> transforms, ConstWeakArray<Mat3x4> prevTransforms,
-										 RebarStagingGpuMemoryPool& alloc,
-										 const Vec4& positionScaleAndTranslation = Vec4(1.0f, 0.0f, 0.0f, 0.0f));
-
-	U32 getGpuSceneViewOffset() const
-	{
-		ANKI_ASSERT((m_gpuSceneRenderable.m_offset % 4) == 0);
-		return U32(m_gpuSceneRenderable.m_offset);
-	}
-
-private:
-	RenderQueueDrawCallback m_callback = nullptr;
-	const void* m_userData = nullptr;
-	U64 m_mergeKey = kMaxU64;
-	FillRayTracingInstanceQueueElementCallback m_rtCallback = nullptr;
-	const void* m_rtCallbackUserData = nullptr;
-	SegregatedListsGpuMemoryPoolToken m_gpuSceneRenderable;
-	RenderComponentFlag m_flags = RenderComponentFlag::kNone;
-
-	void onDestroy(SceneNode& node);
-};
-/// @}
-
-} // end namespace anki

+ 0 - 1
AnKi/Scene/Forward.h

@@ -12,7 +12,6 @@ class SceneComponent;
 class FrustumComponent;
 class InstanceComponent;
 class MoveComponent;
-class RenderComponent;
 class SpatialComponent;
 class DecalComponent;
 class ReflectionProxyComponent;

+ 0 - 18
AnKi/Scene/GpuParticleEmitterNode.cpp

@@ -7,7 +7,6 @@
 #include <AnKi/Scene/Components/MoveComponent.h>
 #include <AnKi/Scene/Components/SpatialComponent.h>
 #include <AnKi/Scene/Components/GenericGpuComputeJobComponent.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 #include <AnKi/Scene/Components/GpuParticleEmitterComponent.h>
 
 namespace anki {
@@ -80,29 +79,12 @@ GpuParticleEmitterNode::GpuParticleEmitterNode(SceneGraph* scene, CString name)
 
 	GenericGpuComputeJobComponent* gpuComp = newComponent<GenericGpuComputeJobComponent>();
 	gpuComp->setCallback(GpuParticleEmitterComponent::simulateCallback, pec);
-
-	RenderComponent* rcomp = newComponent<RenderComponent>();
-	const U64 noMerging = 0;
-	rcomp->initRaster(GpuParticleEmitterComponent::drawCallback, pec, noMerging);
 }
 
 GpuParticleEmitterNode::~GpuParticleEmitterNode()
 {
 }
 
-Error GpuParticleEmitterNode::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_unused]] Second crntTime)
-{
-	const GpuParticleEmitterComponent& pec = getFirstComponentOfType<GpuParticleEmitterComponent>();
-
-	if(pec.isEnabled())
-	{
-		RenderComponent& rc = getFirstComponentOfType<RenderComponent>();
-		rc.setFlagsFromMaterial(pec.getParticleEmitterResource()->getMaterial());
-	}
-
-	return Error::kNone;
-}
-
 void GpuParticleEmitterNode::onMoveComponentUpdate(const MoveComponent& movec)
 {
 	getFirstComponentOfType<SpatialComponent>().setSpatialOrigin(movec.getWorldTransform().getOrigin().xyz());

+ 0 - 2
AnKi/Scene/GpuParticleEmitterNode.h

@@ -20,8 +20,6 @@ public:
 
 	~GpuParticleEmitterNode();
 
-	Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
-
 private:
 	class MoveFeedbackComponent;
 	class ShapeFeedbackComponent;

+ 1 - 282
AnKi/Scene/ModelNode.cpp

@@ -9,7 +9,6 @@
 #include <AnKi/Scene/Components/MoveComponent.h>
 #include <AnKi/Scene/Components/SkinComponent.h>
 #include <AnKi/Scene/Components/SpatialComponent.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 #include <AnKi/Scene/Components/ModelComponent.h>
 #include <AnKi/Resource/ModelResource.h>
 #include <AnKi/Resource/ResourceManager.h>
@@ -52,18 +51,15 @@ public:
 ModelNode::ModelNode(SceneGraph* scene, CString name)
 	: SceneNode(scene, name)
 {
-	newComponent<ModelComponent>();
 	newComponent<SkinComponent>();
+	newComponent<ModelComponent>();
 	newComponent<MoveComponent>();
 	newComponent<FeedbackComponent>();
 	newComponent<SpatialComponent>();
-	newComponent<RenderComponent>(); // One of many
-	m_renderProxies.create(getMemoryPool(), 1);
 }
 
 ModelNode::~ModelNode()
 {
-	m_renderProxies.destroy(getMemoryPool());
 }
 
 void ModelNode::feedbackUpdate()
@@ -87,17 +83,6 @@ void ModelNode::feedbackUpdate()
 	{
 		m_aabbLocal = modelc.getModelResource()->getBoundingVolume();
 		updateSpatial = true;
-
-		if(modelc.getModelResource()->getModelPatches().getSize() == countComponentsOfType<RenderComponent>())
-		{
-			// Easy, just re-init the render components
-			initRenderComponents();
-		}
-		else
-		{
-			// Need to create more render components, can't do it at the moment, deffer it
-			m_deferredRenderComponentUpdate = true;
-		}
 	}
 
 	// Skin update
@@ -122,270 +107,4 @@ void ModelNode::feedbackUpdate()
 	}
 }
 
-Error ModelNode::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_unused]] Second crntTime)
-{
-	if(ANKI_LIKELY(!m_deferredRenderComponentUpdate))
-	{
-		return Error::kNone;
-	}
-
-	m_deferredRenderComponentUpdate = false;
-
-	const ModelComponent& modelc = getFirstComponentOfType<ModelComponent>();
-	const U32 modelPatchCount = modelc.getModelResource()->getModelPatches().getSize();
-	const U32 renderComponentCount = countComponentsOfType<RenderComponent>();
-
-	if(modelPatchCount > renderComponentCount)
-	{
-		const U32 diff = modelPatchCount - renderComponentCount;
-
-		for(U32 i = 0; i < diff; ++i)
-		{
-			newComponent<RenderComponent>();
-		}
-
-		m_renderProxies.resize(getMemoryPool(), modelPatchCount);
-	}
-	else
-	{
-		ANKI_ASSERT(!"TODO");
-	}
-
-	ANKI_ASSERT(countComponentsOfType<RenderComponent>() == modelPatchCount);
-
-	// Now you can init the render components
-	initRenderComponents();
-
-	return Error::kNone;
-}
-
-void ModelNode::initRenderComponents()
-{
-	const ModelComponent& modelc = getFirstComponentOfType<ModelComponent>();
-	const ModelResourcePtr& model = modelc.getModelResource();
-	const SkinComponent& skinc = getFirstComponentOfType<SkinComponent>();
-
-	ANKI_ASSERT(modelc.getModelResource()->getModelPatches().getSize() == countComponentsOfType<RenderComponent>());
-	ANKI_ASSERT(modelc.getModelResource()->getModelPatches().getSize() == m_renderProxies.getSize());
-
-	for(U32 patchIdx = 0; patchIdx < model->getModelPatches().getSize(); ++patchIdx)
-	{
-		const ModelPatch& modelPatch = model->getModelPatches()[patchIdx];
-		RenderComponent& rc = getNthComponentOfType<RenderComponent>(patchIdx);
-		rc.initRaster(
-			[](RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData) {
-				const RenderProxy& proxy = *static_cast<const RenderProxy*>(userData[0]);
-				const U32 modelPatchIdx = U32(&proxy - &proxy.m_node->m_renderProxies[0]);
-				proxy.m_node->draw(ctx, userData, modelPatchIdx);
-			},
-			&m_renderProxies[patchIdx], modelc.getRenderMergeKeys()[patchIdx]);
-
-		rc.setFlagsFromMaterial(modelPatch.getMaterial());
-
-		if(!!(modelPatch.getMaterial()->getRenderingTechniques() & RenderingTechniqueBit::kAllRt))
-		{
-			rc.initRayTracing(
-				[](U32 lod, const void* userData, RayTracingInstanceQueueElement& el) {
-					const RenderProxy& proxy = *static_cast<const RenderProxy*>(userData);
-					const U32 modelPatchIdx = U32(&proxy - &proxy.m_node->m_renderProxies[0]);
-					proxy.m_node->setupRayTracingInstanceQueueElement(lod, modelPatchIdx, el);
-				},
-				&m_renderProxies[patchIdx]);
-		}
-
-		// Upload to GPU scene
-		GpuSceneRenderable renderable = {};
-		renderable.m_worldTransformsOffset = getFirstComponentOfType<MoveComponent>().getTransformsGpuSceneOffset();
-		renderable.m_aabbOffset = getFirstComponentOfType<SpatialComponent>().getAabbGpuSceneOffset();
-		renderable.m_uniformsOffset = getFirstComponentOfType<ModelComponent>().getUniformsGpuSceneOffset(patchIdx);
-		renderable.m_geometryOffset = getFirstComponentOfType<ModelComponent>().getGpuSceneMeshLodsOffset()
-									  + sizeof(GpuSceneMeshLod) * kMaxLodCount * patchIdx;
-		if(skinc.isEnabled())
-		{
-			renderable.m_boneTransformsOffset = skinc.getBoneTransformsGpuSceneOffset();
-		}
-
-		getExternalSubsystems().m_gpuSceneMicroPatcher->newCopy(getFrameMemoryPool(), rc.getGpuSceneViewOffset(),
-																sizeof(renderable), &renderable);
-
-		// Init the proxy
-		RenderProxy& proxy = m_renderProxies[patchIdx];
-		proxy.m_node = this;
-
-		const MeshResource& meshResource = *modelPatch.getMesh();
-		proxy.m_compressedToModelTransform.setTranslationPart(meshResource.getPositionsTranslation().xyz1());
-		proxy.m_compressedToModelTransform(0, 0) = meshResource.getPositionsScale();
-		proxy.m_compressedToModelTransform(1, 1) = meshResource.getPositionsScale();
-		proxy.m_compressedToModelTransform(2, 2) = meshResource.getPositionsScale();
-	}
-}
-
-void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData, U32 modelPatchIdx) const
-{
-	const U32 instanceCount = userData.getSize();
-	ANKI_ASSERT(instanceCount > 0 && instanceCount <= kMaxInstanceCount);
-	ANKI_ASSERT(ctx.m_key.getInstanceCount() == instanceCount);
-
-	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
-
-	if(ANKI_LIKELY(!ctx.m_debugDraw))
-	{
-		const ModelComponent& modelc = getFirstComponentOfType<ModelComponent>();
-		const ModelPatch& patch = modelc.getModelResource()->getModelPatches()[modelPatchIdx];
-		const SkinComponent& skinc = getFirstComponentOfType<SkinComponent>();
-
-		const MoveComponent& movec = getFirstComponentOfType<MoveComponent>();
-		Bool moved = movec.wasDirtyThisFrame();
-		for(U32 i = 1; i < instanceCount; ++i)
-		{
-			const ModelNode& otherNode = *static_cast<const RenderProxy*>(userData[i])->m_node;
-
-			[[maybe_unused]] const U32 otherNodeModelPatchIdx =
-				U32(static_cast<const RenderProxy*>(userData[i]) - &otherNode.m_renderProxies[0]);
-			ANKI_ASSERT(otherNodeModelPatchIdx == modelPatchIdx);
-
-			const MoveComponent& otherNodeMovec = otherNode.getFirstComponentOfType<MoveComponent>();
-
-			moved = moved || otherNodeMovec.wasDirtyThisFrame();
-		}
-
-		ctx.m_key.setVelocity(moved && ctx.m_key.getRenderingTechnique() == RenderingTechnique::kGBuffer);
-		ctx.m_key.setSkinned(skinc.isEnabled());
-
-		ModelRenderingInfo modelInf;
-		patch.getRenderingInfo(ctx.m_key, modelInf);
-
-		// Program
-		cmdb->bindShaderProgram(modelInf.m_program);
-
-		// Bind index buffer
-		cmdb->bindIndexBuffer(getExternalSubsystems().m_unifiedGeometryMemPool->getBuffer(),
-							  modelInf.m_indexBufferOffset, IndexType::kU16);
-
-		// Draw
-		cmdb->drawElements(PrimitiveTopology::kTriangles, modelInf.m_indexCount, instanceCount, modelInf.m_firstIndex,
-						   0, 0);
-	}
-	else
-	{
-		// Draw the bounding volumes
-
-		Mat4* const mvps = newArray<Mat4>(*ctx.m_framePool, instanceCount);
-		for(U32 i = 0; i < instanceCount; ++i)
-		{
-			const ModelNode& otherNode = *static_cast<const RenderProxy*>(userData[i])->m_node;
-			const Aabb& box = otherNode.getFirstComponentOfType<SpatialComponent>().getAabbWorldSpace();
-			const Vec4 tsl = (box.getMin() + box.getMax()) / 2.0f;
-			const Vec3 scale = (box.getMax().xyz() - box.getMin().xyz()) / 2.0f;
-
-			// Set non uniform scale. Add a margin to avoid flickering
-			Mat3 nonUniScale = Mat3::getZero();
-			constexpr F32 kMargin = 1.02f;
-			nonUniScale(0, 0) = scale.x() * kMargin;
-			nonUniScale(1, 1) = scale.y() * kMargin;
-			nonUniScale(2, 2) = scale.z() * kMargin;
-
-			mvps[i] = ctx.m_viewProjectionMatrix * Mat4(tsl.xyz1(), Mat3::getIdentity() * nonUniScale, 1.0f);
-		}
-
-		const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDepthTestOn);
-		if(enableDepthTest)
-		{
-			cmdb->setDepthCompareOperation(CompareOperation::kLess);
-		}
-		else
-		{
-			cmdb->setDepthCompareOperation(CompareOperation::kAlways);
-		}
-
-		getSceneGraph().getDebugDrawer().drawCubes(
-			ConstWeakArray<Mat4>(mvps, instanceCount), Vec4(1.0f, 0.0f, 1.0f, 1.0f), 2.0f,
-			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDitheredDepthTestOn), 2.0f, *ctx.m_rebarStagingPool,
-			cmdb);
-
-		deleteArray(*ctx.m_framePool, mvps, instanceCount);
-
-		// Bones
-		const SkinComponent& skinc = getFirstComponentOfType<SkinComponent>();
-		if(skinc.isEnabled())
-		{
-			const SkinComponent& skinc = getComponentAt<SkinComponent>(0);
-			SkeletonResourcePtr skeleton = skinc.getSkeleronResource();
-			const U32 boneCount = skinc.getBoneTransforms().getSize();
-
-			DynamicArrayRaii<Vec3> lines(ctx.m_framePool);
-			lines.resizeStorage(boneCount * 2);
-			DynamicArrayRaii<Vec3> chidlessLines(ctx.m_framePool);
-			for(U32 i = 0; i < boneCount; ++i)
-			{
-				const Bone& bone = skeleton->getBones()[i];
-				ANKI_ASSERT(bone.getIndex() == i);
-				const Vec4 point(0.0f, 0.0f, 0.0f, 1.0f);
-				const Bone* parent = bone.getParent();
-				Mat4 m = (parent) ? Mat4(skinc.getBoneTransforms()[parent->getIndex()], Vec4(0.0f, 0.0f, 0.0f, 1.0f))
-										* Mat4(parent->getVertexTransform(), Vec4(0.0f, 0.0f, 0.0f, 1.0f)).getInverse()
-								  : Mat4::getIdentity();
-				const Vec3 a = (m * point).xyz();
-
-				m = Mat4(skinc.getBoneTransforms()[i], Vec4(0.0f, 0.0f, 0.0f, 1.0f))
-					* Mat4(bone.getVertexTransform(), Vec4(0.0f, 0.0f, 0.0f, 1.0f)).getInverse();
-				const Vec3 b = (m * point).xyz();
-
-				lines.emplaceBack(a);
-				lines.emplaceBack(b);
-
-				if(bone.getChildren().getSize() == 0)
-				{
-					// If there are not children try to draw something for that bone as well
-					chidlessLines.emplaceBack(b);
-					const F32 len = (b - a).getLength();
-					const Vec3 c = b + (b - a).getNormalized() * len;
-					chidlessLines.emplaceBack(c);
-				}
-			}
-
-			const Mat4 mvp =
-				ctx.m_viewProjectionMatrix * Mat4(getFirstComponentOfType<MoveComponent>().getWorldTransform());
-			getSceneGraph().getDebugDrawer().drawLines(
-				ConstWeakArray<Mat4>(&mvp, 1), Vec4(1.0f), 20.0f,
-				ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDitheredDepthTestOn), lines,
-				*ctx.m_rebarStagingPool, cmdb);
-
-			getSceneGraph().getDebugDrawer().drawLines(
-				ConstWeakArray<Mat4>(&mvp, 1), Vec4(0.7f, 0.7f, 0.7f, 1.0f), 5.0f,
-				ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::kDitheredDepthTestOn), chidlessLines,
-				*ctx.m_rebarStagingPool, cmdb);
-		}
-
-		// Restore state
-		if(!enableDepthTest)
-		{
-			cmdb->setDepthCompareOperation(CompareOperation::kLess);
-		}
-	}
-}
-
-void ModelNode::setupRayTracingInstanceQueueElement(U32 lod, U32 modelPatchIdx,
-													RayTracingInstanceQueueElement& el) const
-{
-	const ModelComponent& modelc = getFirstComponentOfType<ModelComponent>();
-	const ModelPatch& patch = modelc.getModelResource()->getModelPatches()[modelPatchIdx];
-
-	RenderingKey key(RenderingTechnique::kRtShadow, lod, 1, false, false);
-
-	ModelRayTracingInfo info;
-	patch.getRayTracingInfo(key, info);
-
-	memset(&el, 0, sizeof(el));
-
-	el.m_bottomLevelAccelerationStructure = info.m_bottomLevelAccelerationStructure.get();
-
-	const MoveComponent& movec = getFirstComponentOfType<MoveComponent>();
-
-	const Mat4 m4 = Mat4(movec.getWorldTransform()) * m_renderProxies[modelPatchIdx].m_compressedToModelTransform;
-	el.m_transform = Mat3x4(m4);
-
-	el.m_shaderGroupHandleIndex = info.m_shaderGroupHandleIndex;
-}
-
 } // end namespace anki

+ 0 - 11
AnKi/Scene/ModelNode.h

@@ -26,24 +26,13 @@ public:
 
 	~ModelNode();
 
-	Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
-
 private:
 	class FeedbackComponent;
 	class RenderProxy;
 
 	Aabb m_aabbLocal;
-	DynamicArray<RenderProxy> m_renderProxies; ///< The size matches the number of render components.
-
-	Bool m_deferredRenderComponentUpdate = false;
 
 	void feedbackUpdate();
-
-	void draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData, U32 modelPatchIdx) const;
-
-	void setupRayTracingInstanceQueueElement(U32 lod, U32 modelPatchIdx, RayTracingInstanceQueueElement& el) const;
-
-	void initRenderComponents();
 };
 /// @}
 

+ 1 - 26
AnKi/Scene/ParticleEmitterNode.cpp

@@ -7,7 +7,6 @@
 #include <AnKi/Scene/Components/MoveComponent.h>
 #include <AnKi/Scene/Components/SpatialComponent.h>
 #include <AnKi/Scene/Components/ParticleEmitterComponent.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 
 namespace anki {
 
@@ -68,13 +67,10 @@ ParticleEmitterNode::ParticleEmitterNode(SceneGraph* scene, CString name)
 
 	newComponent<MoveFeedbackComponent>();
 
-	ParticleEmitterComponent* particleEmitterc = newComponent<ParticleEmitterComponent>();
+	newComponent<ParticleEmitterComponent>();
 
 	newComponent<ShapeFeedbackComponent>();
 	newComponent<SpatialComponent>();
-
-	RenderComponent* rcomp = newComponent<RenderComponent>();
-	rcomp->initRaster(ParticleEmitterComponent::drawCallback, particleEmitterc, 0); // No merging
 }
 
 ParticleEmitterNode::~ParticleEmitterNode()
@@ -83,7 +79,6 @@ ParticleEmitterNode::~ParticleEmitterNode()
 
 void ParticleEmitterNode::onMoveComponentUpdate(MoveComponent& move)
 {
-	getFirstComponentOfType<ParticleEmitterComponent>().setWorldTransform(move.getWorldTransform());
 	getFirstComponentOfType<SpatialComponent>().setSpatialOrigin(move.getWorldTransform().getOrigin().xyz());
 }
 
@@ -93,24 +88,4 @@ void ParticleEmitterNode::onShapeUpdate()
 	getFirstComponentOfType<SpatialComponent>().setAabbWorldSpace(pec.getAabbWorldSpace());
 }
 
-Error ParticleEmitterNode::frameUpdate([[maybe_unused]] Second prevUpdateTime, [[maybe_unused]] Second crntTime)
-{
-	const ParticleEmitterComponent& pec = getFirstComponentOfType<ParticleEmitterComponent>();
-	if(pec.isEnabled())
-	{
-		RenderComponent& rc = getFirstComponentOfType<RenderComponent>();
-		rc.setFlagsFromMaterial(pec.getParticleEmitterResource()->getMaterial());
-
-		// GPU scene update
-		GpuSceneRenderable renderable = {};
-		renderable.m_worldTransformsOffset = getFirstComponentOfType<MoveComponent>().getTransformsGpuSceneOffset();
-		renderable.m_uniformsOffset = pec.getGpuSceneUniforms();
-		renderable.m_geometryOffset = pec.getGpuSceneParticlesOffset();
-		getExternalSubsystems().m_gpuSceneMicroPatcher->newCopy(getFrameMemoryPool(), rc.getGpuSceneViewOffset(),
-																sizeof(renderable), &renderable);
-	}
-
-	return Error::kNone;
-}
-
 } // end namespace anki

+ 0 - 2
AnKi/Scene/ParticleEmitterNode.h

@@ -20,8 +20,6 @@ public:
 
 	~ParticleEmitterNode();
 
-	Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
-
 private:
 	class MoveFeedbackComponent;
 	class ShapeFeedbackComponent;

+ 5 - 1
AnKi/Scene/PhysicsDebugNode.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Scene/PhysicsDebugNode.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
 #include <AnKi/Scene/Components/SpatialComponent.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Resource/ResourceManager.h>
@@ -15,6 +14,8 @@ PhysicsDebugNode::PhysicsDebugNode(SceneGraph* scene, CString name)
 	: SceneNode(scene, name)
 	, m_physDbgDrawer(&scene->getDebugDrawer())
 {
+	// TODO
+#if 0
 	RenderComponent* rcomp = newComponent<RenderComponent>();
 	rcomp->setFlags(RenderComponentFlag::kNone);
 	rcomp->initRaster(
@@ -22,6 +23,7 @@ PhysicsDebugNode::PhysicsDebugNode(SceneGraph* scene, CString name)
 			static_cast<PhysicsDebugNode*>(userData[0])->draw(ctx);
 		},
 		this, 0);
+#endif
 
 	SpatialComponent* scomp = newComponent<SpatialComponent>();
 	scomp->setUpdateOctreeBounds(false); // Don't mess with the bounds
@@ -35,12 +37,14 @@ PhysicsDebugNode::~PhysicsDebugNode()
 
 void PhysicsDebugNode::draw(RenderQueueDrawContext& ctx)
 {
+#if 0
 	if(ctx.m_debugDraw)
 	{
 		m_physDbgDrawer.start(ctx.m_viewProjectionMatrix, ctx.m_commandBuffer, ctx.m_rebarStagingPool);
 		m_physDbgDrawer.drawWorld(*getExternalSubsystems().m_physicsWorld);
 		m_physDbgDrawer.end();
 	}
+#endif
 }
 
 } // end namespace anki

+ 8 - 2
AnKi/Scene/SceneNode.h

@@ -269,9 +269,15 @@ protected:
 		TComponent* comp = newInstance<TComponent>(getMemoryPool(), this);
 
 		// Inform all other components that some component was added
-		for(SceneComponent* comp : m_components)
+		for(SceneComponent* other : m_components)
 		{
-			comp->onOtherComponentRemovedOrAddedReal(comp, true);
+			ANKI_CALL_INTERNAL(other->onOtherComponentRemovedOrAddedReal(comp, true));
+		}
+
+		// Inform the current component about others
+		for(SceneComponent* other : m_components)
+		{
+			ANKI_CALL_INTERNAL(comp->onOtherComponentRemovedOrAddedReal(other, true));
 		}
 
 		m_components.emplaceBack(getMemoryPool(), comp);

+ 56 - 35
AnKi/Scene/Visibility.cpp

@@ -7,7 +7,7 @@
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Scene/Components/FrustumComponent.h>
 #include <AnKi/Scene/Components/LensFlareComponent.h>
-#include <AnKi/Scene/Components/RenderComponent.h>
+#include <AnKi/Scene/Components/ModelComponent.h>
 #include <AnKi/Scene/Components/ReflectionProbeComponent.h>
 #include <AnKi/Scene/Components/DecalComponent.h>
 #include <AnKi/Scene/Components/MoveComponent.h>
@@ -16,6 +16,7 @@
 #include <AnKi/Scene/Components/SpatialComponent.h>
 #include <AnKi/Scene/Components/GlobalIlluminationProbeComponent.h>
 #include <AnKi/Scene/Components/GenericGpuComputeJobComponent.h>
+#include <AnKi/Scene/Components/ParticleEmitterComponent.h>
 #include <AnKi/Scene/Components/UiComponent.h>
 #include <AnKi/Scene/Components/SkyboxComponent.h>
 #include <AnKi/Renderer/MainRenderer.h>
@@ -281,6 +282,10 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 	const Bool wantsEarlyZ =
 		!!(frustumFlags & FrustumComponentVisibilityTestFlag::kEarlyZ) && m_frcCtx->m_visCtx->m_earlyZDist > 0.0f;
 
+	const Bool testedNodeIsProbe =
+		testedNode.tryGetFirstComponentOfType<ReflectionProbeComponent>()
+		|| testedNode.tryGetFirstComponentOfType<GlobalIlluminationProbeComponent>(); // TODO hack for now
+
 	// Iterate
 	RenderQueueView& result = m_frcCtx->m_queueViews[taskId];
 	for(U i = 0; i < m_spatialToTestCount; ++i)
@@ -298,15 +303,18 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		// Check what components the frustum needs
 		Bool wantNode = false;
 
-		const RenderComponent* rc = nullptr;
-		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kRenderComponents) && getComponent(node, rc);
+		const ModelComponent* modelc = nullptr;
+		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kRenderComponents)
+					&& getComponent(node, modelc) && modelc->isEnabled();
 
 		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kShadowCasterRenderComponents)
-					&& getComponent(node, rc) && !!(rc->getFlags() & RenderComponentFlag::kCastsShadow);
+					&& getComponent(node, modelc) && modelc->isEnabled() && modelc->getCastsShadow();
+
+		// TODO ray tracing
 
-		const RenderComponent* rtRc = nullptr;
-		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kAllRayTracing) && getComponent(node, rtRc)
-					&& rtRc->getSupportsRayTracing();
+		const ParticleEmitterComponent* partemitc = nullptr;
+		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kRenderComponents)
+					&& getComponent(node, partemitc) && partemitc->isEnabled();
 
 		const LightComponent* lc = nullptr;
 		wantNode |= !!(frustumFlags & FrustumComponentVisibilityTestFlag::kLights) && getComponent(node, lc);
@@ -360,46 +368,59 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		WeakArray<RenderQueue> nextQueues;
 		WeakArray<FrustumComponent> nextQueueFrustumComponents; // Optional
 
-		node.iterateComponentsOfType<RenderComponent>([&](const RenderComponent& rc) {
-			RenderableQueueElement* el;
-			if(!!(rc.getFlags() & RenderComponentFlag::kForwardShading))
+		if(modelc)
+		{
+			const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::kNear];
+			const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, spatialc->getAabbWorldSpace()));
+
+			const U8 lod = (testedNodeIsProbe) ? 0 : computeLod(primaryFrc, distanceFromCamera);
+
+			WeakArray<RenderableQueueElement> elements;
+			modelc->setupRenderableQueueElements(lod, RenderingTechnique::kGBuffer, pool, elements);
+			for(RenderableQueueElement& el : elements)
 			{
-				el = result.m_forwardShadingRenderables.newElement(pool);
+				el.m_distanceFromCamera = distanceFromCamera;
+				*result.m_renderables.newElement(pool) = el;
 			}
-			else
+
+			modelc->setupRenderableQueueElements(lod, RenderingTechnique::kForward, pool, elements);
+			for(RenderableQueueElement& el : elements)
 			{
-				el = result.m_renderables.newElement(pool);
+				el.m_distanceFromCamera = distanceFromCamera;
+				*result.m_forwardShadingRenderables.newElement(pool) = el;
 			}
 
-			rc.setupRenderableQueueElement(*el);
+			if(wantsEarlyZ && distanceFromCamera < m_frcCtx->m_visCtx->m_earlyZDist)
+			{
+				modelc->setupRenderableQueueElements(lod, RenderingTechnique::kGBufferEarlyZ, pool, elements);
+				for(RenderableQueueElement& el : elements)
+				{
+					el.m_distanceFromCamera = distanceFromCamera;
+					*result.m_earlyZRenderables.newElement(pool) = el;
+				}
+			}
+		}
 
-			// Compute distance from the frustum
+		if(partemitc)
+		{
 			const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::kNear];
-			el->m_distanceFromCamera = !!(rc.getFlags() & RenderComponentFlag::kSortLast)
-										   ? primaryFrc.getFar()
-										   : max(0.0f, testPlane(nearPlane, spatialc->getAabbWorldSpace()));
-
-			el->m_lod = computeLod(primaryFrc, el->m_distanceFromCamera);
+			const F32 distanceFromCamera = max(0.0f, testPlane(nearPlane, spatialc->getAabbWorldSpace()));
 
-			// Add to early Z
-			if(wantsEarlyZ && el->m_distanceFromCamera < m_frcCtx->m_visCtx->m_earlyZDist
-			   && !(rc.getFlags() & RenderComponentFlag::kForwardShading))
+			WeakArray<RenderableQueueElement> elements;
+			partemitc->setupRenderableQueueElements(RenderingTechnique::kGBuffer, pool, elements);
+			for(RenderableQueueElement& el : elements)
 			{
-				RenderableQueueElement* el2 = result.m_earlyZRenderables.newElement(pool);
-				*el2 = *el;
+				el.m_distanceFromCamera = distanceFromCamera;
+				*result.m_renderables.newElement(pool) = el;
 			}
 
-			// Add to RT
-			if(rtRc)
+			partemitc->setupRenderableQueueElements(RenderingTechnique::kForward, pool, elements);
+			for(RenderableQueueElement& el : elements)
 			{
-				RayTracingInstanceQueueElement* el = result.m_rayTracingInstances.newElement(pool);
-
-				// Compute the LOD
-				const Plane& nearPlane = primaryFrc.getViewPlanes()[FrustumPlaneType::kNear];
-				const F32 dist = testPlane(nearPlane, spatialc->getAabbWorldSpace());
-				rc.setupRayTracingInstanceQueueElement(computeLod(primaryFrc, dist), *el);
+				el.m_distanceFromCamera = distanceFromCamera;
+				*result.m_forwardShadingRenderables.newElement(pool) = el;
 			}
-		});
+		}
 
 		if(lc)
 		{
@@ -699,7 +720,7 @@ void CombineResultsTask::combine()
 		std::sort(results.m_renderables.getBegin(), results.m_renderables.getEnd(), MaterialDistanceSortFunctor());
 
 		std::sort(results.m_earlyZRenderables.getBegin(), results.m_earlyZRenderables.getEnd(),
-				  DistanceSortFunctor<RenderableQueueElement>());
+				  MaterialDistanceSortFunctor());
 
 		std::sort(results.m_forwardShadingRenderables.getBegin(), results.m_forwardShadingRenderables.getEnd(),
 				  RevDistanceSortFunctor<RenderableQueueElement>());

+ 1 - 8
AnKi/Scene/VisibilityInternal.h

@@ -47,14 +47,7 @@ class MaterialDistanceSortFunctor
 public:
 	Bool operator()(const RenderableQueueElement& a, const RenderableQueueElement& b)
 	{
-		if(a.m_lod == b.m_lod)
-		{
-			return a.m_mergeKey < b.m_mergeKey;
-		}
-		else
-		{
-			return a.m_lod < b.m_lod;
-		}
+		return a.m_mergeKey < b.m_mergeKey;
 	}
 };
 

+ 3 - 6
AnKi/Shaders/ForwardShadingGenericTransparent.ankiprog

@@ -21,7 +21,7 @@
 
 struct VertIn
 {
-	[[vk::location(0)]] PackedGpuSceneRenderableInstance m_gpuSceneRenderableInstance : INSTANCE;
+	[[vk::location(0)]] GpuSceneRenderablePacked m_gpuSceneRenderable : RENDERABLE;
 	U32 m_svVertexId : SV_VERTEXID;
 };
 
@@ -39,11 +39,8 @@ VertOut main(VertIn input)
 {
 	VertOut output;
 
-	const UnpackedGpuSceneRenderableInstance instance =
-		unpackRenderableGpuViewInstance(input.m_gpuSceneRenderableInstance);
-	const GpuSceneRenderable renderable = g_gpuScene.Load<GpuSceneRenderable>(instance.m_renderableOffset);
-	const GpuSceneMeshLod mesh =
-		g_gpuScene.Load<GpuSceneMeshLod>(renderable.m_geometryOffset * sizeof(GpuSceneMeshLod) * instance.m_lod);
+	const GpuSceneRenderable renderable = unpackGpuSceneRenderable(input.m_gpuSceneRenderable);
+	const GpuSceneMeshLod mesh = g_gpuScene.Load<GpuSceneMeshLod>(renderable.m_geometryOffset);
 	const Mat3x4 worldTransform = g_gpuScene.Load<Mat3x4>(renderable.m_worldTransformsOffset);
 	const UnpackedMeshVertex vertex = loadVertex(mesh, input.m_svVertexId, false);
 

+ 2 - 4
AnKi/Shaders/ForwardShadingParticles.ankiprog

@@ -14,7 +14,7 @@
 
 struct VertIn
 {
-	[[vk::location(0)]] PackedGpuSceneRenderableInstance m_gpuSceneRenderableInstance : INSTANCE;
+	[[vk::location(0)]] GpuSceneRenderablePacked m_gpuSceneRenderable : RENDERABLE;
 	U32 m_svVertexId : SV_VERTEXID;
 };
 
@@ -42,9 +42,7 @@ VertOut main(VertIn input)
 	const U32 particleId = input.m_svVertexId / 6u;
 	const U32 vertexId = input.m_svVertexId % 6u;
 
-	const UnpackedGpuSceneRenderableInstance instance =
-		unpackRenderableGpuViewInstance(input.m_gpuSceneRenderableInstance);
-	const GpuSceneRenderable renderable = g_gpuScene.Load<GpuSceneRenderable>(instance.m_renderableOffset);
+	const GpuSceneRenderable renderable = unpackGpuSceneRenderable(input.m_gpuSceneRenderable);
 	const GpuSceneParticles particles = g_gpuScene.Load<GpuSceneParticles>(renderable.m_geometryOffset);
 
 	U32 idx = particles.m_vertexOffsets[(U32)VertexStreamId::kParticlePosition] + particleId * sizeof(Vec3);

+ 3 - 6
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -61,7 +61,7 @@
 struct VertIn
 {
 	U32 m_svVertexId : SV_VERTEXID;
-	[[vk::location(0)]] PackedGpuSceneRenderableInstance m_gpuSceneRenderableInstance : INSTANCE;
+	[[vk::location(0)]] GpuSceneRenderablePacked m_gpuSceneRenderable : RENDERABLE;
 };
 
 struct VertOut
@@ -172,11 +172,8 @@ VertOut main(VertIn input)
 {
 	VertOut output;
 
-	const UnpackedGpuSceneRenderableInstance instance =
-		unpackRenderableGpuViewInstance(input.m_gpuSceneRenderableInstance);
-	const GpuSceneRenderable renderable = g_gpuScene.Load<GpuSceneRenderable>(instance.m_renderableOffset);
-	const GpuSceneMeshLod mesh =
-		g_gpuScene.Load<GpuSceneMeshLod>(renderable.m_geometryOffset + sizeof(GpuSceneMeshLod) * instance.m_lod);
+	const GpuSceneRenderable renderable = unpackGpuSceneRenderable(input.m_gpuSceneRenderable);
+	const GpuSceneMeshLod mesh = g_gpuScene.Load<GpuSceneMeshLod>(renderable.m_geometryOffset);
 	UnpackedMeshVertex vert = loadVertex(mesh, input.m_svVertexId, ANKI_BONES);
 
 	const Mat3x4 worldTransform = g_gpuScene.Load<Mat3x4>(renderable.m_worldTransformsOffset);

+ 13 - 8
AnKi/Shaders/Include/GpuSceneFunctions.h

@@ -9,18 +9,23 @@
 
 ANKI_BEGIN_NAMESPACE
 
-ANKI_SHADER_FUNC_INLINE PackedGpuSceneRenderableInstance
-packGpuSceneRenderableInstance(UnpackedGpuSceneRenderableInstance x)
+ANKI_SHADER_FUNC_INLINE GpuSceneRenderablePacked packGpuSceneRenderable(GpuSceneRenderable x)
 {
-	return (x.m_renderableOffset << 2u) | x.m_lod;
+	GpuSceneRenderablePacked o;
+	o[0] = x.m_worldTransformsOffset;
+	o[1] = x.m_uniformsOffset;
+	o[2] = x.m_geometryOffset;
+	o[3] = x.m_boneTransformsOffset;
+	return o;
 }
 
-ANKI_SHADER_FUNC_INLINE UnpackedGpuSceneRenderableInstance
-unpackRenderableGpuViewInstance(PackedGpuSceneRenderableInstance x)
+ANKI_SHADER_FUNC_INLINE GpuSceneRenderable unpackGpuSceneRenderable(GpuSceneRenderablePacked x)
 {
-	UnpackedGpuSceneRenderableInstance o;
-	o.m_lod = x & 3u;
-	o.m_renderableOffset = x >> 2u;
+	GpuSceneRenderable o;
+	o.m_worldTransformsOffset = x[0];
+	o.m_uniformsOffset = x[1];
+	o.m_geometryOffset = x[2];
+	o.m_boneTransformsOffset = x[3];
 	return o;
 }
 

+ 3 - 13
AnKi/Shaders/Include/GpuSceneTypes.h

@@ -13,15 +13,13 @@ ANKI_BEGIN_NAMESPACE
 struct GpuSceneRenderable
 {
 	U32 m_worldTransformsOffset; ///< First is the crnt transform and the 2nd the previous
-	U32 m_aabbOffset;
 	U32 m_uniformsOffset;
 	U32 m_geometryOffset;
 	U32 m_boneTransformsOffset;
-	U32 m_padding0;
-	U32 m_padding1;
-	U32 m_padding2;
 };
-static_assert(sizeof(GpuSceneRenderable) == sizeof(Vec4) * 2);
+static_assert(sizeof(GpuSceneRenderable) == sizeof(Vec4) * 1);
+
+typedef UVec4 GpuSceneRenderablePacked;
 
 struct GpuSceneMeshLod
 {
@@ -42,14 +40,6 @@ struct GpuSceneParticles
 };
 static_assert(sizeof(GpuSceneParticles) == sizeof(Vec4) * 2);
 
-struct UnpackedGpuSceneRenderableInstance
-{
-	U32 m_renderableOffset;
-	U32 m_lod;
-};
-
-typedef U32 PackedGpuSceneRenderableInstance;
-
 struct RenderableGpuView
 {
 	Mat3x4 m_worldTransform;

+ 1 - 1
AnKi/Shaders/IndirectDiffuse.hlsl

@@ -13,7 +13,7 @@
 #include <AnKi/Shaders/TonemappingFunctions.hlsl>
 #include <AnKi/Shaders/Include/MiscRendererTypes.h>
 
-#define ENABLE_SSGI false
+#define ENABLE_SSGI true
 #define ENABLE_PROBES true
 #define REMOVE_FIREFLIES false
 #define REPROJECT_LIGHTBUFFER false

+ 13 - 9
Tools/FormatSource.py

@@ -45,6 +45,8 @@ def thread_callback(tid):
             file_txt = file.read()
             file.close()
 
+            original_file_hash = hash(file_txt) 
+
             # Replace all semantics
             for semantic in hlsl_semantics:
                 file_txt = file_txt.replace(": " + semantic, "__" + semantic)
@@ -70,11 +72,8 @@ def thread_callback(tid):
         subprocess.check_call([exe, "-sort-includes=false", style_file, "-i", file_name])
 
         if is_shader:
-            shutil.move(tmp_filename, orig_filename)
-            file_name = orig_filename
-
-            # Read all text
-            file = open(file_name, mode="r", newline="\n")
+            # Read tmp file
+            file = open(tmp_filename, mode="r", newline="\n")
             file_txt = file.read()
             file.close()
 
@@ -82,11 +81,16 @@ def thread_callback(tid):
             for semantic in hlsl_semantics:
                 file_txt = file_txt.replace("__" + semantic, ": " + semantic)
 
-            # Write the new file
-            file = open(file_name, mode="w", newline="\n")
-            file.write(file_txt)
-            file.close()
+            new_file_hash = hash(file_txt)
+
+            # Write formatted file
+            if new_file_hash != original_file_hash:
+                file = open(orig_filename, mode="w", newline="\n")
+                file.write(file_txt)
+                file.close()
 
+            # Cleanup
+            os.remove(tmp_filename)
 
 # Gather the filenames
 file_names = []