Просмотр исходного кода

Some refactoring of scene components

Panagiotis Christopoulos Charitos 3 лет назад
Родитель
Сommit
bc165086a1
45 измененных файлов с 315 добавлено и 172 удалено
  1. 1 1
      AnKi/Gr/CommandBuffer.h
  2. 3 14
      AnKi/Gr/Vulkan/CommandBufferImpl.inl.h
  3. 1 1
      AnKi/Scene/BodyNode.cpp
  4. 1 1
      AnKi/Scene/CameraNode.cpp
  5. 1 0
      AnKi/Scene/Common.h
  6. 2 2
      AnKi/Scene/Components/BodyComponent.h
  7. 12 13
      AnKi/Scene/Components/DecalComponent.h
  8. 7 7
      AnKi/Scene/Components/FogDensityComponent.h
  9. 7 7
      AnKi/Scene/Components/FrustumComponent.h
  10. 4 0
      AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp
  11. 9 7
      AnKi/Scene/Components/GlobalIlluminationProbeComponent.h
  12. 1 2
      AnKi/Scene/Components/GpuParticleEmitterComponent.h
  13. 1 1
      AnKi/Scene/Components/JointComponent.h
  14. 2 2
      AnKi/Scene/Components/LightComponent.h
  15. 7 7
      AnKi/Scene/Components/ModelComponent.h
  16. 6 0
      AnKi/Scene/Components/MoveComponent.cpp
  17. 7 2
      AnKi/Scene/Components/MoveComponent.h
  18. 2 2
      AnKi/Scene/Components/ParticleEmitterComponent.h
  19. 8 8
      AnKi/Scene/Components/PlayerControllerComponent.h
  20. 7 7
      AnKi/Scene/Components/ReflectionProbeComponent.h
  21. 12 0
      AnKi/Scene/Components/RenderComponent.cpp
  22. 5 4
      AnKi/Scene/Components/RenderComponent.h
  23. 56 20
      AnKi/Scene/Components/SceneComponent.cpp
  24. 83 28
      AnKi/Scene/Components/SceneComponent.h
  25. 2 2
      AnKi/Scene/Components/ScriptComponent.h
  26. 2 2
      AnKi/Scene/Components/SkinComponent.h
  27. 4 0
      AnKi/Scene/Components/SpatialComponent.cpp
  28. 4 2
      AnKi/Scene/Components/SpatialComponent.h
  29. 2 2
      AnKi/Scene/Components/TriggerComponent.h
  30. 2 2
      AnKi/Scene/DecalNode.cpp
  31. 2 2
      AnKi/Scene/FogDensityNode.cpp
  32. 2 2
      AnKi/Scene/GlobalIlluminationProbeNode.cpp
  33. 2 2
      AnKi/Scene/GpuParticleEmitterNode.cpp
  34. 4 4
      AnKi/Scene/LightNode.cpp
  35. 1 1
      AnKi/Scene/ModelNode.cpp
  36. 2 2
      AnKi/Scene/ParticleEmitterNode.cpp
  37. 2 2
      AnKi/Scene/PlayerNode.cpp
  38. 2 2
      AnKi/Scene/ReflectionProbeNode.cpp
  39. 1 1
      AnKi/Scene/SceneGraph.cpp
  40. 5 4
      AnKi/Scene/SceneNode.cpp
  41. 1 1
      AnKi/Scene/TriggerNode.cpp
  42. 1 1
      AnKi/Scene/Visibility.cpp
  43. 21 1
      AnKi/Shaders/Include/GpuSceneTypes.h
  44. 4 0
      AnKi/Shaders/Include/MeshTypes.h
  45. 4 1
      AnKi/Util/SegregatedListsAllocatorBuilder.inl.h

+ 1 - 1
AnKi/Gr/CommandBuffer.h

@@ -376,7 +376,7 @@ public:
 	void copyBufferToBuffer(const BufferPtr& src, PtrSize srcOffset, const BufferPtr& dst, PtrSize dstOffset,
 							PtrSize range)
 	{
-		Array<CopyBufferToBufferInfo, 1> copies = {{srcOffset, dstOffset, range}};
+		Array<CopyBufferToBufferInfo, 1> copies = {{{srcOffset, dstOffset, range}}};
 		copyBufferToBuffer(src, dst, copies);
 	}
 

+ 3 - 14
AnKi/Gr/Vulkan/CommandBufferImpl.inl.h

@@ -644,22 +644,11 @@ inline void CommandBufferImpl::copyBufferToBufferInternal(const BufferPtr& src,
 
 	commandCommon();
 
-	DynamicArrayRaii<VkBufferCopy> vkCopies(m_pool, copies.getSize());
-
-	for(U32 i = 0; i < copies.getSize(); ++i)
-	{
-		const CopyBufferToBufferInfo& in = copies[i];
-		VkBufferCopy& out = vkCopies[i];
-		ANKI_ASSERT(in.m_sourceOffset + in.m_range <= src->getSize());
-		ANKI_ASSERT(in.m_destinationOffset + in.m_range <= dst->getSize());
-
-		out.srcOffset = in.m_sourceOffset;
-		out.dstOffset = in.m_destinationOffset;
-		out.size = in.m_range;
-	}
+	static_assert(sizeof(CopyBufferToBufferInfo) == sizeof(VkBufferCopy));
+	const VkBufferCopy* vkCopies = reinterpret_cast<const VkBufferCopy*>(&copies[0]);
 
 	vkCmdCopyBuffer(m_handle, static_cast<const BufferImpl&>(*src).getHandle(),
-					static_cast<const BufferImpl&>(*dst).getHandle(), vkCopies.getSize(), &vkCopies[0]);
+					static_cast<const BufferImpl&>(*dst).getHandle(), copies.getSize(), &vkCopies[0]);
 
 	m_microCmdb->pushObjectRef(src);
 	m_microCmdb->pushObjectRef(dst);

+ 1 - 1
AnKi/Scene/BodyNode.cpp

@@ -24,7 +24,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 1 - 1
AnKi/Scene/CameraNode.cpp

@@ -23,7 +23,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 1 - 0
AnKi/Scene/Common.h

@@ -7,6 +7,7 @@
 
 #include <AnKi/Util/String.h>
 #include <AnKi/Scene/Forward.h>
+#include <AnKi/Core/GpuMemoryPools.h>
 #include <functional>
 
 namespace anki {

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

@@ -57,8 +57,6 @@ public:
 		return m_body;
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	Bool isEnabled() const
 	{
 		return m_mesh.isCreated();
@@ -70,6 +68,8 @@ private:
 	PhysicsBodyPtr m_body;
 	Transform m_trf = Transform::getIdentity();
 	Bool m_markedForUpdate = true;
+
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 };
 /// @}
 

+ 12 - 13
AnKi/Scene/Components/DecalComponent.h

@@ -61,19 +61,6 @@ public:
 		m_markedForUpdate = true;
 	}
 
-	/// Implements SceneComponent::update.
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		updated = m_markedForUpdate;
-		m_markedForUpdate = false;
-		if(updated)
-		{
-			updateInternal();
-		}
-
-		return Error::kNone;
-	}
-
 	const Mat4& getBiasProjectionViewMatrix() const
 	{
 		return m_biasProjViewMat;
@@ -152,6 +139,18 @@ private:
 
 	void updateInternal();
 
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = m_markedForUpdate;
+		m_markedForUpdate = false;
+		if(updated)
+		{
+			updateInternal();
+		}
+
+		return Error::kNone;
+	}
+
 	void draw(RenderQueueDrawContext& ctx) const;
 };
 /// @}

+ 7 - 7
AnKi/Scene/Components/FogDensityComponent.h

@@ -113,13 +113,6 @@ public:
 		}
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		updated = m_markedForUpdate;
-		m_markedForUpdate = false;
-		return Error::kNone;
-	}
-
 private:
 	Vec3 m_aabbMin = Vec3(0.0f);
 
@@ -134,6 +127,13 @@ private:
 
 	Bool m_isBox : 1;
 	Bool m_markedForUpdate : 1;
+
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = m_markedForUpdate;
+		m_markedForUpdate = false;
+		return Error::kNone;
+	}
 };
 
 } // end namespace anki

+ 7 - 7
AnKi/Scene/Components/FrustumComponent.h

@@ -292,13 +292,6 @@ public:
 		return true;
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		ANKI_ASSERT(info.m_node == m_node);
-		updated = updateInternal();
-		return Error::kNone;
-	}
-
 	void setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag bits);
 
 	FrustumComponentVisibilityTestFlag getEnabledVisibilityTests() const
@@ -473,6 +466,13 @@ private:
 	Bool m_miscMarkedForUpdate : 1;
 
 	Bool updateInternal();
+
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		ANKI_ASSERT(info.m_node == m_node);
+		updated = updateInternal();
+		return Error::kNone;
+	}
 };
 /// @}
 

+ 4 - 0
AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp

@@ -26,6 +26,10 @@ GlobalIlluminationProbeComponent::GlobalIlluminationProbeComponent(SceneNode* no
 	}
 }
 
+GlobalIlluminationProbeComponent::~GlobalIlluminationProbeComponent()
+{
+}
+
 void GlobalIlluminationProbeComponent::draw(RenderQueueDrawContext& ctx) const
 {
 	const Aabb box = getAabbWorldSpace();

+ 9 - 7
AnKi/Scene/Components/GlobalIlluminationProbeComponent.h

@@ -22,6 +22,8 @@ class GlobalIlluminationProbeComponent : public SceneComponent
 public:
 	GlobalIlluminationProbeComponent(SceneNode* node);
 
+	~GlobalIlluminationProbeComponent();
+
 	/// Set the bounding box size.
 	void setBoxVolumeSize(const Vec3& sizeXYZ)
 	{
@@ -104,13 +106,6 @@ public:
 		m_shapeDirty = true;
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		updated = m_shapeDirty;
-		m_shapeDirty = false;
-		return Error::kNone;
-	}
-
 private:
 	SceneNode* m_node;
 	U64 m_uuid;
@@ -146,6 +141,13 @@ private:
 	}
 
 	void draw(RenderQueueDrawContext& ctx) const;
+
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = m_shapeDirty;
+		m_shapeDirty = false;
+		return Error::kNone;
+	}
 };
 /// @}
 

+ 1 - 2
AnKi/Scene/Components/GpuParticleEmitterComponent.h

@@ -34,8 +34,6 @@ public:
 		return m_particleEmitterResource;
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	/// Callback that will be used by the GenericGpuComputeJobComponent
 	static void simulateCallback(GenericGpuComputeJobQueueElementContext& ctx, const void* userData)
 	{
@@ -87,6 +85,7 @@ private:
 
 	Bool m_markedForUpdate = true;
 
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 	void simulate(GenericGpuComputeJobQueueElementContext& ctx) const;
 	void draw(RenderQueueDrawContext& ctx) const;
 };

+ 1 - 1
AnKi/Scene/Components/JointComponent.h

@@ -37,7 +37,7 @@ public:
 	/// Create a hinge joint on the BodyComponent of the SceneNode.
 	void newHingeJoint(const Vec3& relPosFactor, const Vec3& axis, F32 brakingImpulse = kMaxF32);
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 
 private:
 	class JointNode;

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

@@ -135,8 +135,6 @@ public:
 		m_shadow = x;
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	void setupPointLightQueueElement(PointLightQueueElement& el) const
 	{
 		ANKI_ASSERT(m_type == LightComponentType::kPoint);
@@ -222,6 +220,8 @@ private:
 	U8 m_shadow : 1;
 	U8 m_markedForUpdate : 1;
 
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
+
 	void draw(RenderQueueDrawContext& ctx) const;
 };
 /// @}

+ 7 - 7
AnKi/Scene/Components/ModelComponent.h

@@ -31,13 +31,6 @@ public:
 		return m_model;
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		updated = m_dirty;
-		m_dirty = false;
-		return Error::kNone;
-	}
-
 	ConstWeakArray<U64> getRenderMergeKeys() const
 	{
 		return m_modelPatchMergeKeys;
@@ -54,6 +47,13 @@ private:
 
 	DynamicArray<U64> m_modelPatchMergeKeys;
 	Bool m_dirty = true;
+
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = m_dirty;
+		m_dirty = false;
+		return Error::kNone;
+	}
 };
 /// @}
 

+ 6 - 0
AnKi/Scene/Components/MoveComponent.cpp

@@ -15,6 +15,7 @@ MoveComponent::MoveComponent(SceneNode* node)
 	, m_ignoreLocalTransform(false)
 	, m_ignoreParentTransform(false)
 {
+	getExternalSubsystems(*node).m_gpuSceneMemoryPool->allocate(sizeof(Mat3x4) * 2, alignof(F32), m_gpuSceneTransforms);
 	markForUpdate();
 }
 
@@ -85,4 +86,9 @@ Bool MoveComponent::updateWorldTransform(SceneNode& node)
 	return dirty;
 }
 
+void MoveComponent::onDestroy(SceneNode& node)
+{
+	getExternalSubsystems(node).m_gpuSceneMemoryPool->free(m_gpuSceneTransforms);
+}
+
 } // end namespace anki

+ 7 - 2
AnKi/Scene/Components/MoveComponent.h

@@ -91,8 +91,6 @@ public:
 		return m_prevWTrf;
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	/// @name Mess with the local transform
 	/// @{
 	void rotateLocalX(F32 angleRad)
@@ -151,6 +149,9 @@ private:
 	/// Keep the previous transformation for checking if it moved
 	Transform m_prevWTrf = Transform::getIdentity();
 
+	SceneNode* m_node = nullptr;
+	SegregatedListsGpuAllocatorToken m_gpuSceneTransforms;
+
 	Bool m_markedForUpdate : 1;
 	Bool m_ignoreLocalTransform : 1;
 	Bool m_ignoreParentTransform : 1;
@@ -162,6 +163,10 @@ private:
 
 	/// Called every frame. It updates the @a m_wtrf if @a shouldUpdateWTrf is true. Then it moves to the children.
 	Bool updateWorldTransform(SceneNode& node);
+
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
+
+	void onDestroy(SceneNode& node);
 };
 /// @}
 

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

@@ -30,8 +30,6 @@ public:
 
 	Error loadParticleEmitterResource(CString filename);
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	void setWorldTransform(const Transform& transform)
 	{
 		m_transform = transform;
@@ -93,6 +91,8 @@ private:
 
 	SimulationType m_simulationType = SimulationType::kUndefined;
 
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
+
 	template<typename TParticle>
 	void simulate(Second prevUpdateTime, Second crntTime, WeakArray<TParticle> particles);
 

+ 8 - 8
AnKi/Scene/Components/PlayerControllerComponent.h

@@ -41,14 +41,6 @@ public:
 		m_player->moveToPosition(pos);
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		const Transform newTrf = m_player->getTransform();
-		updated = newTrf != m_trf;
-		m_trf = newTrf;
-		return Error::kNone;
-	}
-
 	PhysicsPlayerControllerPtr getPhysicsPlayerController() const
 	{
 		return m_player;
@@ -57,6 +49,14 @@ public:
 private:
 	PhysicsPlayerControllerPtr m_player;
 	Transform m_trf = Transform::getIdentity();
+
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		const Transform newTrf = m_player->getTransform();
+		updated = newTrf != m_trf;
+		m_trf = newTrf;
+		return Error::kNone;
+	}
 };
 /// @}
 

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

@@ -73,13 +73,6 @@ public:
 		el.m_debugDrawCallbackUserData = this;
 	}
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override
-	{
-		updated = m_markedForUpdate;
-		m_markedForUpdate = false;
-		return Error::kNone;
-	}
-
 private:
 	SceneNode* m_node = nullptr;
 	U64 m_uuid = 0;
@@ -90,6 +83,13 @@ private:
 
 	ImageResourcePtr m_debugImage;
 
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = m_markedForUpdate;
+		m_markedForUpdate = false;
+		return Error::kNone;
+	}
+
 	static void reflectionProbeQueueElementFeedbackCallback(Bool fillRenderQueuesOnNextFrame, void* userData)
 	{
 		ANKI_ASSERT(userData);

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

@@ -14,6 +14,13 @@ namespace anki {
 
 ANKI_SCENE_COMPONENT_STATICS(RenderComponent)
 
+RenderComponent::RenderComponent(SceneNode* node)
+	: SceneComponent(node, getStaticClassId())
+{
+	getExternalSubsystems(*node).m_gpuSceneMemoryPool->allocate(sizeof(RenderableGpuView2), sizeof(U32),
+																m_gpuSceneRenderableGpuView);
+}
+
 void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, const RenderQueueDrawContext& ctx,
 											   ConstWeakArray<Mat3x4> transforms, ConstWeakArray<Mat3x4> prevTransforms,
 											   StagingGpuMemoryPool& alloc, const Vec4& positionScaleAndTranslation)
@@ -110,4 +117,9 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 	}
 }
 
+void RenderComponent::onDestroy(SceneNode& node)
+{
+	getExternalSubsystems(node).m_gpuSceneMemoryPool->free(m_gpuSceneRenderableGpuView);
+}
+
 } // end namespace anki

+ 5 - 4
AnKi/Scene/Components/RenderComponent.h

@@ -33,10 +33,7 @@ class RenderComponent : public SceneComponent
 	ANKI_SCENE_COMPONENT(RenderComponent)
 
 public:
-	RenderComponent(SceneNode* node)
-		: SceneComponent(node, getStaticClassId())
-	{
-	}
+	RenderComponent(SceneNode* node);
 
 	Bool isEnabled() const
 	{
@@ -114,6 +111,10 @@ private:
 	FillRayTracingInstanceQueueElementCallback m_rtCallback = nullptr;
 	const void* m_rtCallbackUserData = nullptr;
 	RenderComponentFlag m_flags = RenderComponentFlag::kNone;
+
+	SegregatedListsGpuAllocatorToken m_gpuSceneRenderableGpuView;
+
+	void onDestroy(SceneNode& node);
 };
 /// @}
 

+ 56 - 20
AnKi/Scene/Components/SceneComponent.cpp

@@ -8,37 +8,73 @@
 
 namespace anki {
 
-constexpr U32 kMaxSceneComponentClasses = 64;
-static_assert(kMaxSceneComponentClasses < 128, "It can oly be 7 bits because of SceneComponent::m_classId");
 static SceneComponentRtti* g_rttis[kMaxSceneComponentClasses] = {};
-static U32 g_rttiCount = 0;
+SceneComponentCallbacks g_sceneComponentCallbacks;
+static U32 g_sceneComponentClassCount = 0;
 
-SceneComponentRtti::SceneComponentRtti(const char* name, U32 size, U32 alignment, Constructor constructor)
+SceneComponentRtti::SceneComponentRtti(const char* name, U32 size, U32 alignment, SceneComponentVtable vtable)
 {
-	if(g_rttiCount >= kMaxSceneComponentClasses)
+	if(g_sceneComponentClassCount >= kMaxSceneComponentClasses)
 	{
 		// No special logging because this function is called before main
 		printf("Reached maximum component count. Increase kMaxSceneComponentClasses\n");
 		exit(-1);
 	}
 
-	m_constructorCallback = constructor;
 	m_className = name;
-	m_classSize = size;
-	m_classAlignment = alignment;
+	ANKI_ASSERT(size < getMaxNumericLimit<decltype(m_classSize)>());
+	m_classSize = decltype(m_classSize)(size);
+
+	ANKI_ASSERT(alignment < getMaxNumericLimit<decltype(m_classAlignment)>());
+	m_classAlignment = decltype(m_classAlignment)(alignment);
+
 	m_classId = kMaxU8;
 
-	g_rttis[g_rttiCount++] = this;
+	g_rttis[g_sceneComponentClassCount] = this;
+	g_sceneComponentCallbacks.m_constructors[g_sceneComponentClassCount] = vtable.m_constructor;
+	g_sceneComponentCallbacks.m_destructors[g_sceneComponentClassCount] = vtable.m_destructor;
+	g_sceneComponentCallbacks.m_onDestroys[g_sceneComponentClassCount] = vtable.m_onDestroy;
+	g_sceneComponentCallbacks.m_updates[g_sceneComponentClassCount] = vtable.m_update;
+	++g_sceneComponentClassCount;
 
 	// Sort everything because the IDs should be consistend between platforms and compilation builds
-	std::sort(&g_rttis[0], &g_rttis[g_rttiCount], [](const SceneComponentRtti* a, const SceneComponentRtti* b) {
-		return std::strcmp(a->m_className, b->m_className) < 0;
-	});
-
-	// Re-calculate the glass IDs
-	for(U32 i = 0; i < g_rttiCount; ++i)
 	{
-		g_rttis[i]->m_classId = U8(i);
+		// Copy to a temp array
+		class Temp
+		{
+		public:
+			SceneComponentRtti* m_rrti;
+			SceneComponentVtable m_vtable;
+		};
+
+		Temp temps[kMaxSceneComponentClasses];
+		for(U32 i = 0; i < g_sceneComponentClassCount; ++i)
+		{
+			temps[i].m_rrti = g_rttis[i];
+			temps[i].m_vtable = {g_sceneComponentCallbacks.m_constructors[i],
+								 g_sceneComponentCallbacks.m_destructors[i], g_sceneComponentCallbacks.m_onDestroys[i],
+								 g_sceneComponentCallbacks.m_updates[i]};
+		}
+
+		std::sort(&temps[0], &temps[g_sceneComponentClassCount], [](const Temp& a, const Temp& b) {
+			return std::strcmp(a.m_rrti->m_className, b.m_rrti->m_className) < 0;
+		});
+
+		// Re-calculate the glass IDs
+		for(U32 i = 0; i < g_sceneComponentClassCount; ++i)
+		{
+			temps[i].m_rrti->m_classId = U8(i);
+		}
+
+		// Copy back
+		for(U32 i = 0; i < g_sceneComponentClassCount; ++i)
+		{
+			g_rttis[i] = temps[i].m_rrti;
+			g_sceneComponentCallbacks.m_constructors[i] = temps[i].m_vtable.m_constructor;
+			g_sceneComponentCallbacks.m_destructors[i] = temps[i].m_vtable.m_destructor;
+			g_sceneComponentCallbacks.m_onDestroys[i] = temps[i].m_vtable.m_onDestroy;
+			g_sceneComponentCallbacks.m_updates[i] = temps[i].m_vtable.m_update;
+		}
 	}
 }
 
@@ -46,12 +82,12 @@ SceneComponent::SceneComponent([[maybe_unused]] SceneNode* node, U8 classId, Boo
 	: m_classId(classId & 0x7F)
 	, m_feedbackComponent(isFeedbackComponent)
 {
-	ANKI_ASSERT(classId < g_rttiCount);
+	ANKI_ASSERT(classId < g_sceneComponentClassCount);
 }
 
 const SceneComponentRtti& SceneComponent::findClassRtti(CString className)
 {
-	for(U32 i = 0; i < g_rttiCount; ++i)
+	for(U32 i = 0; i < g_sceneComponentClassCount; ++i)
 	{
 		ANKI_ASSERT(g_rttis[i]);
 		ANKI_ASSERT(g_rttis[i]->m_className);
@@ -65,9 +101,9 @@ const SceneComponentRtti& SceneComponent::findClassRtti(CString className)
 	return *g_rttis[0];
 }
 
-const SceneComponentRtti& SceneComponent::findClassRtti(U8 classId)
+const SceneComponentRtti& SceneComponent::getClassRtti(U8 classId)
 {
-	ANKI_ASSERT(classId < g_rttiCount);
+	ANKI_ASSERT(classId < g_sceneComponentClassCount);
 	ANKI_ASSERT(g_rttis[classId]);
 	return *g_rttis[classId];
 }

+ 83 - 28
AnKi/Scene/Components/SceneComponent.h

@@ -11,30 +11,71 @@
 
 namespace anki {
 
+// Forward
+class SceneComponentUpdateInfo;
+
 /// @addtogroup scene
 /// @{
 
+constexpr U32 kMaxSceneComponentClasses = 64;
+static_assert(kMaxSceneComponentClasses < 128, "It can oly be 7 bits because of SceneComponent::m_classId");
+
+using SceneComponentConstructorCallback = void (*)(SceneComponent& self, SceneNode& owner);
+using SceneComponentDestructorCallback = void (*)(SceneComponent& self);
+using SceneComponentOnDestroyCallback = void (*)(SceneComponent& self, SceneNode& owner);
+using SceneComponentUpdateCallback = Error (*)(SceneComponent& self, SceneComponentUpdateInfo& info, Bool& updated);
+
+class SceneComponentVtable
+{
+public:
+	SceneComponentConstructorCallback m_constructor;
+	SceneComponentDestructorCallback m_destructor;
+	SceneComponentOnDestroyCallback m_onDestroy;
+	SceneComponentUpdateCallback m_update;
+};
+
+/// Callbacks live in their own arrays for better caching.
+class SceneComponentCallbacks
+{
+public:
+	SceneComponentConstructorCallback m_constructors[kMaxSceneComponentClasses];
+	SceneComponentDestructorCallback m_destructors[kMaxSceneComponentClasses];
+	SceneComponentOnDestroyCallback m_onDestroys[kMaxSceneComponentClasses];
+	SceneComponentUpdateCallback m_updates[kMaxSceneComponentClasses];
+};
+
+extern SceneComponentCallbacks g_sceneComponentCallbacks;
+
 /// Scene component class info.
 class SceneComponentRtti
 {
 public:
-	using Constructor = void (*)(SceneComponent*, SceneNode*);
-
-	U8 m_classId;
 	const char* m_className;
-	U32 m_classSize;
-	U32 m_classAlignment;
-	Constructor m_constructorCallback;
+	U16 m_classSize;
+	U8 m_classAlignment;
+	U8 m_classId;
 
-	SceneComponentRtti(const char* name, U32 size, U32 alignment, Constructor constructor);
+	SceneComponentRtti(const char* name, U32 size, U32 alignment, SceneComponentVtable vtable);
 };
 
 /// Define a scene component.
 #define ANKI_SCENE_COMPONENT(className) \
 	static SceneComponentRtti _m_rtti; \
-	static void _construct(SceneComponent* self, SceneNode* node) \
+	static void _construct(SceneComponent& self, SceneNode& node) \
+	{ \
+		callConstructor(static_cast<className&>(self), &node); \
+	} \
+	static void _destruct(SceneComponent& self) \
+	{ \
+		callDestructor(static_cast<className&>(self)); \
+	} \
+	static void _onDestroy(SceneComponent& self, SceneNode& node) \
+	{ \
+		static_cast<className&>(self).onDestroy(node); \
+	} \
+	static Error _update(SceneComponent& self, SceneComponentUpdateInfo& info, Bool& updated) \
 	{ \
-		::new(self) className(node); \
+		return static_cast<className&>(self).update(info, updated); \
 	} \
 \
 public: \
@@ -47,8 +88,9 @@ private:
 
 /// Define the statics of a scene component.
 #define ANKI_SCENE_COMPONENT_STATICS(className) \
-	SceneComponentRtti className::_m_rtti(ANKI_STRINGIZE(className), sizeof(className), alignof(className), \
-										  className::_construct);
+	SceneComponentRtti className::_m_rtti( \
+		ANKI_STRINGIZE(className), sizeof(className), alignof(className), \
+		{className::_construct, className::_destruct, className::_onDestroy, className::_update});
 
 /// Passed to SceneComponent::update.
 /// @memberof SceneComponent
@@ -68,17 +110,14 @@ public:
 	}
 };
 
-/// Scene node component
+/// Scene node component.
+/// @note Doesn't have C++ virtuals to keep it compact.
 class SceneComponent
 {
 public:
 	/// Construct the scene component.
 	SceneComponent(SceneNode* node, U8 classId, Bool isFeedbackComponent = false);
 
-	virtual ~SceneComponent()
-	{
-	}
-
 	U8 getClassId() const
 	{
 		return m_classId;
@@ -94,30 +133,46 @@ public:
 		return m_feedbackComponent;
 	}
 
-	/// Do some updating
-	/// @param[in,out] info Update info.
-	/// @param[out] updated true if an update happened.
-	virtual Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	static const SceneComponentRtti& findClassRtti(CString className);
+
+	static const SceneComponentRtti& getClassRtti(U8 classId);
+
+	ANKI_INTERNAL void onDestroyReal(SceneNode& node)
 	{
-		updated = false;
-		return Error::kNone;
+		g_sceneComponentCallbacks.m_onDestroys[m_classId](*this, node);
+	}
+
+	ANKI_INTERNAL Error updateReal(SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		return g_sceneComponentCallbacks.m_updates[m_classId](*this, info, updated);
 	}
 
-	/// Don't call it.
-	void setTimestamp(Timestamp timestamp)
+	/// Don't call it directly.
+	ANKI_INTERNAL void setTimestamp(Timestamp timestamp)
 	{
 		ANKI_ASSERT(timestamp > 0);
 		ANKI_ASSERT(timestamp >= m_timestamp);
 		m_timestamp = timestamp;
 	}
 
-	static const SceneComponentRtti& findClassRtti(CString className);
-
-	static const SceneComponentRtti& findClassRtti(U8 classId);
-
 protected:
 	static SceneGraphExternalSubsystems& getExternalSubsystems(const SceneNode& node);
 
+	/// Pseudo-virtual
+	void onDestroy([[maybe_unused]] SceneNode& node)
+	{
+		// Do nothing
+	}
+
+	/// Pseudo-virtual to update the component.
+	/// @param[in,out] info Update info.
+	/// @param[out] updated true if an update happened.
+	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
+	{
+		updated = false;
+		return Error::kNone;
+	}
+
 private:
 	Timestamp m_timestamp = 1; ///< Indicates when an update happened
 	U8 m_classId : 7; ///< Cache the type ID.

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

@@ -26,8 +26,6 @@ public:
 
 	Error loadScriptResource(CString fname);
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	Bool isEnabled() const
 	{
 		return m_script.isCreated();
@@ -37,6 +35,8 @@ private:
 	SceneNode* m_node;
 	ScriptResourcePtr m_script;
 	ScriptEnvironment* m_env = nullptr;
+
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 };
 /// @}
 

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

@@ -49,8 +49,6 @@ public:
 	/// Load the skeleton resource.
 	Error loadSkeletonResource(CString filename);
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	void playAnimation(U32 track, AnimationResourcePtr anim, const AnimationPlayInfo& info);
 
 	ConstWeakArray<Mat4> getBoneTransforms() const
@@ -108,6 +106,8 @@ private:
 	U8 m_crntBoneTrfs = 0;
 	U8 m_prevBoneTrfs = 1;
 
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
+
 	void visitBones(const Bone& bone, const Mat4& parentTrf, const BitSet<128, U8>& bonesAnimated, Vec4& minExtend,
 					Vec4& maxExtend);
 };

+ 4 - 0
AnKi/Scene/Components/SpatialComponent.cpp

@@ -22,6 +22,8 @@ SpatialComponent::SpatialComponent(SceneNode* node)
 	ANKI_ASSERT(node);
 	m_octreeInfo.m_userData = this;
 	setAabbWorldSpace(Aabb(Vec3(-1.0f), Vec3(1.0f)));
+
+	getExternalSubsystems(*node).m_gpuSceneMemoryPool->allocate(sizeof(Vec3) * 2, alignof(F32), m_gpuSceneAabb);
 }
 
 SpatialComponent::~SpatialComponent()
@@ -32,6 +34,8 @@ SpatialComponent::~SpatialComponent()
 	}
 
 	m_convexHullPoints.destroy(m_node->getMemoryPool());
+
+	getExternalSubsystems(*m_node).m_gpuSceneMemoryPool->free(m_gpuSceneAabb);
 }
 
 void SpatialComponent::setConvexHullWorldSpace(const ConvexHullShape& hull)

+ 4 - 2
AnKi/Scene/Components/SpatialComponent.h

@@ -110,8 +110,6 @@ public:
 		return m_alwaysVisible;
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 private:
 	SceneNode* m_node;
 
@@ -133,10 +131,14 @@ private:
 
 	OctreePlaceable m_octreeInfo;
 
+	SegregatedListsGpuAllocatorToken m_gpuSceneAabb;
+
 	Bool m_markedForUpdate : 1;
 	Bool m_placed : 1;
 	Bool m_updateOctreeBounds : 1;
 	Bool m_alwaysVisible : 1;
+
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 };
 /// @}
 

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

@@ -26,8 +26,6 @@ public:
 
 	~TriggerComponent();
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
 	void setSphereVolumeRadius(F32 radius);
 
 	Transform getWorldTransform() const
@@ -68,6 +66,8 @@ private:
 	DynamicArray<BodyComponent*> m_bodiesInside;
 	DynamicArray<BodyComponent*> m_bodiesExit;
 	MyPhysicsTriggerProcessContactCallback* m_callbacks = nullptr;
+
+	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 };
 /// @}
 

+ 2 - 2
AnKi/Scene/DecalNode.cpp

@@ -21,7 +21,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -48,7 +48,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 2 - 2
AnKi/Scene/FogDensityNode.cpp

@@ -20,7 +20,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -46,7 +46,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 2 - 2
AnKi/Scene/GlobalIlluminationProbeNode.cpp

@@ -23,7 +23,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -54,7 +54,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 2 - 2
AnKi/Scene/GpuParticleEmitterNode.cpp

@@ -23,7 +23,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -51,7 +51,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 4 - 4
AnKi/Scene/LightNode.cpp

@@ -24,7 +24,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -52,7 +52,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -209,7 +209,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -287,7 +287,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 		const MoveComponent& move = info.m_node->getComponentAt<MoveComponent>(0);

+ 1 - 1
AnKi/Scene/ModelNode.cpp

@@ -29,7 +29,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 		static_cast<ModelNode&>(*info.m_node).feedbackUpdate();

+ 2 - 2
AnKi/Scene/ParticleEmitterNode.cpp

@@ -22,7 +22,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false; // Don't care about updates for this component
 
@@ -50,7 +50,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 		static_cast<ParticleEmitterNode&>(*info.m_node).onShapeUpdate();

+ 2 - 2
AnKi/Scene/PlayerNode.cpp

@@ -24,7 +24,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -75,7 +75,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 2 - 2
AnKi/Scene/ReflectionProbeNode.cpp

@@ -24,7 +24,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 
@@ -53,7 +53,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) override
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 1 - 1
AnKi/Scene/SceneGraph.cpp

@@ -257,7 +257,7 @@ Error SceneGraph::updateNode(Second prevTime, Second crntTime, SceneNode& node)
 		else
 		{
 			componentUpdateInfo.m_node = &node;
-			err = comp.update(componentUpdateInfo, updated);
+			err = comp.updateReal(componentUpdateInfo, updated);
 		}
 
 		if(updated)

+ 5 - 4
AnKi/Scene/SceneNode.cpp

@@ -22,11 +22,12 @@ SceneNode::~SceneNode()
 {
 	HeapMemoryPool& pool = getMemoryPool();
 
-	auto it = m_components.getBegin();
-	auto end = m_components.getEnd();
-	for(; it != end; ++it)
+	for(SceneComponent* comp : m_components)
 	{
-		deleteInstance(pool, *it);
+		comp->onDestroyReal(*this);
+		g_sceneComponentCallbacks.m_destructors[comp->getClassId()](*comp);
+
+		pool.free(comp);
 	}
 
 	Base::destroy(pool);

+ 1 - 1
AnKi/Scene/TriggerNode.cpp

@@ -23,7 +23,7 @@ public:
 	{
 	}
 
-	Error update(SceneComponentUpdateInfo& info, Bool& updated) final
+	Error update(SceneComponentUpdateInfo& info, Bool& updated)
 	{
 		updated = false;
 

+ 1 - 1
AnKi/Scene/Visibility.cpp

@@ -513,7 +513,7 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 					Bool updated;
 					SceneComponentUpdateInfo scUpdateInfo(0.0, 1.0);
 					scUpdateInfo.m_node = &node;
-					[[maybe_unused]] const Error err = cascadeFrustumComponents[i].update(scUpdateInfo, updated);
+					[[maybe_unused]] const Error err = cascadeFrustumComponents[i].updateReal(scUpdateInfo, updated);
 					ANKI_ASSERT(updated == true && !err);
 				}
 

+ 21 - 1
AnKi/Shaders/Include/GpuSceneTypes.h

@@ -5,10 +5,30 @@
 
 #pragma once
 
-#include <AnKi/Shaders/Include/Common.h>
+#include <AnKi/Shaders/Include/MeshTypes.h>
 
 ANKI_BEGIN_NAMESPACE
 
+struct RenderableGpuView2
+{
+	U32 m_worldTransformOffset;
+	U32 m_previousWorldTransformOffset;
+	U32 m_aabbOffset;
+	U32 m_uniformsOffset;
+	U32 m_meshOffset;
+	U32 m_boneTransformsOffset;
+};
+
+struct MeshGpuView
+{
+	Vec3 m_positionScale;
+	F32 m_positionTranslation;
+
+	U32 m_vertexOffsets[kMaxLodCount][kMaxVertexStreamIds];
+	U32 m_indexCounts[kMaxLodCount];
+	U32 m_indexOffsets[kMaxLodCount];
+};
+
 struct RenderableGpuView
 {
 	Mat3x4 m_worldTransform;

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

@@ -57,6 +57,8 @@ inline constexpr Array<Format, U32(VertexStreamId::kMeshRelatedCount)> kMeshRela
 	Format::kR16G16B16_Unorm, Format::kR8G8B8A8_Snorm, Format::kR8G8B8A8_Snorm,
 	Format::kR32G32_Sfloat,   Format::kR8G8B8A8_Uint,  Format::kR8G8B8A8_Snorm};
 
+constexpr U32 kMaxVertexStreamIds = 6u;
+
 #else
 
 // For regular geometry
@@ -74,6 +76,8 @@ const U32 kVertexStreamIdParticleAlpha = 2u;
 const U32 kVertexStreamIdParticleLife = 3u;
 const U32 kVertexStreamIdParticleStartingLife = 4u;
 const U32 kVertexStreamIdParticlePreviousPosition = 5u;
+
+const U32 kMaxVertexStreamIds = 6u;
 #endif
 
 ANKI_END_NAMESPACE

+ 4 - 1
AnKi/Util/SegregatedListsAllocatorBuilder.inl.h

@@ -10,7 +10,10 @@ namespace anki {
 template<typename TChunk, typename TInterface, typename TLock>
 SegregatedListsAllocatorBuilder<TChunk, TInterface, TLock>::~SegregatedListsAllocatorBuilder()
 {
-	ANKI_ASSERT(m_chunks.isEmpty() && "Forgot to free memory");
+	if(!m_chunks.isEmpty())
+	{
+		ANKI_UTIL_LOGE("Forgot to free memory");
+	}
 }
 
 template<typename TChunk, typename TInterface, typename TLock>