Browse Source

Merge pull request #121 from godlikepanos/gpu_occlusion

GPU based occlusion
Panagiotis Christopoulos Charitos 2 years ago
parent
commit
fe26924674
100 changed files with 3292 additions and 2679 deletions
  1. 2 2
      .clang-format
  2. 2 2
      .clang-format-hlsl
  3. 1 12
      AnKi.natvis
  4. 1 2
      AnKi/Collision/Aabb.cpp
  5. 2 2
      AnKi/Collision/Aabb.h
  6. 4 4
      AnKi/Collision/Cone.h
  7. 2 2
      AnKi/Collision/ConvexHullShape.h
  8. 5 1
      AnKi/Collision/Functions.h
  9. 152 6
      AnKi/Collision/FunctionsMisc.cpp
  10. 2 4
      AnKi/Collision/FunctionsTestPlane.cpp
  11. 1 2
      AnKi/Collision/GjkEpa.cpp
  12. 1 2
      AnKi/Collision/GjkEpa.h
  13. 2 2
      AnKi/Collision/LineSegment.h
  14. 1 2
      AnKi/Collision/Obb.cpp
  15. 3 3
      AnKi/Collision/Obb.h
  16. 2 2
      AnKi/Collision/Plane.h
  17. 3 4
      AnKi/Collision/Ray.h
  18. 1 2
      AnKi/Collision/Sphere.cpp
  19. 2 2
      AnKi/Collision/Sphere.h
  20. 3 2
      AnKi/Config.h.cmake
  21. 1 1
      AnKi/Core.h
  22. 0 46
      AnKi/Core/AllConfigVars.defs.h
  23. 104 225
      AnKi/Core/App.cpp
  24. 12 24
      AnKi/Core/App.h
  25. 13 12
      AnKi/Core/CMakeLists.txt
  26. 127 0
      AnKi/Core/CVarSet.cpp
  27. 230 0
      AnKi/Core/CVarSet.h
  28. 4 4
      AnKi/Core/Common.h
  29. 0 260
      AnKi/Core/ConfigSet.cpp
  30. 0 178
      AnKi/Core/ConfigSet.h
  31. 0 25
      AnKi/Core/ConfigVars.defs.h
  32. 46 23
      AnKi/Core/CoreTracer.cpp
  33. 10 2
      AnKi/Core/CoreTracer.h
  34. 47 0
      AnKi/Core/GpuMemory/GpuReadbackMemoryPool.cpp
  35. 108 0
      AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h
  36. 156 0
      AnKi/Core/GpuMemory/GpuSceneBuffer.cpp
  37. 191 0
      AnKi/Core/GpuMemory/GpuSceneBuffer.h
  38. 109 0
      AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h
  39. 96 0
      AnKi/Core/GpuMemory/RebarTransientMemoryPool.cpp
  40. 131 0
      AnKi/Core/GpuMemory/RebarTransientMemoryPool.h
  41. 53 0
      AnKi/Core/GpuMemory/UnifiedGeometryBuffer.cpp
  42. 147 0
      AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h
  43. 0 240
      AnKi/Core/GpuMemoryPools.cpp
  44. 0 230
      AnKi/Core/GpuMemoryPools.h
  45. 1 2
      AnKi/Core/MaliHwCounters.cpp
  46. 113 0
      AnKi/Core/StatsSet.cpp
  47. 342 0
      AnKi/Core/StatsSet.h
  48. 0 153
      AnKi/Core/StatsUi.cpp
  49. 0 37
      AnKi/Core/StatsUi.defs.h
  50. 0 136
      AnKi/Core/StatsUi.h
  51. 30 8
      AnKi/Gr/AccelerationStructure.h
  52. 0 1
      AnKi/Gr/CMakeLists.txt
  53. 77 54
      AnKi/Gr/CommandBuffer.h
  54. 3 11
      AnKi/Gr/Common.cpp
  55. 48 44
      AnKi/Gr/Common.h
  56. 0 23
      AnKi/Gr/ConfigVars.defs.h
  57. 33 60
      AnKi/Gr/Gl/CommandBuffer.cpp
  58. 5 6
      AnKi/Gr/Gl/CommandBufferImpl.cpp
  59. 1 2
      AnKi/Gr/Gl/Common.cpp
  60. 1 2
      AnKi/Gr/Gl/Common.h
  61. 2 4
      AnKi/Gr/Gl/Fence.cpp
  62. 1 2
      AnKi/Gr/Gl/Framebuffer.cpp
  63. 9 12
      AnKi/Gr/Gl/FramebufferImpl.cpp
  64. 2 4
      AnKi/Gr/Gl/FramebufferImpl.h
  65. 3 5
      AnKi/Gr/Gl/GlState.cpp
  66. 2 4
      AnKi/Gr/Gl/GlState.h
  67. 1 2
      AnKi/Gr/Gl/GrManagerImpl.cpp
  68. 1 2
      AnKi/Gr/Gl/GrManagerImplSdl.cpp
  69. 2 4
      AnKi/Gr/Gl/RenderingThread.cpp
  70. 2 4
      AnKi/Gr/Gl/Shader.cpp
  71. 2 2
      AnKi/Gr/Gl/ShaderImpl.cpp
  72. 3 4
      AnKi/Gr/Gl/ShaderProgram.cpp
  73. 1 2
      AnKi/Gr/Gl/ShaderProgramImpl.h
  74. 8 13
      AnKi/Gr/Gl/StateTracker.h
  75. 11 19
      AnKi/Gr/Gl/TextureImpl.cpp
  76. 4 16
      AnKi/Gr/GrManager.h
  77. 151 151
      AnKi/Gr/RenderGraph.cpp
  78. 69 75
      AnKi/Gr/RenderGraph.h
  79. 35 36
      AnKi/Gr/RenderGraph.inl.h
  80. 1 3
      AnKi/Gr/Sampler.h
  81. 3 5
      AnKi/Gr/ShaderProgram.cpp
  82. 13 11
      AnKi/Gr/ShaderProgram.h
  83. 4 5
      AnKi/Gr/Texture.h
  84. 8 11
      AnKi/Gr/TextureView.h
  85. 9 12
      AnKi/Gr/Utils/Functions.cpp
  86. 8 9
      AnKi/Gr/Utils/Functions.h
  87. 23 7
      AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.cpp
  88. 18 8
      AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h
  89. 3 4
      AnKi/Gr/Utils/StackGpuMemoryPool.cpp
  90. 2 2
      AnKi/Gr/Utils/StackGpuMemoryPool.h
  91. 7 2
      AnKi/Gr/Vulkan/AccelerationStructure.cpp
  92. 60 45
      AnKi/Gr/Vulkan/AccelerationStructureImpl.cpp
  93. 13 8
      AnKi/Gr/Vulkan/AccelerationStructureImpl.h
  94. 22 26
      AnKi/Gr/Vulkan/BufferImpl.cpp
  95. 2 3
      AnKi/Gr/Vulkan/BufferImpl.h
  96. 79 67
      AnKi/Gr/Vulkan/CommandBuffer.cpp
  97. 8 8
      AnKi/Gr/Vulkan/CommandBufferFactory.cpp
  98. 6 25
      AnKi/Gr/Vulkan/CommandBufferFactory.h
  99. 46 82
      AnKi/Gr/Vulkan/CommandBufferImpl.cpp
  100. 217 106
      AnKi/Gr/Vulkan/CommandBufferImpl.h

+ 2 - 2
.clang-format

@@ -57,7 +57,7 @@ BreakConstructorInitializersBeforeComma: true
 BreakConstructorInitializers: BeforeColon
 BreakConstructorInitializers: BeforeColon
 BreakAfterJavaFieldAnnotations: false
 BreakAfterJavaFieldAnnotations: false
 BreakStringLiterals: true
 BreakStringLiterals: true
-ColumnLimit:     120
+ColumnLimit:     150
 CommentPragmas:  '^ IWYU pragma:'
 CommentPragmas:  '^ IWYU pragma:'
 QualifierAlignment: Leave
 QualifierAlignment: Leave
 CompactNamespaces: false
 CompactNamespaces: false
@@ -122,7 +122,7 @@ ObjCSpaceBeforeProtocolList: true
 PenaltyBreakAssignment: 2
 PenaltyBreakAssignment: 2
 PenaltyBreakBeforeFirstCallParameter: 19
 PenaltyBreakBeforeFirstCallParameter: 19
 PenaltyBreakComment: 300
 PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
+PenaltyBreakFirstLessLess: 150
 PenaltyBreakOpenParenthesis: 0
 PenaltyBreakOpenParenthesis: 0
 PenaltyBreakString: 1000
 PenaltyBreakString: 1000
 PenaltyBreakTemplateDeclaration: 10
 PenaltyBreakTemplateDeclaration: 10

+ 2 - 2
.clang-format-hlsl

@@ -57,7 +57,7 @@ BreakBeforeTernaryOperators: true
 BreakConstructorInitializers: BeforeColon
 BreakConstructorInitializers: BeforeColon
 BreakAfterJavaFieldAnnotations: false
 BreakAfterJavaFieldAnnotations: false
 BreakStringLiterals: true
 BreakStringLiterals: true
-ColumnLimit:     120
+ColumnLimit:     150
 CommentPragmas:  '^ IWYU pragma:'
 CommentPragmas:  '^ IWYU pragma:'
 QualifierAlignment: Leave
 QualifierAlignment: Leave
 CompactNamespaces: false
 CompactNamespaces: false
@@ -122,7 +122,7 @@ ObjCSpaceBeforeProtocolList: true
 PenaltyBreakAssignment: 2
 PenaltyBreakAssignment: 2
 PenaltyBreakBeforeFirstCallParameter: 19
 PenaltyBreakBeforeFirstCallParameter: 19
 PenaltyBreakComment: 300
 PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
+PenaltyBreakFirstLessLess: 150
 PenaltyBreakOpenParenthesis: 0
 PenaltyBreakOpenParenthesis: 0
 PenaltyBreakString: 1000
 PenaltyBreakString: 1000
 PenaltyBreakTemplateDeclaration: 10
 PenaltyBreakTemplateDeclaration: 10

+ 1 - 12
AnKi.natvis

@@ -34,17 +34,6 @@
 		</Expand>
 		</Expand>
 	</Type>
 	</Type>
 
 
-	<Type Name="anki::DynamicArrayRaii&lt;*&gt;">
-		<Intrinsic Name="size" Expression="m_size" />
-		<DisplayString>{{ size={m_size} capacity={m_capacity} }}</DisplayString>
-		<Expand>
-			<ArrayItems>
-				<Size>m_size</Size>
-				<ValuePointer>m_data</ValuePointer>
-			</ArrayItems>
-		</Expand>
-	</Type>
-
 	<Type Name="anki::Array&lt;*,*&gt;">
 	<Type Name="anki::Array&lt;*,*&gt;">
 		<DisplayString>{{ size={$T2} }}</DisplayString>
 		<DisplayString>{{ size={$T2} }}</DisplayString>
 		<Expand>
 		<Expand>
@@ -62,7 +51,7 @@
 		<DisplayString>{m_data.m_data,s}</DisplayString>
 		<DisplayString>{m_data.m_data,s}</DisplayString>
 	</Type>
 	</Type>
 
 
-	<Type Name="anki::BaseStringRaii&lt;*&gt;">
+	<Type Name="anki::BaseString&lt;*&gt;">
 		<DisplayString Condition="(bool)(m_data.m_data==0)">*Empty*</DisplayString>
 		<DisplayString Condition="(bool)(m_data.m_data==0)">*Empty*</DisplayString>
 		<DisplayString>{m_data.m_data,s}</DisplayString>
 		<DisplayString>{m_data.m_data,s}</DisplayString>
 	</Type>
 	</Type>

+ 1 - 2
AnKi/Collision/Aabb.cpp

@@ -38,8 +38,7 @@ Aabb Aabb::getCompoundShape(const Aabb& b) const
 	return out;
 	return out;
 }
 }
 
 
-void Aabb::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride,
-							 [[maybe_unused]] PtrSize buffSize)
+void Aabb::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride, [[maybe_unused]] PtrSize buffSize)
 {
 {
 	// Preconditions
 	// Preconditions
 	ANKI_ASSERT(pointBuffer);
 	ANKI_ASSERT(pointBuffer);

+ 2 - 2
AnKi/Collision/Aabb.h

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

+ 4 - 4
AnKi/Collision/Cone.h

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

+ 2 - 2
AnKi/Collision/ConvexHullShape.h

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

+ 5 - 1
AnKi/Collision/Functions.h

@@ -9,6 +9,7 @@
 #include <AnKi/Collision/Plane.h>
 #include <AnKi/Collision/Plane.h>
 #include <AnKi/Collision/Ray.h>
 #include <AnKi/Collision/Ray.h>
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Collision/Aabb.h>
+#include <AnKi/Util/WeakArray.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -225,7 +226,10 @@ void extractClipPlanes(const Mat4& mvp, Array<Plane, 6>& planes);
 void extractClipPlane(const Mat4& mvp, FrustumPlaneType id, Plane& plane);
 void extractClipPlane(const Mat4& mvp, FrustumPlaneType id, Plane& plane);
 
 
 /// Compute the edges of the far plane of a frustum
 /// Compute the edges of the far plane of a frustum
-void computeEdgesOfFrustum(F32 far, F32 fovX, F32 fovY, Vec4 points[4]);
+void computeEdgesOfFrustum(F32 far, F32 fovX, F32 fovY, Vec3 points[4]);
+
+/// Welzl's algorithm that computes a compact bounding sphere given a point cloud.
+Sphere computeBoundingSphere(ConstWeakArray<Vec3> points);
 
 
 /// @}
 /// @}
 
 

+ 152 - 6
AnKi/Collision/FunctionsMisc.cpp

@@ -4,11 +4,15 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #include <AnKi/Collision/Functions.h>
 #include <AnKi/Collision/Functions.h>
+#include <AnKi/Collision/Sphere.h>
 
 
 namespace anki {
 namespace anki {
 
 
 void extractClipPlane(const Mat4& mvp, FrustumPlaneType id, Plane& plane)
 void extractClipPlane(const Mat4& mvp, FrustumPlaneType id, Plane& plane)
 {
 {
+	// This code extracts the planes assuming the projection matrices are DX-like right-handed (eg D3DXMatrixPerspectiveFovRH)
+	// See "Fast Extraction of Viewing Frustum Planes from the WorldView-Projection Matrix" paper for more info
+
 #define ANKI_CASE(i, a, op, b) \
 #define ANKI_CASE(i, a, op, b) \
 	case i: \
 	case i: \
 	{ \
 	{ \
@@ -21,7 +25,14 @@ void extractClipPlane(const Mat4& mvp, FrustumPlaneType id, Plane& plane)
 
 
 	switch(id)
 	switch(id)
 	{
 	{
-		ANKI_CASE(FrustumPlaneType::kNear, 3, +, 2)
+	case FrustumPlaneType::kNear:
+	{
+		const Vec4 planeEqationCoefs = mvp.getRow(2);
+		const Vec4 n = planeEqationCoefs.xyz0();
+		const F32 len = n.getLength();
+		plane = Plane(n / len, -planeEqationCoefs.w() / len);
+		break;
+	}
 		ANKI_CASE(FrustumPlaneType::kFar, 3, -, 2)
 		ANKI_CASE(FrustumPlaneType::kFar, 3, -, 2)
 		ANKI_CASE(FrustumPlaneType::kLeft, 3, +, 0)
 		ANKI_CASE(FrustumPlaneType::kLeft, 3, +, 0)
 		ANKI_CASE(FrustumPlaneType::kRight, 3, -, 0)
 		ANKI_CASE(FrustumPlaneType::kRight, 3, -, 0)
@@ -42,17 +53,152 @@ void extractClipPlanes(const Mat4& mvp, Array<Plane, 6>& planes)
 	}
 	}
 }
 }
 
 
-void computeEdgesOfFrustum(F32 far, F32 fovX, F32 fovY, Vec4 points[4])
+void computeEdgesOfFrustum(F32 far, F32 fovX, F32 fovY, Vec3 points[4])
 {
 {
 	// This came from unprojecting. It works, don't touch it
 	// This came from unprojecting. It works, don't touch it
 	const F32 x = far * tan(fovY / 2.0f) * fovX / fovY;
 	const F32 x = far * tan(fovY / 2.0f) * fovX / fovY;
 	const F32 y = tan(fovY / 2.0f) * far;
 	const F32 y = tan(fovY / 2.0f) * far;
 	const F32 z = -far;
 	const F32 z = -far;
 
 
-	points[0] = Vec4(x, y, z, 0.0f); // top right
-	points[1] = Vec4(-x, y, z, 0.0f); // top left
-	points[2] = Vec4(-x, -y, z, 0.0f); // bot left
-	points[3] = Vec4(x, -y, z, 0.0f); // bot right
+	points[0] = Vec3(x, y, z); // top right
+	points[1] = Vec3(-x, y, z); // top left
+	points[2] = Vec3(-x, -y, z); // bot left
+	points[3] = Vec3(x, -y, z); // bot right
+}
+
+Vec4 computeBoundingSphereRecursive(WeakArray<const Vec3*> pPoints, U32 begin, U32 p, U32 b)
+{
+	Vec4 sphere;
+
+	switch(b)
+	{
+	case 0:
+		sphere = Vec4(0.0f, 0.0f, 0.0f, -1.0f);
+		break;
+	case 1:
+		sphere = Vec4(*pPoints[begin - 1], kEpsilonf);
+		break;
+	case 2:
+	{
+		const Vec3 O = *pPoints[begin - 1];
+		const Vec3 A = *pPoints[begin - 2];
+
+		const Vec3 a = A - O;
+
+		const Vec3 o = 0.5f * a;
+
+		const F32 radius = o.getLength() + kEpsilonf;
+		const Vec3 center = O + o;
+
+		sphere = Vec4(center, radius);
+		break;
+	}
+	case 3:
+	{
+		const Vec3 O = *pPoints[begin - 1];
+		const Vec3 A = *pPoints[begin - 2];
+		const Vec3 B = *pPoints[begin - 3];
+
+		const Vec3 a = A - O;
+		const Vec3 b = B - O;
+
+		const Vec3 acrossb = a.cross(b);
+		const F32 denominator = 2.0f * (acrossb.dot(acrossb));
+
+		Vec3 o = b.dot(b) * acrossb.cross(a);
+		o += a.dot(a) * b.cross(acrossb);
+		o /= denominator;
+
+		const F32 radius = o.getLength() + kEpsilonf;
+		const Vec3 center = O + o;
+
+		sphere = Vec4(center, radius);
+
+		return sphere;
+	}
+#if 0
+	// There is this case as well but it fails if points are coplanar so avoid it
+	case 4:
+	{
+		const Vec3 O = *pPoints[begin - 1];
+		const Vec3 A = *pPoints[begin - 2];
+		const Vec3 B = *pPoints[begin - 3];
+		const Vec3 C = *pPoints[begin - 4];
+
+		const Vec3 a = A - O;
+		const Vec3 b = B - O;
+		const Vec3 c = C - O;
+
+		auto compDet = [](F32 m11, F32 m12, F32 m13, F32 m21, F32 m22, F32 m23, F32 m31, F32 m32, F32 m33) {
+			return m11 * (m22 * m33 - m32 * m23) - m21 * (m12 * m33 - m32 * m13) + m31 * (m12 * m23 - m22 * m13);
+		};
+
+		const F32 denominator = 2.0f * compDet(a.x(), a.y(), a.z(), b.x(), b.y(), b.z(), c.x(), c.y(), c.z());
+
+		Vec3 o = c.dot(c) * a.cross(b);
+		o += b.dot(b) * c.cross(a);
+		o += a.dot(a) * b.cross(c);
+		o /= denominator;
+
+		const F32 radius = o.getLength() + kEpsilonf;
+		const Vec3 center = O + o;
+
+		sphere = Vec4(center, radius);
+
+		return sphere;
+	}
+#endif
+	default:
+		ANKI_ASSERT(0);
+	}
+
+	for(U32 i = 0; i < p; i++)
+	{
+		const F32 distSq = (sphere.xyz() - *pPoints[begin + i]).getLengthSquared();
+		const F32 radiusSq = sphere.w() * sphere.w();
+
+		if(distSq > radiusSq)
+		{
+			for(U32 j = i; j > 0; j--)
+			{
+				const Vec3* T = pPoints[begin + j];
+				pPoints[begin + j] = pPoints[begin + j - 1];
+				pPoints[begin + j - 1] = T;
+			}
+
+			sphere = computeBoundingSphereRecursive(pPoints, begin + 1, i, b + 1);
+		}
+	}
+
+	return sphere;
+}
+
+Sphere computeBoundingSphere(ConstWeakArray<Vec3> points)
+{
+	ANKI_ASSERT(points.getSize() >= 3);
+
+	DynamicArray<const Vec3*> pPointsDyn;
+	Array<const Vec3*, 8> pPointsArr;
+	WeakArray<const Vec3*> pPoints;
+
+	if(points.getSize() > pPointsArr.getSize())
+	{
+		pPointsDyn.resize(points.getSize());
+		pPoints = pPointsDyn;
+	}
+	else
+	{
+		pPoints = {&pPointsArr[0], points.getSize()};
+	}
+
+	for(U32 i = 0; i < points.getSize(); ++i)
+	{
+		pPoints[i] = &points[i];
+	}
+
+	const Vec4 sphere = computeBoundingSphereRecursive(pPoints, 0, pPoints.getSize(), 0);
+
+	return Sphere(sphere.xyz(), sphere.w());
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 4
AnKi/Collision/FunctionsTestPlane.cpp

@@ -13,8 +13,7 @@ F32 testPlane(const Plane& plane, const Aabb& aabb)
 	__m128 gezero = _mm_cmpge_ps(plane.getNormal().getSimd(), _mm_setzero_ps());
 	__m128 gezero = _mm_cmpge_ps(plane.getNormal().getSimd(), _mm_setzero_ps());
 
 
 	Vec4 diagMin;
 	Vec4 diagMin;
-	diagMin.getSimd() =
-		_mm_or_ps(_mm_and_ps(gezero, aabb.getMin().getSimd()), _mm_andnot_ps(gezero, aabb.getMax().getSimd()));
+	diagMin.getSimd() = _mm_or_ps(_mm_and_ps(gezero, aabb.getMin().getSimd()), _mm_andnot_ps(gezero, aabb.getMax().getSimd()));
 #else
 #else
 	Vec4 diagMin(0.0f), diagMax(0.0f);
 	Vec4 diagMin(0.0f), diagMax(0.0f);
 	// set min/max values for x,y,z direction
 	// set min/max values for x,y,z direction
@@ -43,8 +42,7 @@ F32 testPlane(const Plane& plane, const Aabb& aabb)
 
 
 #if ANKI_SIMD_SSE
 #if ANKI_SIMD_SSE
 	Vec4 diagMax;
 	Vec4 diagMax;
-	diagMax.getSimd() =
-		_mm_or_ps(_mm_and_ps(gezero, aabb.getMax().getSimd()), _mm_andnot_ps(gezero, aabb.getMin().getSimd()));
+	diagMax.getSimd() = _mm_or_ps(_mm_and_ps(gezero, aabb.getMax().getSimd()), _mm_andnot_ps(gezero, aabb.getMin().getSimd()));
 #endif
 #endif
 
 
 	ANKI_ASSERT(diagMax.w() == 0.0f);
 	ANKI_ASSERT(diagMax.w() == 0.0f);

+ 1 - 2
AnKi/Collision/GjkEpa.cpp

@@ -209,8 +209,7 @@ static Bool update(GjkContext& ctx, const GjkSupport& a)
 	return true;
 	return true;
 }
 }
 
 
-Bool gjkIntersection(const void* shape0, GjkSupportCallback shape0Callback, const void* shape1,
-					 GjkSupportCallback shape1Callback)
+Bool gjkIntersection(const void* shape0, GjkSupportCallback shape0Callback, const void* shape1, GjkSupportCallback shape1Callback)
 {
 {
 	ANKI_ASSERT(shape0 && shape0Callback && shape1 && shape1Callback);
 	ANKI_ASSERT(shape0 && shape0Callback && shape1 && shape1Callback);
 
 

+ 1 - 2
AnKi/Collision/GjkEpa.h

@@ -16,8 +16,7 @@ namespace anki {
 using GjkSupportCallback = Vec4 (*)(const void* shape, const Vec4& dir);
 using GjkSupportCallback = Vec4 (*)(const void* shape, const Vec4& dir);
 
 
 /// Return true if the two convex shapes intersect.
 /// Return true if the two convex shapes intersect.
-Bool gjkIntersection(const void* shape0, GjkSupportCallback shape0Callback, const void* shape1,
-					 GjkSupportCallback shape1Callback);
+Bool gjkIntersection(const void* shape0, GjkSupportCallback shape0Callback, const void* shape1, GjkSupportCallback shape1Callback);
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 2
AnKi/Collision/LineSegment.h

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

+ 1 - 2
AnKi/Collision/Obb.cpp

@@ -74,8 +74,7 @@ void Obb::getExtremePoints(Array<Vec4, 8>& points) const
 	}
 	}
 }
 }
 
 
-void Obb::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride,
-							[[maybe_unused]] PtrSize buffSize)
+void Obb::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride, [[maybe_unused]] PtrSize buffSize)
 {
 {
 	// Preconditions
 	// Preconditions
 	ANKI_ASSERT(pointBuffer);
 	ANKI_ASSERT(pointBuffer);

+ 3 - 3
AnKi/Collision/Obb.h

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

+ 2 - 2
AnKi/Collision/Plane.h

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

+ 3 - 4
AnKi/Collision/Ray.h

@@ -95,21 +95,20 @@ public:
 
 
 private:
 private:
 	Vec4 m_origin
 	Vec4 m_origin
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 		= Vec4(kMaxF32)
 #endif
 #endif
 		;
 		;
 
 
 	Vec4 m_dir
 	Vec4 m_dir
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		= Vec4(kMaxF32)
 		= Vec4(kMaxF32)
 #endif
 #endif
 		;
 		;
 
 
 	void check() const
 	void check() const
 	{
 	{
-		ANKI_ASSERT(m_origin.w() == 0.0f && m_dir.w() == 0.0f
-					&& isZero(m_dir.getLengthSquared() - 1.0f, kEpsilonf * 100.0f));
+		ANKI_ASSERT(m_origin.w() == 0.0f && m_dir.w() == 0.0f && isZero(m_dir.getLengthSquared() - 1.0f, kEpsilonf * 100.0f));
 	}
 	}
 };
 };
 /// @}
 /// @}

+ 1 - 2
AnKi/Collision/Sphere.cpp

@@ -31,8 +31,7 @@ Sphere Sphere::getCompoundShape(const Sphere& b) const
 	return Sphere((ca + cb) / 2.0f, (ca - cb).getLength() / 2.0f);
 	return Sphere((ca + cb) / 2.0f, (ca - cb).getLength() / 2.0f);
 }
 }
 
 
-void Sphere::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride,
-							   [[maybe_unused]] PtrSize buffSize)
+void Sphere::setFromPointCloud(const Vec3* pointBuffer, U pointCount, PtrSize pointStride, [[maybe_unused]] PtrSize buffSize)
 {
 {
 	// Calc center
 	// Calc center
 	{
 	{

+ 2 - 2
AnKi/Collision/Sphere.h

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

+ 3 - 2
AnKi/Config.h.cmake

@@ -21,7 +21,8 @@
 #define ANKI_DEBUG_SYMBOLS ${ANKI_DEBUG_SYMBOLS}
 #define ANKI_DEBUG_SYMBOLS ${ANKI_DEBUG_SYMBOLS}
 #define ANKI_OPTIMIZE ${ANKI_OPTIMIZE}
 #define ANKI_OPTIMIZE ${ANKI_OPTIMIZE}
 #define ANKI_TESTS ${ANKI_TESTS}
 #define ANKI_TESTS ${ANKI_TESTS}
-#define ANKI_ENABLE_TRACE ${_ANKI_ENABLE_TRACE}
+#define ANKI_TRACING_ENABLED ${_ANKI_TRACING_ENABLED}
+#define ANKI_STATS_ENABLED ${_ANKI_STATS_ENABLED}
 #define ANKI_SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
 #define ANKI_SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
 #define ANKI_DLSS ${_ANKI_DLSS_ENABLED}
 #define ANKI_DLSS ${_ANKI_DLSS_ENABLED}
 
 
@@ -166,7 +167,7 @@
 // Some compiler attributes
 // Some compiler attributes
 #if ANKI_COMPILER_GCC_COMPATIBLE
 #if ANKI_COMPILER_GCC_COMPATIBLE
 #	define ANKI_RESTRICT __restrict
 #	define ANKI_RESTRICT __restrict
-#	define ANKI_FORCE_INLINE __attribute__((always_inline))
+#	define ANKI_FORCE_INLINE inline __attribute__((always_inline))
 #	define ANKI_DONT_INLINE __attribute__((noinline))
 #	define ANKI_DONT_INLINE __attribute__((noinline))
 #	define ANKI_UNUSED __attribute__((__unused__))
 #	define ANKI_UNUSED __attribute__((__unused__))
 #	define ANKI_COLD __attribute__((cold, optimize("Os")))
 #	define ANKI_COLD __attribute__((cold, optimize("Os")))

+ 1 - 1
AnKi/Core.h

@@ -6,5 +6,5 @@
 #pragma once
 #pragma once
 
 
 #include <AnKi/Core/App.h>
 #include <AnKi/Core/App.h>
-#include <AnKi/Core/ConfigSet.h>
+#include <AnKi/Core/CVarSet.h>
 #include <AnKi/Core/CoreTracer.h>
 #include <AnKi/Core/CoreTracer.h>

+ 0 - 46
AnKi/Core/AllConfigVars.defs.h

@@ -1,46 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#if !defined(ANKI_CONFIG_VAR_GROUP)
-#	define ANKI_CONFIG_VAR_GROUP(name)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_U8)
-#	define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_U32)
-#	define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_PTR_SIZE)
-#	define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_F32)
-#	define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_BOOL)
-#	define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description)
-#endif
-
-#if !defined(ANKI_CONFIG_VAR_STRING)
-#	define ANKI_CONFIG_VAR_STRING(name, defaultValue, description)
-#endif
-
-#include <AnKi/Core/ConfigVars.defs.h>
-#include <AnKi/Gr/ConfigVars.defs.h>
-#include <AnKi/Resource/ConfigVars.defs.h>
-#include <AnKi/Scene/ConfigVars.defs.h>
-#include <AnKi/Renderer/ConfigVars.defs.h>
-
-#undef ANKI_CONFIG_VAR_GROUP
-#undef ANKI_CONFIG_VAR_U8
-#undef ANKI_CONFIG_VAR_U32
-#undef ANKI_CONFIG_VAR_PTR_SIZE
-#undef ANKI_CONFIG_VAR_F32
-#undef ANKI_CONFIG_VAR_BOOL
-#undef ANKI_CONFIG_VAR_STRING

+ 104 - 225
AnKi/Core/App.cpp

@@ -5,31 +5,32 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #include <AnKi/Core/App.h>
 #include <AnKi/Core/App.h>
-#include <AnKi/Core/ConfigSet.h>
+#include <AnKi/Core/CVarSet.h>
+#include <AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/Filesystem.h>
 #include <AnKi/Util/Filesystem.h>
 #include <AnKi/Util/System.h>
 #include <AnKi/Util/System.h>
-#include <AnKi/Util/ThreadHive.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Core/CoreTracer.h>
 #include <AnKi/Core/CoreTracer.h>
-#include <AnKi/Core/DeveloperConsole.h>
-#include <AnKi/Core/StatsUi.h>
+#include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
+#include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
+#include <AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h>
+#include <AnKi/Core/StatsSet.h>
 #include <AnKi/Window/NativeWindow.h>
 #include <AnKi/Window/NativeWindow.h>
 #include <AnKi/Core/MaliHwCounters.h>
 #include <AnKi/Core/MaliHwCounters.h>
 #include <AnKi/Window/Input.h>
 #include <AnKi/Window/Input.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Scene/SceneGraph.h>
-#include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Physics/PhysicsWorld.h>
 #include <AnKi/Physics/PhysicsWorld.h>
 #include <AnKi/Renderer/MainRenderer.h>
 #include <AnKi/Renderer/MainRenderer.h>
 #include <AnKi/Script/ScriptManager.h>
 #include <AnKi/Script/ScriptManager.h>
 #include <AnKi/Resource/ResourceFilesystem.h>
 #include <AnKi/Resource/ResourceFilesystem.h>
 #include <AnKi/Resource/AsyncLoader.h>
 #include <AnKi/Resource/AsyncLoader.h>
-#include <AnKi/Core/GpuMemoryPools.h>
 #include <AnKi/Ui/UiManager.h>
 #include <AnKi/Ui/UiManager.h>
 #include <AnKi/Ui/Canvas.h>
 #include <AnKi/Ui/Canvas.h>
+#include <AnKi/Scene/DeveloperConsoleUiNode.h>
 #include <csignal>
 #include <csignal>
 
 
 #if ANKI_OS_ANDROID
 #if ANKI_OS_ANDROID
@@ -43,7 +44,34 @@ namespace anki {
 android_app* g_androidApp = nullptr;
 android_app* g_androidApp = nullptr;
 #endif
 #endif
 
 
-void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
+StatCounter g_cpuTotalTimeStatVar(StatCategory::kTime, "CPU total", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+static StatCounter g_cpuAllocatedMemStatVar(StatCategory::kCpuMem, "Total", StatFlag::kBytes);
+static StatCounter g_cpuAllocationCountStatVar(StatCategory::kCpuMem, "Allocations/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame);
+static StatCounter g_cpuFreesCountStatVar(StatCategory::kCpuMem, "Frees/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame);
+
+NumericCVar<U32> g_windowWidthCVar(CVarSubsystem::kCore, "Width", 1920, 16, 16 * 1024, "Width");
+NumericCVar<U32> g_windowHeightCVar(CVarSubsystem::kCore, "Height", 1080, 16, 16 * 1024, "Height");
+NumericCVar<U32> g_windowFullscreenCVar(CVarSubsystem::kCore, "WindowFullscreen", 1, 0, 2,
+										"0: windowed, 1: borderless fullscreen, 2: exclusive fullscreen");
+NumericCVar<U32> g_targetFpsCVar(CVarSubsystem::kCore, "TargetFps", 60u, 1u, kMaxU32, "Target FPS");
+static NumericCVar<U32> g_jobThreadCountCVar(CVarSubsystem::kCore, "JobThreadCount", max(2u, getCpuCoresCount() / 2u), 2u, 1024u,
+											 "Number of job thread");
+NumericCVar<U32> g_displayStatsCVar(CVarSubsystem::kCore, "DisplayStats", 0, 0, 2, "Display stats, 0: None, 1: Simple, 2: Detailed");
+BoolCVar g_clearCachesCVar(CVarSubsystem::kCore, "ClearCaches", false, "Clear all caches");
+BoolCVar g_verboseLogCVar(CVarSubsystem::kCore, "VerboseLog", false, "Verbose logging");
+BoolCVar g_benchmarkModeCVar(CVarSubsystem::kCore, "BenchmarkMode", false, "Run in a benchmark mode. Fixed timestep, unlimited target FPS");
+NumericCVar<U32> g_benchmarkModeFrameCountCVar(CVarSubsystem::kCore, "BenchmarkModeFrameCount", 60 * 60 * 2, 1, kMaxU32,
+											   "How many frames the benchmark will run before it quits");
+
+#if ANKI_PLATFORM_MOBILE
+static StatCounter g_maliGpuActiveStatVar(StatCategory::kGpuMisc, "Mali active cycles", StatFlag::kMainThreadUpdates);
+static StatCounter g_maliGpuReadBandwidthStatVar(StatCategory::kGpuMisc, "Mali read bandwidth", StatFlag::kMainThreadUpdates);
+static StatCounter g_maliGpuWriteBandwidthStatVar(StatCategory::kGpuMisc, "Mali write bandwidth", StatFlag::kMainThreadUpdates);
+
+static BoolCVar g_maliHwCountersCVar(CVarSubsystem::kCore, "MaliHwCounters", false, "Enable Mali counters");
+#endif
+
+void* App::statsAllocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
 {
 {
 	ANKI_ASSERT(userData);
 	ANKI_ASSERT(userData);
 
 
@@ -70,15 +98,14 @@ void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, [[ma
 
 
 		// Allocate
 		// Allocate
 		App* self = static_cast<App*>(userData);
 		App* self = static_cast<App*>(userData);
-		Header* allocation = static_cast<Header*>(
-			self->m_originalAllocCallback(self->m_originalAllocUserData, nullptr, newSize, newAlignment));
+		Header* allocation = static_cast<Header*>(self->m_originalAllocCallback(self->m_originalAllocUserData, nullptr, newSize, newAlignment));
 		allocation->m_allocatedSize = size;
 		allocation->m_allocatedSize = size;
 		++allocation;
 		++allocation;
 		out = static_cast<void*>(allocation);
 		out = static_cast<void*>(allocation);
 
 
 		// Update stats
 		// Update stats
-		self->m_memStats.m_allocatedMem.fetchAdd(size);
-		self->m_memStats.m_allocCount.fetchAdd(1);
+		g_cpuAllocatedMemStatVar.increment(size);
+		g_cpuAllocationCountStatVar.increment(1);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -91,8 +118,8 @@ void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, [[ma
 		ANKI_ASSERT(allocation->m_allocatedSize > 0);
 		ANKI_ASSERT(allocation->m_allocatedSize > 0);
 
 
 		// Update stats
 		// Update stats
-		self->m_memStats.m_freeCount.fetchAdd(1);
-		self->m_memStats.m_allocatedMem.fetchSub(allocation->m_allocatedSize);
+		g_cpuAllocatedMemStatVar.decrement(allocation->m_allocatedSize);
+		g_cpuFreesCountStatVar.increment(1);
 
 
 		// Free
 		// Free
 		self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
 		self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
@@ -105,9 +132,6 @@ App::App(AllocAlignedCallback allocCb, void* allocCbUserData)
 {
 {
 	m_originalAllocCallback = allocCb;
 	m_originalAllocCallback = allocCb;
 	m_originalAllocUserData = allocCbUserData;
 	m_originalAllocUserData = allocCbUserData;
-
-	// Config set is a bit special so init it ASAP
-	ConfigSet::allocateSingleton(allocCb, allocCbUserData);
 }
 }
 
 
 App::~App()
 App::~App()
@@ -118,9 +142,6 @@ App::~App()
 
 
 void App::cleanup()
 void App::cleanup()
 {
 {
-	m_statsUi.reset(nullptr);
-	m_console.reset(nullptr);
-
 	SceneGraph::freeSingleton();
 	SceneGraph::freeSingleton();
 	ScriptManager::freeSingleton();
 	ScriptManager::freeSingleton();
 	MainRenderer::freeSingleton();
 	MainRenderer::freeSingleton();
@@ -128,21 +149,22 @@ void App::cleanup()
 	GpuSceneMicroPatcher::freeSingleton();
 	GpuSceneMicroPatcher::freeSingleton();
 	ResourceManager::freeSingleton();
 	ResourceManager::freeSingleton();
 	PhysicsWorld::freeSingleton();
 	PhysicsWorld::freeSingleton();
-	RebarStagingGpuMemoryPool::freeSingleton();
-	UnifiedGeometryMemoryPool::freeSingleton();
-	GpuSceneMemoryPool::freeSingleton();
-	CoreThreadHive::freeSingleton();
+	RebarTransientMemoryPool::freeSingleton();
+	GpuVisibleTransientMemoryPool::freeSingleton();
+	UnifiedGeometryBuffer::freeSingleton();
+	GpuSceneBuffer::freeSingleton();
+	GpuReadbackMemoryPool::freeSingleton();
+	CoreThreadJobManager::freeSingleton();
 	MaliHwCounters::freeSingleton();
 	MaliHwCounters::freeSingleton();
 	GrManager::freeSingleton();
 	GrManager::freeSingleton();
 	Input::freeSingleton();
 	Input::freeSingleton();
 	NativeWindow::freeSingleton();
 	NativeWindow::freeSingleton();
 
 
-#if ANKI_ENABLE_TRACE
+#if ANKI_TRACING_ENABLED
 	CoreTracer::freeSingleton();
 	CoreTracer::freeSingleton();
 #endif
 #endif
 
 
 	GlobalFrameIndex::freeSingleton();
 	GlobalFrameIndex::freeSingleton();
-	ConfigSet::freeSingleton();
 
 
 	m_settingsDir.destroy();
 	m_settingsDir.destroy();
 	m_cacheDir.destroy();
 	m_cacheDir.destroy();
@@ -165,9 +187,8 @@ Error App::init()
 
 
 Error App::initInternal()
 Error App::initInternal()
 {
 {
-	Logger::getSingleton().enableVerbosity(ConfigSet::getSingleton().getCoreVerboseLog());
-
-	setSignalHandlers();
+	StatsSet::getSingleton().initFromMainThread();
+	Logger::getSingleton().enableVerbosity(g_verboseLogCVar.get());
 
 
 	AllocAlignedCallback allocCb = m_originalAllocCallback;
 	AllocAlignedCallback allocCb = m_originalAllocCallback;
 	void* allocCbUserData = m_originalAllocUserData;
 	void* allocCbUserData = m_originalAllocUserData;
@@ -195,7 +216,7 @@ Error App::initInternal()
 #else
 #else
 		"NO extra checks, "
 		"NO extra checks, "
 #endif
 #endif
-#if ANKI_ENABLE_TRACE
+#if ANKI_TRACING_ENABLED
 		"built with tracing";
 		"built with tracing";
 #else
 #else
 		"NOT built with tracing";
 		"NOT built with tracing";
@@ -213,17 +234,16 @@ Error App::initInternal()
 #if ANKI_SIMD_SSE && ANKI_COMPILER_GCC_COMPATIBLE
 #if ANKI_SIMD_SSE && ANKI_COMPILER_GCC_COMPATIBLE
 	if(!__builtin_cpu_supports("sse4.2"))
 	if(!__builtin_cpu_supports("sse4.2"))
 	{
 	{
-		ANKI_CORE_LOGF(
-			"AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
+		ANKI_CORE_LOGF("AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
 	}
 	}
 #endif
 #endif
 
 
-	ANKI_CORE_LOGI("Number of job threads: %u", ConfigSet::getSingleton().getCoreJobThreadCount());
+	ANKI_CORE_LOGI("Number of job threads: %u", g_jobThreadCountCVar.get());
 
 
-	if(ConfigSet::getSingleton().getCoreBenchmarkMode() && ConfigSet::getSingleton().getGrVsync())
+	if(g_benchmarkModeCVar.get() && g_vsyncCVar.get())
 	{
 	{
 		ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
 		ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
-		ConfigSet::getSingleton().setGrVsync(false);
+		g_vsyncCVar.set(false);
 	}
 	}
 
 
 	GlobalFrameIndex::allocateSingleton();
 	GlobalFrameIndex::allocateSingleton();
@@ -231,7 +251,7 @@ Error App::initInternal()
 	//
 	//
 	// Core tracer
 	// Core tracer
 	//
 	//
-#if ANKI_ENABLE_TRACE
+#if ANKI_TRACING_ENABLED
 	ANKI_CHECK(CoreTracer::allocateSingleton().init(m_settingsDir));
 	ANKI_CHECK(CoreTracer::allocateSingleton().init(m_settingsDir));
 #endif
 #endif
 
 
@@ -239,13 +259,13 @@ Error App::initInternal()
 	// Window
 	// Window
 	//
 	//
 	NativeWindowInitInfo nwinit;
 	NativeWindowInitInfo nwinit;
-	nwinit.m_width = ConfigSet::getSingleton().getWidth();
-	nwinit.m_height = ConfigSet::getSingleton().getHeight();
+	nwinit.m_width = g_windowWidthCVar.get();
+	nwinit.m_height = g_windowHeightCVar.get();
 	nwinit.m_depthBits = 0;
 	nwinit.m_depthBits = 0;
 	nwinit.m_stencilBits = 0;
 	nwinit.m_stencilBits = 0;
-	nwinit.m_fullscreenDesktopRez = ConfigSet::getSingleton().getWindowFullscreen() > 0;
-	nwinit.m_exclusiveFullscreen = ConfigSet::getSingleton().getWindowFullscreen() == 2;
-	nwinit.m_targetFps = ConfigSet::getSingleton().getCoreTargetFps();
+	nwinit.m_fullscreenDesktopRez = g_windowFullscreenCVar.get() > 0;
+	nwinit.m_exclusiveFullscreen = g_windowFullscreenCVar.get() == 2;
+	nwinit.m_targetFps = g_targetFpsCVar.get();
 	NativeWindow::allocateSingleton();
 	NativeWindow::allocateSingleton();
 	ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
 	ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
 
 
@@ -259,7 +279,7 @@ Error App::initInternal()
 	// ThreadPool
 	// ThreadPool
 	//
 	//
 	const Bool pinThreads = !ANKI_OS_ANDROID;
 	const Bool pinThreads = !ANKI_OS_ANDROID;
-	CoreThreadHive::allocateSingleton(ConfigSet::getSingleton().getCoreJobThreadCount(), pinThreads);
+	CoreThreadJobManager::allocateSingleton(g_jobThreadCountCVar.get(), pinThreads);
 
 
 	//
 	//
 	// Graphics API
 	// Graphics API
@@ -273,18 +293,21 @@ Error App::initInternal()
 	//
 	//
 	// Mali HW counters
 	// Mali HW counters
 	//
 	//
-	if(GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm
-	   && ConfigSet::getSingleton().getCoreMaliHwCounters())
+#if ANKI_PLATFORM_MOBILE
+	if(ANKI_STATS_ENABLED && GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm && g_maliHwCountersCVar.get())
 	{
 	{
 		MaliHwCounters::allocateSingleton();
 		MaliHwCounters::allocateSingleton();
 	}
 	}
+#endif
 
 
 	//
 	//
 	// GPU mem
 	// GPU mem
 	//
 	//
-	UnifiedGeometryMemoryPool::allocateSingleton().init();
-	GpuSceneMemoryPool::allocateSingleton().init();
-	RebarStagingGpuMemoryPool::allocateSingleton().init();
+	UnifiedGeometryBuffer::allocateSingleton().init();
+	GpuSceneBuffer::allocateSingleton().init();
+	RebarTransientMemoryPool::allocateSingleton().init();
+	GpuVisibleTransientMemoryPool::allocateSingleton();
+	GpuReadbackMemoryPool::allocateSingleton();
 
 
 	//
 	//
 	// Physics
 	// Physics
@@ -303,8 +326,8 @@ Error App::initInternal()
 	String shadersPath;
 	String shadersPath;
 	getParentFilepath(executableFname, shadersPath);
 	getParentFilepath(executableFname, shadersPath);
 	shadersPath += ":";
 	shadersPath += ":";
-	shadersPath += ConfigSet::getSingleton().getRsrcDataPaths();
-	ConfigSet::getSingleton().setRsrcDataPaths(shadersPath);
+	shadersPath += g_dataPathsCVar.get();
+	g_dataPathsCVar.set(shadersPath);
 #endif
 #endif
 
 
 	ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));
 	ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));
@@ -323,8 +346,7 @@ Error App::initInternal()
 	// Renderer
 	// Renderer
 	//
 	//
 	MainRendererInitInfo renderInit;
 	MainRendererInitInfo renderInit;
-	renderInit.m_swapchainSize =
-		UVec2(NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
+	renderInit.m_swapchainSize = UVec2(NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
 	renderInit.m_allocCallback = allocCb;
 	renderInit.m_allocCallback = allocCb;
 	renderInit.m_allocCallbackUserData = allocCbUserData;
 	renderInit.m_allocCallbackUserData = allocCbUserData;
 	ANKI_CHECK(MainRenderer::allocateSingleton().init(renderInit));
 	ANKI_CHECK(MainRenderer::allocateSingleton().init(renderInit));
@@ -339,12 +361,6 @@ Error App::initInternal()
 	//
 	//
 	ANKI_CHECK(SceneGraph::allocateSingleton().init(allocCb, allocCbUserData));
 	ANKI_CHECK(SceneGraph::allocateSingleton().init(allocCb, allocCbUserData));
 
 
-	//
-	// Misc
-	//
-	ANKI_CHECK(UiManager::getSingleton().newInstance<StatsUi>(m_statsUi));
-	ANKI_CHECK(UiManager::getSingleton().newInstance<DeveloperConsole>(m_console));
-
 	ANKI_CORE_LOGI("Application initialized");
 	ANKI_CORE_LOGI("Application initialized");
 
 
 	return Error::kNone;
 	return Error::kNone;
@@ -376,7 +392,7 @@ Error App::initDirs()
 	m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
 	m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
 
 
 	const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
 	const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
-	if(ConfigSet::getSingleton().getCoreClearCaches() && cacheDirExists)
+	if(g_clearCachesCVar.get() && cacheDirExists)
 	{
 	{
 		ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
 		ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
 		ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
 		ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
@@ -400,7 +416,7 @@ Error App::mainLoop()
 	Second crntTime = prevUpdateTime;
 	Second crntTime = prevUpdateTime;
 
 
 	// Benchmark mode stuff:
 	// Benchmark mode stuff:
-	const Bool benchmarkMode = ConfigSet::getSingleton().getCoreBenchmarkMode();
+	const Bool benchmarkMode = g_benchmarkModeCVar.get();
 	Second aggregatedCpuTime = 0.0;
 	Second aggregatedCpuTime = 0.0;
 	Second aggregatedGpuTime = 0.0;
 	Second aggregatedGpuTime = 0.0;
 	constexpr U32 kBenchmarkFramesToGatherBeforeFlush = 60;
 	constexpr U32 kBenchmarkFramesToGatherBeforeFlush = 60;
@@ -431,59 +447,37 @@ Error App::mainLoop()
 
 
 			ANKI_CHECK(SceneGraph::getSingleton().update(prevUpdateTime, crntTime));
 			ANKI_CHECK(SceneGraph::getSingleton().update(prevUpdateTime, crntTime));
 
 
-			RenderQueue rqueue;
-			SceneGraph::getSingleton().doVisibilityTests(rqueue);
-
-			// Inject stats UI
-			CoreDynamicArray<UiQueueElement> newUiElementArr;
-			injectUiElements(newUiElementArr, rqueue);
-
 			// Render
 			// Render
 			TexturePtr presentableTex = GrManager::getSingleton().acquireNextPresentableTexture();
 			TexturePtr presentableTex = GrManager::getSingleton().acquireNextPresentableTexture();
-			MainRenderer::getSingleton().setStatsEnabled(ConfigSet::getSingleton().getCoreDisplayStats() > 0
-														 || benchmarkMode
-#if ANKI_ENABLE_TRACE
-														 || Tracer::getSingleton().getEnabled()
-#endif
-			);
-			ANKI_CHECK(MainRenderer::getSingleton().render(rqueue, presentableTex));
+			ANKI_CHECK(MainRenderer::getSingleton().render(presentableTex.get()));
 
 
-			// Pause and sync async loader. That will force all tasks before the pause to finish in this frame.
-			ResourceManager::getSingleton().getAsyncLoader().pause();
-
-			// If we get stats exclude the time of GR because it forces some GPU-CPU serialization. We don't want to
-			// count that
+			// If we get stats exclude the time of GR because it forces some GPU-CPU serialization. We don't want to count that
 			Second grTime = 0.0;
 			Second grTime = 0.0;
-			if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
+			if(benchmarkMode || g_displayStatsCVar.get() > 0) [[unlikely]]
 			{
 			{
 				grTime = HighRezTimer::getCurrentTime();
 				grTime = HighRezTimer::getCurrentTime();
 			}
 			}
 
 
 			GrManager::getSingleton().swapBuffers();
 			GrManager::getSingleton().swapBuffers();
 
 
-			if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
+			if(benchmarkMode || g_displayStatsCVar.get() > 0) [[unlikely]]
 			{
 			{
 				grTime = HighRezTimer::getCurrentTime() - grTime;
 				grTime = HighRezTimer::getCurrentTime() - grTime;
 			}
 			}
 
 
-			const PtrSize rebarMemUsed = RebarStagingGpuMemoryPool::getSingleton().endFrame();
-			UnifiedGeometryMemoryPool::getSingleton().endFrame();
-			GpuSceneMemoryPool::getSingleton().endFrame();
-
-			// Update the trace info with some async loader stats
-			U64 asyncTaskCount = ResourceManager::getSingleton().getAsyncLoader().getCompletedTaskCount();
-			ANKI_TRACE_INC_COUNTER(RsrcAsyncTasks, asyncTaskCount - m_resourceCompletedAsyncTaskCount);
-			m_resourceCompletedAsyncTaskCount = asyncTaskCount;
-
-			// Now resume the loader
-			ResourceManager::getSingleton().getAsyncLoader().resume();
+			RebarTransientMemoryPool::getSingleton().endFrame();
+			UnifiedGeometryBuffer::getSingleton().endFrame();
+			GpuSceneBuffer::getSingleton().endFrame();
+			GpuVisibleTransientMemoryPool::getSingleton().endFrame();
+			GpuReadbackMemoryPool::getSingleton().endFrame();
 
 
 			// Sleep
 			// Sleep
 			const Second endTime = HighRezTimer::getCurrentTime();
 			const Second endTime = HighRezTimer::getCurrentTime();
 			const Second frameTime = endTime - startTime;
 			const Second frameTime = endTime - startTime;
+			g_cpuTotalTimeStatVar.set((frameTime - grTime) * 1000.0);
 			if(!benchmarkMode) [[likely]]
 			if(!benchmarkMode) [[likely]]
 			{
 			{
-				const Second timerTick = 1.0_sec / Second(ConfigSet::getSingleton().getCoreTargetFps());
+				const Second timerTick = 1.0_sec / Second(g_targetFpsCVar.get());
 				if(frameTime < timerTick)
 				if(frameTime < timerTick)
 				{
 				{
 					ANKI_TRACE_SCOPED_EVENT(TimerTickSleep);
 					ANKI_TRACE_SCOPED_EVENT(TimerTickSleep);
@@ -494,7 +488,7 @@ Error App::mainLoop()
 			else
 			else
 			{
 			{
 				aggregatedCpuTime += frameTime - grTime;
 				aggregatedCpuTime += frameTime - grTime;
-				aggregatedGpuTime += MainRenderer::getSingleton().getStats().m_renderingGpuTime;
+				aggregatedGpuTime += 0; // TODO
 				++benchmarkFramesGathered;
 				++benchmarkFramesGathered;
 				if(benchmarkFramesGathered >= kBenchmarkFramesToGatherBeforeFlush)
 				if(benchmarkFramesGathered >= kBenchmarkFramesToGatherBeforeFlush)
 				{
 				{
@@ -509,70 +503,31 @@ Error App::mainLoop()
 			}
 			}
 
 
 			// Stats
 			// Stats
-			if(ConfigSet::getSingleton().getCoreDisplayStats() > 0)
-			{
-				StatsUiInput in;
-				in.m_cpuFrameTime = frameTime - grTime;
-				in.m_rendererTime = MainRenderer::getSingleton().getStats().m_renderingCpuTime;
-				in.m_sceneUpdateTime = SceneGraph::getSingleton().getStats().m_updateTime;
-				in.m_visibilityTestsTime = SceneGraph::getSingleton().getStats().m_visibilityTestsTime;
-				in.m_physicsTime = SceneGraph::getSingleton().getStats().m_physicsUpdate;
-
-				in.m_gpuFrameTime = MainRenderer::getSingleton().getStats().m_renderingGpuTime;
-
-				if(MaliHwCounters::isAllocated())
-				{
-					MaliHwCountersOut out;
-					MaliHwCounters::getSingleton().sample(out);
-					in.m_gpuActiveCycles = out.m_gpuActive;
-					in.m_gpuReadBandwidth = out.m_readBandwidth;
-					in.m_gpuWriteBandwidth = out.m_writeBandwidth;
-				}
-
-				in.m_cpuAllocatedMemory = m_memStats.m_allocatedMem.load();
-				in.m_cpuAllocationCount = m_memStats.m_allocCount.load();
-				in.m_cpuFreeCount = m_memStats.m_freeCount.load();
-
-				const GrManagerStats grStats = GrManager::getSingleton().getStats();
-				UnifiedGeometryMemoryPool::getSingleton().getStats(
-					in.m_unifiedGometryExternalFragmentation, in.m_unifiedGeometryAllocated, in.m_unifiedGeometryTotal);
-				GpuSceneMemoryPool::getSingleton().getStats(in.m_gpuSceneExternalFragmentation, in.m_gpuSceneAllocated,
-															in.m_gpuSceneTotal);
-				in.m_gpuDeviceMemoryAllocated = grStats.m_deviceMemoryAllocated;
-				in.m_gpuDeviceMemoryInUse = grStats.m_deviceMemoryInUse;
-				in.m_reBar = rebarMemUsed;
-
-				in.m_drawableCount = rqueue.countAllRenderables();
-				in.m_vkCommandBufferCount = grStats.m_commandBufferCount;
-
-				StatsUi& statsUi = *static_cast<StatsUi*>(m_statsUi.get());
-				const StatsUiDetail detail = (ConfigSet::getSingleton().getCoreDisplayStats() == 1)
-												 ? StatsUiDetail::kFpsOnly
-												 : StatsUiDetail::kDetailed;
-				statsUi.setStats(in, detail);
-			}
-
-#if ANKI_ENABLE_TRACE
-			if(m_renderer->getStats().m_renderingGpuTime >= 0.0)
+#if ANKI_PLATFORM_MOBILE
+			if(MaliHwCounters::isAllocated())
 			{
 			{
-				ANKI_TRACE_CUSTOM_EVENT(Gpu, m_renderer->getStats().m_renderingGpuSubmitTimestamp,
-										m_renderer->getStats().m_renderingGpuTime);
+				MaliHwCountersOut out;
+				MaliHwCounters::getSingleton().sample(out);
+				g_maliGpuActiveStatVar.set(out.m_gpuActive);
+				g_maliGpuReadBandwidthStatVar.set(out.m_readBandwidth);
+				g_maliGpuWriteBandwidthStatVar.set(out.m_writeBandwidth);
 			}
 			}
 #endif
 #endif
 
 
+			StatsSet::getSingleton().endFrame();
+
 			++GlobalFrameIndex::getSingleton().m_value;
 			++GlobalFrameIndex::getSingleton().m_value;
 
 
 			if(benchmarkMode) [[unlikely]]
 			if(benchmarkMode) [[unlikely]]
 			{
 			{
-				if(GlobalFrameIndex::getSingleton().m_value
-				   >= ConfigSet::getSingleton().getCoreBenchmarkModeFrameCount())
+				if(GlobalFrameIndex::getSingleton().m_value >= g_benchmarkModeFrameCountCVar.get())
 				{
 				{
 					quit = true;
 					quit = true;
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-#if ANKI_ENABLE_TRACE
+#if ANKI_TRACING_ENABLED
 		static U64 frame = 1;
 		static U64 frame = 1;
 		CoreTracer::getSingleton().flushFrame(frame++);
 		CoreTracer::getSingleton().flushFrame(frame++);
 #endif
 #endif
@@ -586,47 +541,11 @@ Error App::mainLoop()
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
-void App::injectUiElements(CoreDynamicArray<UiQueueElement>& newUiElementArr, RenderQueue& rqueue)
-{
-	const U32 originalCount = rqueue.m_uis.getSize();
-	if(ConfigSet::getSingleton().getCoreDisplayStats() > 0 || m_consoleEnabled)
-	{
-		const U32 extraElements = (ConfigSet::getSingleton().getCoreDisplayStats() > 0) + (m_consoleEnabled != 0);
-		newUiElementArr.resize(originalCount + extraElements);
-
-		if(originalCount > 0)
-		{
-			memcpy(&newUiElementArr[0], &rqueue.m_uis[0], rqueue.m_uis.getSizeInBytes());
-		}
-
-		rqueue.m_uis = WeakArray<UiQueueElement>(newUiElementArr);
-	}
-
-	U32 count = originalCount;
-	if(ConfigSet::getSingleton().getCoreDisplayStats() > 0)
-	{
-		newUiElementArr[count].m_userData = m_statsUi.get();
-		newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
-			static_cast<StatsUi*>(userData)->build(canvas);
-		};
-		++count;
-	}
-
-	if(m_consoleEnabled)
-	{
-		newUiElementArr[count].m_userData = m_console.get();
-		newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
-			static_cast<DeveloperConsole*>(userData)->build(canvas);
-		};
-		++count;
-	}
-}
-
 void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData)
 void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData)
 {
 {
-	if(ConfigSet::getSingleton().getCoreDisplayStats() > 1)
+	if(ANKI_STATS_ENABLED && g_displayStatsCVar.get() > 1)
 	{
 	{
-		allocCb = MemStats::allocCallback;
+		allocCb = statsAllocCallback;
 		allocCbUserData = this;
 		allocCbUserData = this;
 	}
 	}
 	else
 	else
@@ -635,52 +554,12 @@ void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserD
 	}
 	}
 }
 }
 
 
-void App::setSignalHandlers()
+Bool App::toggleDeveloperConsole()
 {
 {
-	auto handler = [](int signum) -> void {
-		const char* name = nullptr;
-		switch(signum)
-		{
-		case SIGABRT:
-			name = "SIGABRT";
-			break;
-		case SIGSEGV:
-			name = "SIGSEGV";
-			break;
-#if ANKI_POSIX
-		case SIGBUS:
-			name = "SIGBUS";
-			break;
-#endif
-		case SIGILL:
-			name = "SIGILL";
-			break;
-		case SIGFPE:
-			name = "SIGFPE";
-			break;
-		}
-
-		if(name)
-			printf("Caught signal %d (%s)\n", signum, name);
-		else
-			printf("Caught signal %d\n", signum);
-
-		U32 count = 0;
-		printf("Backtrace:\n");
-		backtrace([&count](CString symbol) {
-			printf("%.2u: %s\n", count++, symbol.cstr());
-		});
-
-		ANKI_DEBUG_BREAK();
-	};
-
-	signal(SIGSEGV, handler);
-	signal(SIGILL, handler);
-	signal(SIGFPE, handler);
-#if ANKI_POSIX
-	signal(SIGBUS, handler);
-#endif
-	// Ignore for now: signal(SIGABRT, handler);
+	SceneNode& node = SceneGraph::getSingleton().findSceneNode("_DevConsole");
+	static_cast<DeveloperConsoleUiNode&>(node).toggleConsole();
+	m_consoleEnabled = static_cast<DeveloperConsoleUiNode&>(node).isConsoleEnabled();
+	return m_consoleEnabled;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 12 - 24
AnKi/Core/App.h

@@ -5,7 +5,7 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <AnKi/Core/Common.h>
+#include <AnKi/Core/CVarSet.h>
 #include <AnKi/Util/String.h>
 #include <AnKi/Util/String.h>
 #include <AnKi/Util/Ptr.h>
 #include <AnKi/Util/Ptr.h>
 #include <AnKi/Ui/UiImmediateModeBuilder.h>
 #include <AnKi/Ui/UiImmediateModeBuilder.h>
@@ -15,6 +15,14 @@ namespace anki {
 // Forward
 // Forward
 class UiQueueElement;
 class UiQueueElement;
 class RenderQueue;
 class RenderQueue;
+class StatCounter;
+extern NumericCVar<U32> g_windowWidthCVar;
+extern NumericCVar<U32> g_windowHeightCVar;
+extern NumericCVar<U32> g_windowFullscreenCVar;
+extern NumericCVar<U32> g_targetFpsCVar;
+extern NumericCVar<U32> g_displayStatsCVar;
+extern StatCounter g_cpuTotalTimeStatVar;
+extern StatCounter g_rendererGpuTimeStatVar;
 
 
 /// The core class of the engine.
 /// The core class of the engine.
 class App
 class App
@@ -47,37 +55,22 @@ public:
 		return Error::kNone;
 		return Error::kNone;
 	}
 	}
 
 
-	void setDisplayDeveloperConsole(Bool display)
-	{
-		m_consoleEnabled = display;
-	}
+	Bool toggleDeveloperConsole();
 
 
-	Bool getDisplayDeveloperConsole() const
+	Bool getDeveloperConsoleEnabled() const
 	{
 	{
 		return m_consoleEnabled;
 		return m_consoleEnabled;
 	}
 	}
 
 
 private:
 private:
-	// Misc
-	UiImmediateModeBuilderPtr m_statsUi;
-	UiImmediateModeBuilderPtr m_console;
 	Bool m_consoleEnabled = false;
 	Bool m_consoleEnabled = false;
 	CoreString m_settingsDir; ///< The path that holds the configuration
 	CoreString m_settingsDir; ///< The path that holds the configuration
 	CoreString m_cacheDir; ///< This is used as a cache
 	CoreString m_cacheDir; ///< This is used as a cache
-	U64 m_resourceCompletedAsyncTaskCount = 0;
 
 
 	void* m_originalAllocUserData = nullptr;
 	void* m_originalAllocUserData = nullptr;
 	AllocAlignedCallback m_originalAllocCallback = nullptr;
 	AllocAlignedCallback m_originalAllocCallback = nullptr;
 
 
-	class MemStats
-	{
-	public:
-		Atomic<PtrSize> m_allocatedMem = {0};
-		Atomic<U64> m_allocCount = {0};
-		Atomic<U64> m_freeCount = {0};
-
-		static void* allocCallback(void* userData, void* ptr, PtrSize size, PtrSize alignment);
-	} m_memStats;
+	static void* statsAllocCallback(void* userData, void* ptr, PtrSize size, PtrSize alignment);
 
 
 	void initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData);
 	void initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData);
 
 
@@ -85,11 +78,6 @@ private:
 
 
 	Error initDirs();
 	Error initDirs();
 	void cleanup();
 	void cleanup();
-
-	/// Inject a new UI element in the render queue for displaying various stuff.
-	void injectUiElements(CoreDynamicArray<UiQueueElement>& elements, RenderQueue& rqueue);
-
-	void setSignalHandlers();
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

+ 13 - 12
AnKi/Core/CMakeLists.txt

@@ -1,25 +1,26 @@
 set(sources
 set(sources
 	App.cpp
 	App.cpp
-	ConfigSet.cpp
-	GpuMemoryPools.cpp
-	DeveloperConsole.cpp
+	CVarSet.cpp
 	CoreTracer.cpp
 	CoreTracer.cpp
 	MaliHwCounters.cpp
 	MaliHwCounters.cpp
-	StatsUi.cpp)
+	StatsSet.cpp
+	GpuMemory/UnifiedGeometryBuffer.cpp
+	GpuMemory/GpuSceneBuffer.cpp
+	GpuMemory/RebarTransientMemoryPool.cpp
+	GpuMemory/GpuReadbackMemoryPool.cpp)
 
 
 set(headers
 set(headers
-	AllConfigVars.defs.h
 	App.h
 	App.h
 	Common.h
 	Common.h
-	ConfigSet.h
-	ConfigVars.defs.h
+	CVarSet.h
 	CoreTracer.h
 	CoreTracer.h
-	DeveloperConsole.h
-	GpuMemoryPools.h
 	MaliHwCounters.h
 	MaliHwCounters.h
-	StatsUi.h
-	StatsUi.defs.h
-	StdinListener.h)
+	StatsSet.h
+	StdinListener.h
+	GpuMemory/UnifiedGeometryBuffer.h
+	GpuMemory/GpuSceneBuffer.h
+	GpuMemory/RebarTransientMemoryPool.h
+	GpuMemory/GpuReadbackMemoryPool.h)
 
 
 add_library(AnKiCore ${sources} ${headers})
 add_library(AnKiCore ${sources} ${headers})
 
 

+ 127 - 0
AnKi/Core/CVarSet.cpp

@@ -0,0 +1,127 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/CVarSet.h>
+#include <AnKi/Util/Xml.h>
+#include <AnKi/Util/Logger.h>
+#include <AnKi/Util/File.h>
+
+// Because some cvars set their default values
+#include <AnKi/Util/System.h>
+#include <AnKi/Shaders/Include/ClusteredShadingTypes.h>
+
+namespace anki {
+
+static constexpr Array<CString, U32(CVarSubsystem::kCount)> g_cvarSubsystemNames = {"Core", "R", "Gr", "Rsrc", "Scene"};
+
+void CVar::getFullNameInternal(Array<Char, 256>& arr) const
+{
+	snprintf(arr.getBegin(), arr.getSize(), "%s.%s", g_cvarSubsystemNames[m_subsystem].cstr(), m_name.cstr());
+}
+
+CoreString CVar::getFullName() const
+{
+	CoreString out;
+	out.sprintf("%s.%s", g_cvarSubsystemNames[m_subsystem].cstr(), m_name.cstr());
+	return out;
+}
+
+void CVarSet::registerCVar(CVar* cvar)
+{
+	m_cvars.pushBack(cvar);
+}
+
+Error CVarSet::setFromCommandLineArguments(U32 cmdLineArgsCount, char* cmdLineArgs[])
+{
+	for(U i = 0; i < cmdLineArgsCount; ++i)
+	{
+		ANKI_ASSERT(cmdLineArgs[i]);
+		const CString varName = cmdLineArgs[i];
+
+		// Get the value string
+		++i;
+		if(i >= cmdLineArgsCount)
+		{
+			ANKI_CORE_LOGE("Expecting a command line argument after %s", varName.cstr());
+			return Error::kUserData;
+		}
+		ANKI_ASSERT(cmdLineArgs[i]);
+		const CString value = cmdLineArgs[i];
+
+		// Find the CVar
+		CVar* foundCVar = nullptr;
+		Array<Char, 256> fullnameArr;
+		for(CVar& it : m_cvars)
+		{
+			it.getFullNameInternal(fullnameArr);
+			CString fullname = &fullnameArr[0];
+
+			if(fullname == varName || it.m_name == varName)
+			{
+				if(foundCVar)
+				{
+					ANKI_CORE_LOGW("Command line arg %s has ambiguous name", varName.cstr());
+				}
+				else
+				{
+					foundCVar = &it;
+				}
+			}
+		}
+
+		if(foundCVar)
+		{
+#define ANKI_CVAR_NUMERIC_SET(type) \
+	case CVar::Type::kNumeric##type: \
+	{ \
+		type v; \
+		err = value.toNumber(v); \
+		if(!err) \
+		{ \
+			static_cast<NumericCVar<type>&>(*foundCVar).set(v); \
+		} \
+		break; \
+	}
+
+			Error err = Error::kNone;
+			switch(foundCVar->m_type)
+			{
+			case CVar::Type::kString:
+				static_cast<StringCVar&>(*foundCVar).set(value);
+				break;
+			case CVar::Type::kBool:
+			{
+				U32 v;
+				err = value.toNumber(v);
+				if(!err)
+				{
+					static_cast<BoolCVar&>(*foundCVar).set(v != 0);
+				}
+				break;
+			}
+				ANKI_CVAR_NUMERIC_SET(U8)
+				ANKI_CVAR_NUMERIC_SET(U32)
+				ANKI_CVAR_NUMERIC_SET(PtrSize)
+				ANKI_CVAR_NUMERIC_SET(F32)
+			default:
+				ANKI_ASSERT(0);
+			}
+
+			if(err)
+			{
+				foundCVar->getFullNameInternal(fullnameArr);
+				ANKI_CORE_LOGE("Wrong value for %s. Value will not be set", &fullnameArr[0]);
+			}
+		}
+		else
+		{
+			ANKI_CORE_LOGW("Can't recognize command line argument: %s. Skipping", varName.cstr());
+		}
+	}
+
+	return Error::kNone;
+}
+
+} // end namespace anki

+ 230 - 0
AnKi/Core/CVarSet.h

@@ -0,0 +1,230 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Util/List.h>
+#include <AnKi/Util/String.h>
+#include <AnKi/Util/Singleton.h>
+#include <AnKi/Util/Enum.h>
+#include <AnKi/Math/Functions.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+enum class CVarSubsystem : U32
+{
+	kCore,
+	kRenderer,
+	kGr,
+	kResource,
+	kScene,
+
+	kCount,
+	kFirst = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CVarSubsystem)
+
+/// Config variable base.
+class CVar : public IntrusiveListEnabled<CVar>
+{
+	friend class CVarSet;
+
+public:
+	CVar(const CVar&) = delete;
+
+	CVar& operator=(const CVar&) = delete;
+
+	CoreString getFullName() const;
+
+protected:
+	CString m_name;
+	CString m_descr;
+	CVarSubsystem m_subsystem;
+
+	enum class Type : U32
+	{
+		kString,
+		kBool,
+		kNumericU8,
+		kNumericU32,
+		kNumericPtrSize,
+		kNumericF32
+	};
+
+	Type m_type;
+
+	CVar(Type type, CVarSubsystem subsystem, CString name, CString descr = {})
+		: m_name(name)
+		, m_descr((!descr.isEmpty()) ? descr : "No description")
+		, m_subsystem(subsystem)
+		, m_type(type)
+	{
+		ANKI_ASSERT(subsystem < CVarSubsystem::kCount);
+		registerSelf();
+	}
+
+private:
+	void registerSelf();
+
+	void getFullNameInternal(Array<Char, 256>& arr) const;
+};
+
+/// Numeric config variable.
+template<typename TNumber>
+class NumericCVar : public CVar
+{
+public:
+	NumericCVar(CVarSubsystem subsystem, CString name, TNumber defaultVal, TNumber min = getMinNumericLimit<TNumber>(),
+				TNumber max = getMaxNumericLimit<TNumber>(), CString descr = CString())
+		: CVar(getCVarType(), subsystem, name, descr)
+		, m_value(defaultVal)
+		, m_min(min)
+		, m_max(max)
+	{
+		ANKI_ASSERT(min <= max);
+		ANKI_ASSERT(defaultVal >= min && defaultVal <= max);
+	}
+
+	void set(TNumber val)
+	{
+		const TNumber newVal = clamp(val, m_min, m_max);
+		if(newVal != val)
+		{
+			ANKI_CORE_LOGW("Out of range value set for config var: %s", m_name.cstr());
+		}
+		m_value = newVal;
+	}
+
+	TNumber get() const
+	{
+		return m_value;
+	}
+
+private:
+	TNumber m_value;
+	TNumber m_min;
+	TNumber m_max;
+
+	static Type getCVarType();
+};
+
+#define ANKI_CVAR_NUMERIC_TYPE(type) \
+	template<> \
+	inline CVar::Type NumericCVar<type>::getCVarType() \
+	{ \
+		return Type::kNumeric##type; \
+	}
+
+ANKI_CVAR_NUMERIC_TYPE(U8)
+ANKI_CVAR_NUMERIC_TYPE(U32)
+ANKI_CVAR_NUMERIC_TYPE(PtrSize)
+ANKI_CVAR_NUMERIC_TYPE(F32)
+#undef ANKI_CVAR_NUMERIC_TYPE
+
+/// String config variable.
+class StringCVar : public CVar
+{
+public:
+	StringCVar(CVarSubsystem subsystem, CString name, CString value, CString descr = CString())
+		: CVar(Type::kString, subsystem, name, descr)
+	{
+		set(value);
+	}
+
+	~StringCVar()
+	{
+		if(m_str)
+		{
+			free(m_str);
+		}
+	}
+
+	void set(CString name)
+	{
+		if(m_str)
+		{
+			free(m_str);
+		}
+		const U len = name.getLength();
+		m_str = static_cast<Char*>(malloc(len + 1));
+
+		if(len == 0)
+		{
+			m_str[0] = '\0';
+		}
+		else
+		{
+			memcpy(m_str, name.cstr(), len + 1);
+		}
+	}
+
+	CString get() const
+	{
+		return m_str;
+	}
+
+private:
+	Char* m_str;
+};
+
+/// Boolean config variable.
+class BoolCVar : public CVar
+{
+public:
+	BoolCVar(CVarSubsystem subsystem, CString name, Bool defaultVal, CString descr = CString())
+		: CVar(Type::kBool, subsystem, name, descr)
+		, m_val(defaultVal)
+	{
+	}
+
+	void set(Bool val)
+	{
+		m_val = val;
+	}
+
+	Bool get() const
+	{
+		return m_val;
+	}
+
+private:
+	Bool m_val;
+};
+
+/// Access all configuration variables.
+class CVarSet : public MakeSingletonLazyInit<CVarSet>
+{
+	friend class CVar;
+
+public:
+	CVarSet() = default;
+
+	CVarSet(const CVarSet& b) = delete; // Non-copyable
+
+	CVarSet& operator=(const CVarSet& b) = delete; // Non-copyable
+
+	Error loadFromFile(CString filename);
+
+	Error saveToFile(CString filename) const;
+
+	Error setFromCommandLineArguments(U32 cmdLineArgsCount, char* cmdLineArgs[]);
+
+private:
+	IntrusiveList<CVar> m_cvars;
+
+	void registerCVar(CVar* var);
+};
+
+inline void CVar::registerSelf()
+{
+	CVarSet::getSingleton().registerCVar(this);
+}
+/// @}
+
+} // end namespace anki

+ 4 - 4
AnKi/Core/Common.h

@@ -9,7 +9,7 @@
 #include <AnKi/Util/StdTypes.h>
 #include <AnKi/Util/StdTypes.h>
 #include <AnKi/Util/MemoryPool.h>
 #include <AnKi/Util/MemoryPool.h>
 #include <AnKi/Util/DynamicArray.h>
 #include <AnKi/Util/DynamicArray.h>
-#include <AnKi/Util/ThreadHive.h>
+#include <AnKi/Util/ThreadJobManager.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -32,14 +32,14 @@ private:
 	~CoreMemoryPool() = default;
 	~CoreMemoryPool() = default;
 };
 };
 
 
-class CoreThreadHive : public ThreadHive, public MakeSingleton<CoreThreadHive>
+class CoreThreadJobManager : public ThreadJobManager, public MakeSingleton<CoreThreadJobManager>
 {
 {
 	template<typename>
 	template<typename>
 	friend class MakeSingleton;
 	friend class MakeSingleton;
 
 
 public:
 public:
-	CoreThreadHive(U32 threadCount, Bool pinToCores = false)
-		: ThreadHive(threadCount, pinToCores)
+	CoreThreadJobManager(U32 threadCount, Bool pinToCores = false)
+		: ThreadJobManager(threadCount, pinToCores)
 	{
 	{
 	}
 	}
 };
 };

+ 0 - 260
AnKi/Core/ConfigSet.cpp

@@ -1,260 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Core/ConfigSet.h>
-#include <AnKi/Util/Xml.h>
-#include <AnKi/Util/Logger.h>
-#include <AnKi/Util/File.h>
-
-// Because some cvars set their default values
-#include <AnKi/Util/System.h>
-#include <AnKi/Shaders/Include/ClusteredShadingTypes.h>
-
-namespace anki {
-
-ConfigSet::~ConfigSet()
-{
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	if(m_##name.m_value) \
-	{ \
-		m_pool.free(m_##name.m_value); \
-	}
-#include <AnKi/Core/AllConfigVars.defs.h>
-
-#if ANKI_EXTRA_CHECKS
-	for(const Var& var : m_vars)
-	{
-		if(var.m_timesAccessed.load() == 0)
-		{
-			ANKI_CORE_LOGW("Config var doesn't appear to have been accessed. Maybe unused: %s", var.m_name.cstr());
-		}
-	}
-#endif
-}
-
-void ConfigSet::init(AllocAlignedCallback allocCb, void* allocCbUserData)
-{
-	ANKI_ASSERT(!isInitialized());
-	m_pool.init(allocCb, allocCbUserData);
-
-#define ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description) \
-	ANKI_ASSERT((minValue) <= (maxValue) && (defaultValue) >= (minValue) && (defaultValue) <= (maxValue)); \
-	m_##name.m_name = #name; \
-	m_##name.m_description = description; \
-	m_##name.m_value = defaultValue; \
-	m_##name.m_min = minValue; \
-	m_##name.m_max = maxValue; \
-	m_vars.pushBack(&m_##name);
-
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
-
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
-
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
-
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_NUMERIC(name, defaultValue, minValue, maxValue, description)
-
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
-	m_##name.m_name = #name; \
-	m_##name.m_description = description; \
-	m_##name.m_value = defaultValue; \
-	m_vars.pushBack(&m_##name);
-
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	m_##name.m_name = #name; \
-	m_##name.m_description = description; \
-	setStringVar(defaultValue, m_##name); \
-	m_vars.pushBack(&m_##name);
-
-#include <AnKi/Core/AllConfigVars.defs.h>
-}
-
-ConfigSet::Var* ConfigSet::tryFind(CString optionName)
-{
-	for(auto it = m_vars.getBegin(); it != m_vars.getEnd(); ++it)
-	{
-		if((*it).m_name == optionName)
-		{
-			return &(*it);
-		}
-	}
-
-	return nullptr;
-}
-
-const ConfigSet::Var* ConfigSet::tryFind(CString optionName) const
-{
-	for(auto it = m_vars.getBegin(); it != m_vars.getEnd(); ++it)
-	{
-		if((*it).m_name == optionName)
-		{
-			return &(*it);
-		}
-	}
-
-	return nullptr;
-}
-
-Error ConfigSet::loadFromFile(CString filename)
-{
-	ANKI_ASSERT(isInitialized());
-
-	ANKI_CORE_LOGI("Loading config file %s", filename.cstr());
-	CoreXmlDocument xml;
-	ANKI_CHECK(xml.loadFile(filename));
-
-	XmlElement rootel;
-	ANKI_CHECK(xml.getChildElement("config", rootel));
-
-	XmlElement el;
-
-#define ANKI_NUMERIC(name) \
-	ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
-	if(el) \
-	{ \
-		ANKI_CHECK(el.getNumber(m_##name.m_value)); \
-	}
-
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(name)
-
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
-	ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
-	if(el) \
-	{ \
-		CString txt; \
-		ANKI_CHECK(el.getText(txt)); \
-		if(txt == "true") \
-		{ \
-			m_##name.m_value = true; \
-		} \
-		else if(txt == "false") \
-		{ \
-			m_##name.m_value = false; \
-		} \
-		else \
-		{ \
-			ANKI_CORE_LOGE("Wrong value for %s", m_##name.m_name.cstr()); \
-			return Error::kUserData; \
-		} \
-	}
-
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	ANKI_CHECK(rootel.getChildElementOptional(m_##name.m_name, el)); \
-	if(el) \
-	{ \
-		CString txt; \
-		ANKI_CHECK(el.getText(txt)); \
-		setStringVar(txt, m_##name); \
-	}
-
-#include <AnKi/Core/AllConfigVars.defs.h>
-#undef ANKI_NUMERIC
-
-	return Error::kNone;
-}
-
-Error ConfigSet::saveToFile(CString filename) const
-{
-	ANKI_ASSERT(isInitialized());
-	ANKI_CORE_LOGI("Saving config file %s", &filename[0]);
-
-	File file;
-	ANKI_CHECK(file.open(filename, FileOpenFlag::kWrite));
-
-	ANKI_CHECK(file.writeTextf("%s\n<config>\n", CoreXmlDocument::kXmlHeader.cstr()));
-
-#define ANKI_NUMERIC_UINT(name) \
-	ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
-	ANKI_CHECK(file.writeTextf("\t<%s>%" PRIu64 "</%s>\n", m_##name.m_name.cstr(), U64(m_##name.m_value), \
-							   m_##name.m_name.cstr()));
-
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC_UINT(name)
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
-	ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
-	ANKI_CHECK(file.writeTextf("\t<%s>%s</%s>\n", m_##name.m_name.cstr(), (m_##name.m_value) ? "true" : "false", \
-							   m_##name.m_name.cstr()));
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	ANKI_CHECK(file.writeTextf("\t<!-- %s -->\n", m_##name.m_description.cstr())); \
-	ANKI_CHECK(file.writeTextf("\t<%s>%s</%s>\n", m_##name.m_name.cstr(), m_##name.m_value, m_##name.m_name.cstr()));
-#include <AnKi/Core/AllConfigVars.defs.h>
-#undef ANKI_NUMERIC_UINT
-
-	ANKI_CHECK(file.writeText("</config>\n"));
-	return Error::kNone;
-}
-
-Error ConfigSet::setFromCommandLineArguments(U32 cmdLineArgsCount, char* cmdLineArgs[])
-{
-	ANKI_ASSERT(isInitialized());
-
-	for(U i = 0; i < cmdLineArgsCount; ++i)
-	{
-		ANKI_ASSERT(cmdLineArgs[i]);
-		const CString varName = cmdLineArgs[i];
-
-		// Set the value
-		++i;
-		if(i >= cmdLineArgsCount)
-		{
-			ANKI_CORE_LOGE("Expecting a command line argument after %s", varName.cstr());
-			return Error::kUserData;
-		}
-
-		ANKI_ASSERT(cmdLineArgs[i]);
-		const CString value = cmdLineArgs[i];
-
-		if(false)
-		{
-		}
-
-#define ANKI_NUMERIC(type, name) \
-	else if(varName == m_##name.m_name) \
-	{ \
-		type v; \
-		ANKI_CHECK(value.toNumber(v)); \
-		set##name(v); \
-	}
-
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(U8, name)
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(U32, name)
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(PtrSize, name)
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) ANKI_NUMERIC(F32, name)
-
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
-	else if(varName == m_##name.m_name) \
-	{ \
-		U32 v; \
-		ANKI_CHECK(value.toNumber(v)); \
-		m_##name.m_value = v != 0; \
-	}
-
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	else if(varName == m_##name.m_name) \
-	{ \
-		setStringVar(value, m_##name); \
-	}
-
-#include <AnKi/Core/AllConfigVars.defs.h>
-#undef ANKI_NUMERIC
-		else
-		{
-			ANKI_CORE_LOGW("Can't recognize command line argument: %s. Skipping", varName.cstr());
-		}
-	}
-
-	return Error::kNone;
-}
-
-} // end namespace anki

+ 0 - 178
AnKi/Core/ConfigSet.h

@@ -1,178 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Core/Common.h>
-#include <AnKi/Util/List.h>
-#include <AnKi/Util/String.h>
-#include <AnKi/Util/Singleton.h>
-#include <AnKi/Math/Functions.h>
-
-namespace anki {
-
-/// @addtogroup core
-/// @{
-
-/// A storage of configuration variables.
-class ConfigSet : public MakeSingleton<ConfigSet>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	ConfigSet(const ConfigSet& b) = delete; // Non-copyable
-
-	ConfigSet& operator=(const ConfigSet& b) = delete; // Non-copyable
-
-	Error loadFromFile(CString filename);
-
-	Error saveToFile(CString filename) const;
-
-	Error setFromCommandLineArguments(U32 cmdLineArgsCount, char* cmdLineArgs[]);
-
-	// Define getters and setters
-#if ANKI_EXTRA_CHECKS
-#	define ANKI_CONFIG_VAR_GET(type, name, defaultValue, minValue, maxValue, description) \
-		type get##name() const \
-		{ \
-			ANKI_ASSERT(isInitialized()); \
-			m_##name.m_timesAccessed.fetchAdd(1); \
-			return m_##name.m_value; \
-		}
-#else
-#	define ANKI_CONFIG_VAR_GET(type, name, defaultValue, minValue, maxValue, description) \
-		type get##name() const \
-		{ \
-			ANKI_ASSERT(isInitialized()); \
-			return m_##name.m_value; \
-		}
-#endif
-#define ANKI_CONFIG_VAR_SET(type, name, defaultValue, minValue, maxValue, description) \
-	void set##name(type value) \
-	{ \
-		ANKI_ASSERT(isInitialized()); \
-		const type newValue = clamp(value, m_##name.m_min, m_##name.m_max); \
-		if(newValue != value) \
-		{ \
-			ANKI_CORE_LOGW("Out of range value set for config var: %s", m_##name.m_name.cstr()); \
-		} \
-		m_##name.m_value = newValue; \
-	}
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_GET(U8, name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_SET(U8, name, defaultValue, minValue, maxValue, description)
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_GET(U32, name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_SET(U32, name, defaultValue, minValue, maxValue, description)
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_GET(PtrSize, name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_SET(PtrSize, name, defaultValue, minValue, maxValue, description)
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_GET(F32, name, defaultValue, minValue, maxValue, description) \
-	ANKI_CONFIG_VAR_SET(F32, name, defaultValue, minValue, maxValue, description)
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) \
-	ANKI_CONFIG_VAR_GET(Bool, name, defaultValue, minValue, maxValue, description) \
-	void set##name(Bool value) \
-	{ \
-		ANKI_ASSERT(isInitialized()); \
-		m_##name.m_value = value; \
-	}
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) \
-	ANKI_CONFIG_VAR_GET(CString, name, defaultValue, minValue, maxValue, description) \
-	void set##name(CString value) \
-	{ \
-		ANKI_ASSERT(isInitialized()); \
-		setStringVar(value, m_##name); \
-	}
-#include <AnKi/Core/AllConfigVars.defs.h>
-#undef ANKI_CONFIG_VAR_GET
-#undef ANKI_CONFIG_VAR_SET
-
-private:
-	class Var : public IntrusiveListEnabled<Var>
-	{
-	public:
-		CString m_name;
-		CString m_description;
-#if ANKI_EXTRA_CHECKS
-		mutable Atomic<U32> m_timesAccessed = {0};
-#endif
-	};
-
-	template<typename T>
-	class NumberVar : public Var
-	{
-	public:
-		T m_value;
-		T m_min;
-		T m_max;
-	};
-
-	class StringVar : public Var
-	{
-	public:
-		Char* m_value = nullptr;
-	};
-
-	class BoolVar : public Var
-	{
-	public:
-		Bool m_value;
-	};
-
-	HeapMemoryPool m_pool;
-	IntrusiveList<Var> m_vars;
-
-#define ANKI_CONFIG_VAR_U8(name, defaultValue, minValue, maxValue, description) NumberVar<U8> m_##name;
-#define ANKI_CONFIG_VAR_U32(name, defaultValue, minValue, maxValue, description) NumberVar<U32> m_##name;
-#define ANKI_CONFIG_VAR_PTR_SIZE(name, defaultValue, minValue, maxValue, description) NumberVar<PtrSize> m_##name;
-#define ANKI_CONFIG_VAR_F32(name, defaultValue, minValue, maxValue, description) NumberVar<F32> m_##name;
-#define ANKI_CONFIG_VAR_BOOL(name, defaultValue, description) BoolVar m_##name;
-#define ANKI_CONFIG_VAR_STRING(name, defaultValue, description) StringVar m_##name;
-#include <AnKi/Core/AllConfigVars.defs.h>
-
-	ConfigSet(AllocAlignedCallback allocCb, void* allocCbUserData)
-	{
-		init(allocCb, allocCbUserData);
-	}
-
-	~ConfigSet();
-
-	void init(AllocAlignedCallback allocCb, void* allocCbUserData);
-
-	Bool isInitialized() const
-	{
-		return !m_vars.isEmpty();
-	}
-
-	Var* tryFind(CString name);
-	const Var* tryFind(CString name) const;
-
-	Var& find(CString name)
-	{
-		Var* o = tryFind(name);
-		ANKI_ASSERT(o && "Couldn't find config option");
-		return *o;
-	}
-
-	const Var& find(CString name) const
-	{
-		const Var* o = tryFind(name);
-		ANKI_ASSERT(o && "Couldn't find config option");
-		return *o;
-	}
-
-	void setStringVar(CString val, StringVar& var)
-	{
-		m_pool.free(var.m_value);
-		const U32 len = val.getLength();
-		var.m_value = static_cast<Char*>(m_pool.allocate(len + 1, alignof(Char)));
-		memcpy(var.m_value, val.getBegin(), len + 1);
-	}
-};
-/// @}
-
-} // end namespace anki

+ 0 - 25
AnKi/Core/ConfigVars.defs.h

@@ -1,25 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-ANKI_CONFIG_VAR_GROUP(CORE)
-
-ANKI_CONFIG_VAR_PTR_SIZE(CoreRebarGpuMemorySize, 24_MB, 1_MB, 1_GB, "ReBAR: always mapped GPU memory")
-ANKI_CONFIG_VAR_PTR_SIZE(CoreGlobalVertexMemorySize, 128_MB, 16_MB, 2_GB, "Global index and vertex buffer size")
-ANKI_CONFIG_VAR_PTR_SIZE(CoreGpuSceneInitialSize, 64_MB, 16_MB, 2_GB, "Global memory for the GPU scene")
-
-ANKI_CONFIG_VAR_BOOL(CoreMaliHwCounters, false, "Enable Mali counters")
-
-ANKI_CONFIG_VAR_U32(Width, 1920, 16, 16 * 1024, "Width")
-ANKI_CONFIG_VAR_U32(Height, 1080, 16, 16 * 1024, "Height")
-ANKI_CONFIG_VAR_U32(WindowFullscreen, 1, 0, 2, "0: windowed, 1: borderless fullscreen, 2: exclusive fullscreen")
-
-ANKI_CONFIG_VAR_U32(CoreTargetFps, 60u, 1u, kMaxU32, "Target FPS")
-ANKI_CONFIG_VAR_U32(CoreJobThreadCount, max(2u, getCpuCoresCount() / 2u), 2u, 1024u, "Number of job thread")
-ANKI_CONFIG_VAR_U32(CoreDisplayStats, 0, 0, 2, "Display stats, 0: None, 1: Simple, 2: Detailed")
-ANKI_CONFIG_VAR_BOOL(CoreClearCaches, false, "Clear all caches")
-ANKI_CONFIG_VAR_BOOL(CoreVerboseLog, false, "Verbose logging")
-ANKI_CONFIG_VAR_BOOL(CoreBenchmarkMode, false, "Run in a benchmark mode. Fixed timestep, unlimited target FPS")
-ANKI_CONFIG_VAR_U32(CoreBenchmarkModeFrameCount, 60 * 60 * 2, 1, kMaxU32,
-					"How many frames the benchmark will run before it quits")

+ 46 - 23
AnKi/Core/CoreTracer.cpp

@@ -11,6 +11,10 @@
 
 
 namespace anki {
 namespace anki {
 
 
+BoolCVar g_tracingEnabledCVar(CVarSubsystem::kCore, "Tracing", false, "Enable or disable tracing");
+
+#if ANKI_TRACING_ENABLED
+
 static void getSpreadsheetColumnName(U32 column, Array<char, 3>& arr)
 static void getSpreadsheetColumnName(U32 column, Array<char, 3>& arr)
 {
 {
 	U32 major = column / 26;
 	U32 major = column / 26;
@@ -68,7 +72,7 @@ CoreTracer::~CoreTracer()
 	}
 	}
 
 
 	// Write counter file
 	// Write counter file
-	err = writeCountersForReal();
+	err = writeCountersOnShutdown();
 
 
 	// Cleanup
 	// Cleanup
 	while(!m_frameCounters.isEmpty())
 	while(!m_frameCounters.isEmpty())
@@ -90,7 +94,7 @@ CoreTracer::~CoreTracer()
 Error CoreTracer::init(CString directory)
 Error CoreTracer::init(CString directory)
 {
 {
 	Tracer::allocateSingleton();
 	Tracer::allocateSingleton();
-	const Bool enableTracer = getenv("ANKI_CORE_TRACER_ENABLED") && getenv("ANKI_CORE_TRACER_ENABLED")[0] == '1';
+	const Bool enableTracer = g_tracingEnabledCVar.get();
 	Tracer::getSingleton().setEnabled(enableTracer);
 	Tracer::getSingleton().setEnabled(enableTracer);
 	ANKI_CORE_LOGI("Tracing is %s from the beginning", (enableTracer) ? "enabled" : "disabled");
 	ANKI_CORE_LOGI("Tracing is %s from the beginning", (enableTracer) ? "enabled" : "disabled");
 
 
@@ -100,13 +104,10 @@ Error CoreTracer::init(CString directory)
 
 
 	std::tm tm = getLocalTime();
 	std::tm tm = getLocalTime();
 	CoreString fname;
 	CoreString fname;
-	fname.sprintf("%s/%d%02d%02d-%02d%02d_", directory.cstr(), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
-				  tm.tm_min);
+	fname.sprintf("%s/%d%02d%02d-%02d%02d_", directory.cstr(), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
 
 
-	ANKI_CHECK(m_traceJsonFile.open(CoreString().sprintf("%strace.json", fname.cstr()), FileOpenFlag::kWrite));
-	ANKI_CHECK(m_traceJsonFile.writeText("[\n"));
-
-	ANKI_CHECK(m_countersCsvFile.open(CoreString().sprintf("%scounters.csv", fname.cstr()), FileOpenFlag::kWrite));
+	m_traceJsonFilename.sprintf("%strace.json", fname.cstr());
+	m_countersCsvFilename.sprintf("%scounters.csv", fname.cstr());
 
 
 	return Error::kNone;
 	return Error::kNone;
 }
 }
@@ -159,6 +160,18 @@ Error CoreTracer::threadWorker()
 
 
 Error CoreTracer::writeEvents(ThreadWorkItem& item)
 Error CoreTracer::writeEvents(ThreadWorkItem& item)
 {
 {
+	if(item.m_events.getSize() == 0)
+	{
+		return Error::kNone;
+	}
+
+	if(!m_traceJsonFile.isOpen())
+	{
+		ANKI_CHECK(m_traceJsonFile.open(m_traceJsonFilename, FileOpenFlag::kWrite));
+		ANKI_CHECK(m_traceJsonFile.writeText("[\n"));
+		ANKI_CORE_LOGI("Trace file created: %s", m_traceJsonFilename.cstr());
+	}
+
 	// First sort them to fix overlaping in chrome
 	// First sort them to fix overlaping in chrome
 	std::sort(item.m_events.getBegin(), item.m_events.getEnd(), [](const TracerEvent& a, TracerEvent& b) {
 	std::sort(item.m_events.getBegin(), item.m_events.getEnd(), [](const TracerEvent& a, TracerEvent& b) {
 		return (a.m_start != b.m_start) ? a.m_start < b.m_start : a.m_duration > b.m_duration;
 		return (a.m_start != b.m_start) ? a.m_start < b.m_start : a.m_duration > b.m_duration;
@@ -171,11 +184,10 @@ Error CoreTracer::writeEvents(ThreadWorkItem& item)
 		const I64 durMicroSec = I64(event.m_duration * 1000000.0);
 		const I64 durMicroSec = I64(event.m_duration * 1000000.0);
 
 
 		// Do a hack
 		// Do a hack
-		const ThreadId tid = (event.m_name == "GPU_TIME") ? 1 : item.m_tid;
+		const ThreadId tid = (event.m_name == "tGpuFrameTime") ? 1 : item.m_tid;
 
 
 		ANKI_CHECK(m_traceJsonFile.writeTextf("{\"name\": \"%s\", \"cat\": \"PERF\", \"ph\": \"X\", "
 		ANKI_CHECK(m_traceJsonFile.writeTextf("{\"name\": \"%s\", \"cat\": \"PERF\", \"ph\": \"X\", "
-											  "\"pid\": 1, \"tid\": %" PRIu64 ", \"ts\": %" PRIi64 ", \"dur\": %" PRIi64
-											  "},\n",
+											  "\"pid\": 1, \"tid\": %" PRIu64 ", \"ts\": %" PRIi64 ", \"dur\": %" PRIi64 "},\n",
 											  event.m_name.cstr(), tid, startMicroSec, durMicroSec));
 											  event.m_name.cstr(), tid, startMicroSec, durMicroSec));
 	}
 	}
 
 
@@ -310,27 +322,37 @@ void CoreTracer::flushFrame(U64 frame)
 			self.m_cvar.notifyOne();
 			self.m_cvar.notifyOne();
 		},
 		},
 		&ctx);
 		&ctx);
+
+	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar.get())
+	{
+		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar.get());
+		ANKI_CORE_LOGI("%s tracing", (g_tracingEnabledCVar.get()) ? "Enabling" : "Disabling");
+	}
 }
 }
 
 
-Error CoreTracer::writeCountersForReal()
+Error CoreTracer::writeCountersOnShutdown()
 {
 {
-	if(!m_countersCsvFile.isOpen() || m_frameCounters.getSize() == 0)
+	if(m_frameCounters.getSize() == 0)
 	{
 	{
 		return Error::kNone;
 		return Error::kNone;
 	}
 	}
 
 
+	File countersCsvFile;
+	ANKI_CHECK(countersCsvFile.open(m_countersCsvFilename, FileOpenFlag::kWrite));
+	ANKI_CORE_LOGI("Counter file created: %s", m_countersCsvFilename.cstr());
+
 	// Write the header
 	// Write the header
-	ANKI_CHECK(m_countersCsvFile.writeText("Frame"));
+	ANKI_CHECK(countersCsvFile.writeText("Frame"));
 	for(U32 i = 0; i < m_counterNames.getSize(); ++i)
 	for(U32 i = 0; i < m_counterNames.getSize(); ++i)
 	{
 	{
-		ANKI_CHECK(m_countersCsvFile.writeTextf(",%s", m_counterNames[i].cstr()));
+		ANKI_CHECK(countersCsvFile.writeTextf(",%s", m_counterNames[i].cstr()));
 	}
 	}
-	ANKI_CHECK(m_countersCsvFile.writeText("\n"));
+	ANKI_CHECK(countersCsvFile.writeText("\n"));
 
 
 	// Write each frame
 	// Write each frame
 	for(const PerFrameCounters& frame : m_frameCounters)
 	for(const PerFrameCounters& frame : m_frameCounters)
 	{
 	{
-		ANKI_CHECK(m_countersCsvFile.writeTextf("%" PRIu64, frame.m_frame));
+		ANKI_CHECK(countersCsvFile.writeTextf("%" PRIu64, frame.m_frame));
 
 
 		for(U32 j = 0; j < m_counterNames.getSize(); ++j)
 		for(U32 j = 0; j < m_counterNames.getSize(); ++j)
 		{
 		{
@@ -345,29 +367,30 @@ Error CoreTracer::writeCountersForReal()
 				}
 				}
 			}
 			}
 
 
-			ANKI_CHECK(m_countersCsvFile.writeTextf(",%" PRIu64, value));
+			ANKI_CHECK(countersCsvFile.writeTextf(",%" PRIu64, value));
 		}
 		}
 
 
-		ANKI_CHECK(m_countersCsvFile.writeText("\n"));
+		ANKI_CHECK(countersCsvFile.writeText("\n"));
 	}
 	}
 
 
 	// Write some statistics
 	// Write some statistics
 	Array<const char*, 2> funcs = {"SUM", "AVERAGE"};
 	Array<const char*, 2> funcs = {"SUM", "AVERAGE"};
 	for(const char* func : funcs)
 	for(const char* func : funcs)
 	{
 	{
-		ANKI_CHECK(m_countersCsvFile.writeText(func));
+		ANKI_CHECK(countersCsvFile.writeText(func));
 		for(U32 i = 0; i < m_frameCounters.getSize(); ++i)
 		for(U32 i = 0; i < m_frameCounters.getSize(); ++i)
 		{
 		{
 			Array<char, 3> columnName;
 			Array<char, 3> columnName;
 			getSpreadsheetColumnName(i + 1, columnName);
 			getSpreadsheetColumnName(i + 1, columnName);
-			ANKI_CHECK(m_countersCsvFile.writeTextf(",=%s(%s2:%s%zu)", func, &columnName[0], &columnName[0],
-													m_frameCounters.getSize() + 1));
+			ANKI_CHECK(countersCsvFile.writeTextf(",=%s(%s2:%s%zu)", func, &columnName[0], &columnName[0], m_frameCounters.getSize() + 1));
 		}
 		}
 
 
-		ANKI_CHECK(m_countersCsvFile.writeText("\n"));
+		ANKI_CHECK(countersCsvFile.writeText("\n"));
 	}
 	}
 
 
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
+#endif
+
 } // end namespace anki
 } // end namespace anki

+ 10 - 2
AnKi/Core/CoreTracer.h

@@ -9,12 +9,17 @@
 #include <AnKi/Util/Thread.h>
 #include <AnKi/Util/Thread.h>
 #include <AnKi/Util/List.h>
 #include <AnKi/Util/List.h>
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/File.h>
+#include <AnKi/Core/CVarSet.h>
 
 
 namespace anki {
 namespace anki {
 
 
 /// @addtogroup core
 /// @addtogroup core
 /// @{
 /// @{
 
 
+extern BoolCVar g_tracingEnabledCVar;
+
+#if ANKI_TRACING_ENABLED
+
 /// A system that sits on top of the tracer and processes the counters and events.
 /// A system that sits on top of the tracer and processes the counters and events.
 class CoreTracer : public MakeSingleton<CoreTracer>
 class CoreTracer : public MakeSingleton<CoreTracer>
 {
 {
@@ -40,8 +45,9 @@ private:
 	IntrusiveList<PerFrameCounters> m_frameCounters;
 	IntrusiveList<PerFrameCounters> m_frameCounters;
 
 
 	IntrusiveList<ThreadWorkItem> m_workItems; ///< Items for the thread to process.
 	IntrusiveList<ThreadWorkItem> m_workItems; ///< Items for the thread to process.
+	CoreString m_traceJsonFilename;
+	CoreString m_countersCsvFilename;
 	File m_traceJsonFile;
 	File m_traceJsonFile;
-	File m_countersCsvFile;
 	Bool m_quit = false;
 	Bool m_quit = false;
 
 
 	CoreTracer();
 	CoreTracer();
@@ -52,8 +58,10 @@ private:
 
 
 	Error writeEvents(ThreadWorkItem& item);
 	Error writeEvents(ThreadWorkItem& item);
 	void gatherCounters(ThreadWorkItem& item);
 	void gatherCounters(ThreadWorkItem& item);
-	Error writeCountersForReal();
+	Error writeCountersOnShutdown();
 };
 };
+
+#endif
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 47 - 0
AnKi/Core/GpuMemory/GpuReadbackMemoryPool.cpp

@@ -0,0 +1,47 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h>
+#include <AnKi/Gr/GrManager.h>
+
+namespace anki {
+
+GpuReadbackMemoryPool::GpuReadbackMemoryPool()
+{
+	const Array classes = {64_B, 256_B, 1_MB, 5_MB};
+
+	const BufferUsageBit buffUsage = BufferUsageBit::kAllStorage;
+	const BufferMapAccessBit mapAccess = BufferMapAccessBit::kRead;
+
+	m_pool.init(buffUsage, classes, classes.getBack(), "GpuReadback", false, mapAccess);
+
+	m_alignment = GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment;
+}
+
+GpuReadbackMemoryPool ::~GpuReadbackMemoryPool()
+{
+}
+
+GpuReadbackMemoryAllocation GpuReadbackMemoryPool::allocate(PtrSize size)
+{
+	GpuReadbackMemoryAllocation out;
+	m_pool.allocate(size, m_alignment, out.m_token);
+	out.m_buffer = &m_pool.getGpuBuffer();
+	out.m_mappedMemory = static_cast<U8*>(m_pool.getGpuBufferMappedMemory()) + out.m_token.m_offset;
+	return out;
+}
+
+void GpuReadbackMemoryPool::deferredFree(GpuReadbackMemoryAllocation& allocation)
+{
+	m_pool.deferredFree(allocation.m_token);
+	::new(&allocation) GpuReadbackMemoryAllocation();
+}
+
+void GpuReadbackMemoryPool::endFrame()
+{
+	m_pool.endFrame();
+}
+
+} // end namespace anki

+ 108 - 0
AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h

@@ -0,0 +1,108 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+/// @memberof GpuReadbackMemoryPool
+class GpuReadbackMemoryAllocation
+{
+	friend class GpuReadbackMemoryPool;
+
+public:
+	GpuReadbackMemoryAllocation() = default;
+
+	GpuReadbackMemoryAllocation(const GpuReadbackMemoryAllocation&) = delete;
+
+	GpuReadbackMemoryAllocation(GpuReadbackMemoryAllocation&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GpuReadbackMemoryAllocation();
+
+	GpuReadbackMemoryAllocation& operator=(const GpuReadbackMemoryAllocation&) = delete;
+
+	GpuReadbackMemoryAllocation& operator=(GpuReadbackMemoryAllocation&& b)
+	{
+		ANKI_ASSERT(!isValid() && "Forgot to delete");
+		m_token = b.m_token;
+		b.m_token = {};
+		m_buffer = b.m_buffer;
+		m_mappedMemory = b.m_mappedMemory;
+		return *this;
+	}
+
+	Bool isValid() const
+	{
+		return m_token.m_offset != kMaxPtrSize;
+	}
+
+	/// Get offset in the Unified Geometry Buffer buffer.
+	U32 getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return U32(m_token.m_offset);
+	}
+
+	U32 getAllocatedSize() const
+	{
+		ANKI_ASSERT(isValid());
+		return U32(m_token.m_size);
+	}
+
+	Buffer& getBuffer() const
+	{
+		ANKI_ASSERT(isValid());
+		return *m_buffer;
+	}
+
+	const void* getMappedMemory() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_mappedMemory;
+	}
+
+private:
+	SegregatedListsGpuMemoryPoolToken m_token;
+	Buffer* m_buffer = nullptr;
+	void* m_mappedMemory = nullptr;
+};
+
+class GpuReadbackMemoryPool : public MakeSingleton<GpuReadbackMemoryPool>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	GpuReadbackMemoryAllocation allocate(PtrSize size);
+
+	void deferredFree(GpuReadbackMemoryAllocation& allocation);
+
+	void endFrame();
+
+private:
+	SegregatedListsGpuMemoryPool m_pool;
+	U32 m_alignment = 0;
+
+	GpuReadbackMemoryPool();
+
+	~GpuReadbackMemoryPool();
+};
+
+inline GpuReadbackMemoryAllocation::~GpuReadbackMemoryAllocation()
+{
+	GpuReadbackMemoryPool::getSingleton().deferredFree(*this);
+}
+/// @}
+
+} // end namespace anki

+ 156 - 0
AnKi/Core/GpuMemory/GpuSceneBuffer.cpp

@@ -0,0 +1,156 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
+#include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
+#include <AnKi/Core/CVarSet.h>
+#include <AnKi/Core/StatsSet.h>
+#include <AnKi/Util/Tracer.h>
+#include <AnKi/Resource/ResourceManager.h>
+#include <AnKi/Gr/CommandBuffer.h>
+
+namespace anki {
+
+static StatCounter g_gpuSceneBufferAllocatedSizeStatVar(StatCategory::kGpuMem, "GPU scene allocated",
+														StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+static StatCounter g_gpuSceneBufferTotalStatVar(StatCategory::kGpuMem, "GPU scene total", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+static StatCounter g_gpuSceneBufferFragmentationStatVar(StatCategory::kGpuMem, "GPU scene fragmentation",
+														StatFlag::kFloat | StatFlag::kMainThreadUpdates);
+
+static NumericCVar<PtrSize> g_gpuSceneInitialSizeCVar(CVarSubsystem::kCore, "GpuSceneInitialSize", 64_MB, 16_MB, 2_GB,
+													  "Global memory for the GPU scene");
+
+void GpuSceneBuffer::init()
+{
+	const PtrSize poolSize = g_gpuSceneInitialSizeCVar.get();
+
+	const Array classes = {32_B, 64_B, 128_B, 256_B, poolSize};
+
+	BufferUsageBit buffUsage = BufferUsageBit::kAllStorage | BufferUsageBit::kTransferDestination;
+
+	m_pool.init(buffUsage, classes, poolSize, "GpuScene", true);
+
+	// Allocate something dummy to force creating the GPU buffer
+	GpuSceneBufferAllocation alloc = allocate(16, 4);
+	deferredFree(alloc);
+}
+
+void GpuSceneBuffer::updateStats() const
+{
+	F32 externalFragmentation;
+	PtrSize userAllocatedSize, totalSize;
+	m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
+
+	g_gpuSceneBufferAllocatedSizeStatVar.set(userAllocatedSize);
+	g_gpuSceneBufferTotalStatVar.set(totalSize);
+	g_gpuSceneBufferFragmentationStatVar.set(externalFragmentation);
+}
+
+/// It packs the source and destination offsets as well as the size of the patch itself.
+class GpuSceneMicroPatcher::PatchHeader
+{
+public:
+	U32 m_dwordCountAndSrcDwordOffsetPack;
+	U32 m_dstDwordOffset;
+};
+
+GpuSceneMicroPatcher::GpuSceneMicroPatcher()
+{
+}
+
+GpuSceneMicroPatcher::~GpuSceneMicroPatcher()
+{
+	static_assert(sizeof(PatchHeader) == 8);
+}
+
+Error GpuSceneMicroPatcher::init()
+{
+	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuSceneMicroPatching.ankiprogbin", m_copyProgram));
+	const ShaderProgramResourceVariant* variant;
+	m_copyProgram->getOrCreateVariant(variant);
+	m_grProgram.reset(&variant->getProgram());
+
+	return Error::kNone;
+}
+
+void GpuSceneMicroPatcher::newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, PtrSize dataSize, const void* data)
+{
+	ANKI_ASSERT(dataSize > 0 && (dataSize % 4) == 0);
+	ANKI_ASSERT((ptrToNumber(data) % 4) == 0);
+	ANKI_ASSERT((gpuSceneDestOffset % 4) == 0 && gpuSceneDestOffset / 4 < kMaxU32);
+
+	const U32 dataDwords = U32(dataSize / 4);
+	U32 gpuSceneDestDwordOffset = U32(gpuSceneDestOffset / 4);
+
+	const U32* patchIt = static_cast<const U32*>(data);
+	const U32* const patchEnd = patchIt + dataDwords;
+
+	// Break the data into multiple copies
+	LockGuard lock(m_mtx);
+
+	if(m_crntFramePatchHeaders.getSize() == 0)
+	{
+		m_crntFramePatchHeaders = DynamicArray<PatchHeader, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
+		m_crntFramePatchData = DynamicArray<U32, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
+	}
+
+	while(patchIt < patchEnd)
+	{
+		const U32 patchDwords = min(kDwordsPerPatch, U32(patchEnd - patchIt));
+
+		PatchHeader& header = *m_crntFramePatchHeaders.emplaceBack();
+		ANKI_ASSERT(((patchDwords - 1) & 0b111111) == (patchDwords - 1));
+		header.m_dwordCountAndSrcDwordOffsetPack = patchDwords - 1;
+		header.m_dwordCountAndSrcDwordOffsetPack <<= 26;
+		ANKI_ASSERT((m_crntFramePatchData.getSize() & 0x3FFFFFF) == m_crntFramePatchData.getSize());
+		header.m_dwordCountAndSrcDwordOffsetPack |= m_crntFramePatchData.getSize();
+		header.m_dstDwordOffset = gpuSceneDestDwordOffset;
+
+		const U32 srcOffset = m_crntFramePatchData.getSize();
+		m_crntFramePatchData.resize(srcOffset + patchDwords);
+		memcpy(&m_crntFramePatchData[srcOffset], patchIt, patchDwords * 4);
+
+		patchIt += patchDwords;
+		gpuSceneDestDwordOffset += patchDwords;
+	}
+}
+
+void GpuSceneMicroPatcher::patchGpuScene(CommandBuffer& cmdb)
+{
+	if(m_crntFramePatchHeaders.getSize() == 0)
+	{
+		return;
+	}
+
+	ANKI_ASSERT(m_crntFramePatchData.getSize() > 0);
+
+	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatches, m_crntFramePatchHeaders.getSize());
+	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatchUploadData, m_crntFramePatchData.getSizeInBytes());
+
+	void* mapped;
+	const RebarAllocation headersToken = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchHeaders.getSizeInBytes(), mapped);
+	memcpy(mapped, &m_crntFramePatchHeaders[0], m_crntFramePatchHeaders.getSizeInBytes());
+
+	const RebarAllocation dataToken = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchData.getSizeInBytes(), mapped);
+	memcpy(mapped, &m_crntFramePatchData[0], m_crntFramePatchData.getSizeInBytes());
+
+	cmdb.bindStorageBuffer(0, 0, headersToken);
+	cmdb.bindStorageBuffer(0, 1, dataToken);
+	cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize);
+
+	cmdb.bindShaderProgram(m_grProgram.get());
+
+	const U32 workgroupCountX = m_crntFramePatchHeaders.getSize();
+	cmdb.dispatchCompute(workgroupCountX, 1, 1);
+
+	// Cleanup to prepare for the new frame
+	U32* data;
+	U32 size, storage;
+	m_crntFramePatchData.moveAndReset(data, size, storage);
+	PatchHeader* datah;
+	m_crntFramePatchHeaders.moveAndReset(datah, size, storage);
+}
+
+} // end namespace anki

+ 191 - 0
AnKi/Core/GpuMemory/GpuSceneBuffer.h

@@ -0,0 +1,191 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
+#include <AnKi/Resource/ShaderProgramResource.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+/// @memberof GpuSceneBuffer
+class GpuSceneBufferAllocation
+{
+	friend class GpuSceneBuffer;
+
+public:
+	GpuSceneBufferAllocation() = default;
+
+	GpuSceneBufferAllocation(const GpuSceneBufferAllocation&) = delete;
+
+	GpuSceneBufferAllocation(GpuSceneBufferAllocation&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~GpuSceneBufferAllocation();
+
+	GpuSceneBufferAllocation& operator=(const GpuSceneBufferAllocation&) = delete;
+
+	GpuSceneBufferAllocation& operator=(GpuSceneBufferAllocation&& b)
+	{
+		ANKI_ASSERT(!isValid() && "Forgot to delete");
+		m_token = b.m_token;
+		b.m_token = {};
+		return *this;
+	}
+
+	Bool isValid() const
+	{
+		return m_token.m_offset != kMaxPtrSize;
+	}
+
+	/// Get offset in the Unified Geometry Buffer buffer.
+	U32 getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return U32(m_token.m_offset);
+	}
+
+	U32 getAllocatedSize() const
+	{
+		ANKI_ASSERT(isValid());
+		return U32(m_token.m_size);
+	}
+
+private:
+	SegregatedListsGpuMemoryPoolToken m_token;
+};
+
+/// Memory pool for the GPU scene.
+class GpuSceneBuffer : public MakeSingleton<GpuSceneBuffer>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	GpuSceneBuffer(const GpuSceneBuffer&) = delete; // Non-copyable
+
+	GpuSceneBuffer& operator=(const GpuSceneBuffer&) = delete; // Non-copyable
+
+	void init();
+
+	GpuSceneBufferAllocation allocate(PtrSize size, U32 alignment)
+	{
+		GpuSceneBufferAllocation alloc;
+		m_pool.allocate(size, alignment, alloc.m_token);
+		return alloc;
+	}
+
+	void deferredFree(GpuSceneBufferAllocation& alloc)
+	{
+		m_pool.deferredFree(alloc.m_token);
+	}
+
+	void endFrame()
+	{
+		m_pool.endFrame();
+#if ANKI_STATS_ENABLED
+		updateStats();
+#endif
+	}
+
+	Buffer& getBuffer() const
+	{
+		return m_pool.getGpuBuffer();
+	}
+
+	BufferOffsetRange getBufferOffsetRange() const
+	{
+		return {&m_pool.getGpuBuffer(), 0, kMaxPtrSize};
+	}
+
+private:
+	SegregatedListsGpuMemoryPool m_pool;
+
+	GpuSceneBuffer() = default;
+
+	~GpuSceneBuffer() = default;
+
+	void updateStats() const;
+};
+
+inline GpuSceneBufferAllocation::~GpuSceneBufferAllocation()
+{
+	GpuSceneBuffer::getSingleton().deferredFree(*this);
+}
+
+/// Creates the copy jobs that will patch the GPU Scene.
+class GpuSceneMicroPatcher : public MakeSingleton<GpuSceneMicroPatcher>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	GpuSceneMicroPatcher(const GpuSceneMicroPatcher&) = delete;
+
+	GpuSceneMicroPatcher& operator=(const GpuSceneMicroPatcher&) = delete;
+
+	Error init();
+
+	/// Copy data for the GPU scene to a staging buffer.
+	/// @note It's thread-safe.
+	void newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, PtrSize dataSize, const void* data);
+
+	template<typename T>
+	void newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, const T& value)
+	{
+		newCopy(frameCpuPool, gpuSceneDestOffset, sizeof(value), &value);
+	}
+
+	/// @see newCopy
+	void newCopy(StackMemoryPool& frameCpuPool, const GpuSceneBufferAllocation& dest, PtrSize dataSize, const void* data)
+	{
+		ANKI_ASSERT(dataSize <= dest.getAllocatedSize());
+		newCopy(frameCpuPool, dest.getOffset(), dataSize, data);
+	}
+
+	/// @see newCopy
+	template<typename T>
+	void newCopy(StackMemoryPool& frameCpuPool, const GpuSceneBufferAllocation& dest, const T& value)
+	{
+		ANKI_ASSERT(sizeof(value) <= dest.getAllocatedSize());
+		newCopy(frameCpuPool, dest.getOffset(), sizeof(value), &value);
+	}
+
+	/// Check if there is a need to call patchGpuScene or if no copies are needed.
+	/// @note Not thread-safe. Nothing else should be happening before calling it.
+	Bool patchingIsNeeded() const
+	{
+		return m_crntFramePatchHeaders.getSize() > 0;
+	}
+
+	/// Copy the data to the GPU scene buffer.
+	/// @note Not thread-safe. Nothing else should be happening before calling it.
+	void patchGpuScene(CommandBuffer& cmdb);
+
+private:
+	static constexpr U32 kDwordsPerPatch = 64;
+
+	class PatchHeader;
+
+	DynamicArray<PatchHeader, MemoryPoolPtrWrapper<StackMemoryPool>> m_crntFramePatchHeaders;
+	DynamicArray<U32, MemoryPoolPtrWrapper<StackMemoryPool>> m_crntFramePatchData;
+	Mutex m_mtx;
+
+	ShaderProgramResourcePtr m_copyProgram;
+	ShaderProgramPtr m_grProgram;
+
+	GpuSceneMicroPatcher();
+
+	~GpuSceneMicroPatcher();
+};
+/// @}
+
+} // end namespace anki

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

@@ -0,0 +1,109 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Gr/Utils/StackGpuMemoryPool.h>
+#include <AnKi/Gr/GrManager.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+/// @memberof GpuVisibleTransientMemoryPool
+class GpuVisibleTransientMemoryAllocation
+{
+	friend class GpuVisibleTransientMemoryPool;
+
+public:
+	Buffer& getBuffer() const
+	{
+		ANKI_ASSERT(isValid());
+		return *m_buffer;
+	}
+
+	PtrSize getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_offset;
+	}
+
+	PtrSize getRange() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_size;
+	}
+
+	Bool isValid() const
+	{
+		return m_buffer != nullptr;
+	}
+
+	operator BufferOffsetRange() const;
+
+private:
+	Buffer* m_buffer = nullptr;
+	PtrSize m_offset = kMaxPtrSize;
+	PtrSize m_size = 0;
+};
+
+/// GPU only transient memory. Used for temporary allocations. Allocations will get reset after each frame.
+class GpuVisibleTransientMemoryPool : public MakeSingleton<GpuVisibleTransientMemoryPool>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	GpuVisibleTransientMemoryAllocation allocate(PtrSize size)
+	{
+		GpuVisibleTransientMemoryAllocation out;
+		m_pool.allocate(size, out.m_offset, out.m_buffer);
+		out.m_size = size;
+		return out;
+	}
+
+	void endFrame()
+	{
+		if(m_frame == 0)
+		{
+			m_pool.reset();
+		}
+
+		m_frame = (m_frame + 1) % kMaxFramesInFlight;
+	}
+
+private:
+	StackGpuMemoryPool m_pool;
+	U32 m_frame = 0;
+
+	GpuVisibleTransientMemoryPool()
+	{
+		U32 alignment = GrManager::getSingleton().getDeviceCapabilities().m_uniformBufferBindOffsetAlignment;
+		alignment = max(alignment, GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment);
+		alignment = max(alignment, GrManager::getSingleton().getDeviceCapabilities().m_sbtRecordAlignment);
+		alignment = max(alignment, GrManager::getSingleton().getDeviceCapabilities().m_accelerationStructureBuildScratchOffsetAlignment);
+
+		BufferUsageBit buffUsage = BufferUsageBit::kAllUniform | BufferUsageBit::kAllStorage | BufferUsageBit::kIndirectDraw
+								   | BufferUsageBit::kIndirectCompute | BufferUsageBit::kVertex | BufferUsageBit::kTransferDestination;
+		if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
+		{
+			buffUsage |= (BufferUsageBit::kAccelerationStructureBuildScratch | BufferUsageBit::kAccelerationStructureBuild);
+		}
+		m_pool.init(10_MB, 2.0, 0, alignment, buffUsage, BufferMapAccessBit::kNone, true, "GpuVisibleTransientMemoryPool");
+	}
+
+	~GpuVisibleTransientMemoryPool() = default;
+};
+
+inline GpuVisibleTransientMemoryAllocation::operator BufferOffsetRange() const
+{
+	ANKI_ASSERT(isValid());
+	return {m_buffer, m_offset, m_size};
+}
+/// @}
+
+} // end namespace anki

+ 96 - 0
AnKi/Core/GpuMemory/RebarTransientMemoryPool.cpp

@@ -0,0 +1,96 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
+#include <AnKi/Core/CVarSet.h>
+#include <AnKi/Core/StatsSet.h>
+#include <AnKi/Util/Tracer.h>
+#include <AnKi/Gr/GrManager.h>
+#include <AnKi/Gr/Buffer.h>
+
+namespace anki {
+
+static StatCounter g_rebarUserMemoryStatVar(StatCategory::kGpuMem, "ReBAR used mem", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+
+static NumericCVar<PtrSize> g_rebarGpuMemorySizeCvar(CVarSubsystem::kCore, "RebarGpuMemorySize", 24_MB, 1_MB, 1_GB,
+													 "ReBAR: always mapped GPU memory");
+
+RebarTransientMemoryPool::~RebarTransientMemoryPool()
+{
+	GrManager::getSingleton().finish();
+
+	m_buffer->unmap();
+	m_buffer.reset(nullptr);
+}
+
+void RebarTransientMemoryPool::init()
+{
+	BufferInitInfo buffInit("ReBar");
+	buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
+	buffInit.m_size = g_rebarGpuMemorySizeCvar.get();
+	buffInit.m_usage = BufferUsageBit::kAllUniform | BufferUsageBit::kAllStorage | BufferUsageBit::kVertex | BufferUsageBit::kIndex
+					   | BufferUsageBit::kShaderBindingTable | BufferUsageBit::kAllIndirect | BufferUsageBit::kTransferSource;
+	m_buffer = GrManager::getSingleton().newBuffer(buffInit);
+
+	m_bufferSize = buffInit.m_size;
+
+	m_alignment = GrManager::getSingleton().getDeviceCapabilities().m_uniformBufferBindOffsetAlignment;
+	m_alignment = max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment);
+	m_alignment = max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_sbtRecordAlignment);
+
+	m_mappedMem = static_cast<U8*>(m_buffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
+}
+
+RebarAllocation RebarTransientMemoryPool::allocateFrame(PtrSize size, void*& mappedMem)
+{
+	RebarAllocation out = tryAllocateFrame(size, mappedMem);
+	if(!out.isValid()) [[unlikely]]
+	{
+		ANKI_CORE_LOGF("Out of ReBAR GPU memory");
+	}
+
+	return out;
+}
+
+RebarAllocation RebarTransientMemoryPool::tryAllocateFrame(PtrSize origSize, void*& mappedMem)
+{
+	const PtrSize size = getAlignedRoundUp(m_alignment, origSize);
+
+	// Try in a loop because we may end up with an allocation its offset crosses the buffer's end
+	PtrSize offset;
+	Bool done = false;
+	do
+	{
+		offset = m_offset.fetchAdd(size) % m_bufferSize;
+		const PtrSize end = (offset + origSize) % (m_bufferSize + 1);
+
+		done = offset < end;
+	} while(!done);
+
+	mappedMem = m_mappedMem + offset;
+	RebarAllocation out;
+	out.m_offset = offset;
+	out.m_range = origSize;
+
+	return out;
+}
+
+void RebarTransientMemoryPool::endFrame()
+{
+	const PtrSize crntOffset = m_offset.getNonAtomically();
+
+	const PtrSize usedMemory = crntOffset - m_previousFrameEndOffset;
+	m_previousFrameEndOffset = crntOffset;
+
+	if(usedMemory >= PtrSize(0.8 * F64(m_bufferSize / kMaxFramesInFlight)))
+	{
+		ANKI_CORE_LOGW("Frame used more that 80%% of its safe limit of ReBAR memory");
+	}
+
+	ANKI_TRACE_INC_COUNTER(ReBarUsedMemory, usedMemory);
+	g_rebarUserMemoryStatVar.set(usedMemory);
+}
+
+} // end namespace anki

+ 131 - 0
AnKi/Core/GpuMemory/RebarTransientMemoryPool.h

@@ -0,0 +1,131 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Gr/Buffer.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+/// Token that gets returned when requesting for memory to write to a resource.
+class RebarAllocation
+{
+	friend class RebarTransientMemoryPool;
+
+public:
+	RebarAllocation() = default;
+
+	~RebarAllocation() = default;
+
+	Bool operator==(const RebarAllocation& b) const
+	{
+		return m_offset == b.m_offset && m_range == b.m_range;
+	}
+
+	Bool isValid() const
+	{
+		return m_range != 0;
+	}
+
+	PtrSize getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_offset;
+	}
+
+	PtrSize getRange() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_range;
+	}
+
+	Buffer& getBuffer() const;
+
+	operator BufferOffsetRange() const;
+
+private:
+	PtrSize m_offset = kMaxPtrSize;
+	PtrSize m_range = 0;
+};
+
+/// Manages staging GPU memory.
+class RebarTransientMemoryPool : public MakeSingleton<RebarTransientMemoryPool>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	RebarTransientMemoryPool(const RebarTransientMemoryPool&) = delete; // Non-copyable
+
+	RebarTransientMemoryPool& operator=(const RebarTransientMemoryPool&) = delete; // Non-copyable
+
+	void init();
+
+	void endFrame();
+
+	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the N-(kMaxFramesInFlight-1) frame.
+	RebarAllocation allocateFrame(PtrSize size, void*& mappedMem);
+
+	template<typename T>
+	RebarAllocation allocateFrame(U32 count, T*& mappedMem)
+	{
+		void* mem;
+		const RebarAllocation out = allocateFrame(count * sizeof(T), mem);
+		mappedMem = static_cast<T*>(mem);
+		return out;
+	}
+
+	template<typename T>
+	RebarAllocation allocateFrame(U32 count, WeakArray<T>& arr)
+	{
+		void* mem;
+		const RebarAllocation out = allocateFrame(count * sizeof(T), mem);
+		arr = {static_cast<T*>(mem), count};
+		return out;
+	}
+
+	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the N-(kMaxFramesInFlight-1) frame.
+	RebarAllocation tryAllocateFrame(PtrSize size, void*& mappedMem);
+
+	ANKI_PURE Buffer& getBuffer() const
+	{
+		return *m_buffer;
+	}
+
+	U8* getBufferMappedAddress()
+	{
+		return m_mappedMem;
+	}
+
+private:
+	BufferPtr m_buffer;
+	U8* m_mappedMem = nullptr; ///< Cache it.
+	PtrSize m_bufferSize = 0; ///< Cache it.
+	Atomic<PtrSize> m_offset = {0};
+	PtrSize m_previousFrameEndOffset = 0;
+	U32 m_alignment = 0;
+
+	RebarTransientMemoryPool() = default;
+
+	~RebarTransientMemoryPool();
+};
+
+inline Buffer& RebarAllocation::getBuffer() const
+{
+	return RebarTransientMemoryPool::getSingleton().getBuffer();
+}
+
+inline RebarAllocation::operator BufferOffsetRange() const
+{
+	ANKI_ASSERT(isValid());
+	return {&RebarTransientMemoryPool::getSingleton().getBuffer(), m_offset, m_range};
+}
+/// @}
+
+} // end namespace anki

+ 53 - 0
AnKi/Core/GpuMemory/UnifiedGeometryBuffer.cpp

@@ -0,0 +1,53 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h>
+#include <AnKi/Core/CVarSet.h>
+#include <AnKi/Core/StatsSet.h>
+#include <AnKi/Gr/GrManager.h>
+
+namespace anki {
+
+static StatCounter g_unifiedGeomBufferAllocatedSizeStatVar(StatCategory::kGpuMem, "UGB allocated", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+static StatCounter g_unifiedGeomBufferTotalStatVar(StatCategory::kGpuMem, "UGB total", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+static StatCounter g_unifiedGeomBufferFragmentationStatVar(StatCategory::kGpuMem, "UGB fragmentation",
+														   StatFlag::kFloat | StatFlag::kMainThreadUpdates);
+
+static NumericCVar<PtrSize> g_unifiedGometryBufferSizeCvar(CVarSubsystem::kCore, "UnifiedGeometryBufferSize", 128_MB, 16_MB, 2_GB,
+														   "Global index and vertex buffer size");
+
+void UnifiedGeometryBuffer::init()
+{
+	const PtrSize poolSize = g_unifiedGometryBufferSizeCvar.get();
+
+	const Array classes = {1_KB, 8_KB, 32_KB, 128_KB, 512_KB, 4_MB, 8_MB, 16_MB, poolSize};
+
+	BufferUsageBit buffUsage = BufferUsageBit::kVertex | BufferUsageBit::kIndex | BufferUsageBit::kTransferDestination
+							   | (BufferUsageBit::kAllTexture & BufferUsageBit::kAllRead);
+
+	if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
+	{
+		buffUsage |= BufferUsageBit::kAccelerationStructureBuild;
+	}
+
+	m_pool.init(buffUsage, classes, poolSize, "UnifiedGeometry", false);
+
+	// Allocate something dummy to force creating the GPU buffer
+	UnifiedGeometryBufferAllocation alloc = allocate(16, 4);
+	deferredFree(alloc);
+}
+
+void UnifiedGeometryBuffer::updateStats() const
+{
+	F32 externalFragmentation;
+	PtrSize userAllocatedSize, totalSize;
+	m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
+
+	g_unifiedGeomBufferAllocatedSizeStatVar.set(userAllocatedSize);
+	g_unifiedGeomBufferTotalStatVar.set(totalSize);
+	g_unifiedGeomBufferFragmentationStatVar.set(externalFragmentation);
+}
+
+} // end namespace anki

+ 147 - 0
AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h

@@ -0,0 +1,147 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+/// @memberof UnifiedGeometryBuffer
+class UnifiedGeometryBufferAllocation
+{
+	friend class UnifiedGeometryBuffer;
+
+public:
+	UnifiedGeometryBufferAllocation() = default;
+
+	UnifiedGeometryBufferAllocation(const UnifiedGeometryBufferAllocation&) = delete;
+
+	UnifiedGeometryBufferAllocation(UnifiedGeometryBufferAllocation&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~UnifiedGeometryBufferAllocation();
+
+	UnifiedGeometryBufferAllocation& operator=(const UnifiedGeometryBufferAllocation&) = delete;
+
+	UnifiedGeometryBufferAllocation& operator=(UnifiedGeometryBufferAllocation&& b)
+	{
+		ANKI_ASSERT(!isValid() && "Forgot to delete");
+		m_token = b.m_token;
+		m_realOffset = b.m_realOffset;
+		m_realAllocatedSize = b.m_realAllocatedSize;
+		b.m_token = {};
+		b.m_realAllocatedSize = 0;
+		b.m_realOffset = kMaxU32;
+		return *this;
+	}
+
+	Bool isValid() const
+	{
+		return m_token.m_offset != kMaxPtrSize;
+	}
+
+	/// Get offset in the Unified Geometry Buffer buffer.
+	U32 getOffset() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_realOffset;
+	}
+
+	U32 getAllocatedSize() const
+	{
+		ANKI_ASSERT(isValid());
+		return m_realAllocatedSize;
+	}
+
+private:
+	SegregatedListsGpuMemoryPoolToken m_token;
+	U32 m_realOffset = kMaxU32; ///< In some allocations with weird alignments we need a different offset.
+	U32 m_realAllocatedSize = 0;
+};
+
+/// Manages vertex and index memory for the WHOLE application.
+class UnifiedGeometryBuffer : public MakeSingleton<UnifiedGeometryBuffer>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+public:
+	UnifiedGeometryBuffer(const UnifiedGeometryBuffer&) = delete; // Non-copyable
+
+	UnifiedGeometryBuffer& operator=(const UnifiedGeometryBuffer&) = delete; // Non-copyable
+
+	void init();
+
+	UnifiedGeometryBufferAllocation allocate(PtrSize size, U32 alignment)
+	{
+		UnifiedGeometryBufferAllocation out;
+		m_pool.allocate(size, alignment, out.m_token);
+		out.m_realOffset = U32(out.m_token.m_offset);
+		out.m_realAllocatedSize = U32(size);
+		return out;
+	}
+
+	/// Allocate a vertex buffer.
+	UnifiedGeometryBufferAllocation allocateFormat(Format format, U32 count)
+	{
+		const U32 texelSize = getFormatInfo(format).m_texelSize;
+		const U32 alignment = max(4u, nextPowerOfTwo(texelSize));
+		const U32 size = count * texelSize + alignment; // Over-allocate
+
+		UnifiedGeometryBufferAllocation out;
+		m_pool.allocate(size, alignment, out.m_token);
+
+		const U32 remainder = out.m_token.m_offset % texelSize;
+		out.m_realOffset = U32(out.m_token.m_offset + (texelSize - remainder));
+		out.m_realAllocatedSize = count * texelSize;
+		ANKI_ASSERT(isAligned(texelSize, out.m_realOffset));
+		ANKI_ASSERT(out.m_realOffset + out.m_realAllocatedSize <= out.m_token.m_offset + out.m_token.m_size);
+		return out;
+	}
+
+	void deferredFree(UnifiedGeometryBufferAllocation& alloc)
+	{
+		m_pool.deferredFree(alloc.m_token);
+		alloc.m_realAllocatedSize = 0;
+		alloc.m_realOffset = kMaxU32;
+	}
+
+	void endFrame()
+	{
+		m_pool.endFrame();
+#if ANKI_STATS_ENABLED
+		updateStats();
+#endif
+	}
+
+	Buffer& getBuffer() const
+	{
+		return m_pool.getGpuBuffer();
+	}
+
+private:
+	SegregatedListsGpuMemoryPool m_pool;
+
+	UnifiedGeometryBuffer() = default;
+
+	~UnifiedGeometryBuffer() = default;
+
+	void updateStats() const;
+};
+
+inline UnifiedGeometryBufferAllocation::~UnifiedGeometryBufferAllocation()
+{
+	UnifiedGeometryBuffer::getSingleton().deferredFree(*this);
+}
+/// @}
+
+} // end namespace anki

+ 0 - 240
AnKi/Core/GpuMemoryPools.cpp

@@ -1,240 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Core/GpuMemoryPools.h>
-#include <AnKi/Core/ConfigSet.h>
-#include <AnKi/Gr/GrManager.h>
-#include <AnKi/Gr/CommandBuffer.h>
-#include <AnKi/Util/Tracer.h>
-#include <AnKi/Resource/ResourceManager.h>
-
-namespace anki {
-
-void UnifiedGeometryMemoryPool::init()
-{
-	const PtrSize poolSize = ConfigSet::getSingleton().getCoreGlobalVertexMemorySize();
-
-	const Array classes = {1_KB, 8_KB, 32_KB, 128_KB, 512_KB, 4_MB, 8_MB, 16_MB, poolSize};
-
-	BufferUsageBit buffUsage = BufferUsageBit::kVertex | BufferUsageBit::kIndex | BufferUsageBit::kTransferDestination
-							   | (BufferUsageBit::kAllTexture & BufferUsageBit::kAllRead);
-
-	if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
-	{
-		buffUsage |= BufferUsageBit::kAccelerationStructureBuild;
-	}
-
-	m_pool.init(buffUsage, classes, poolSize, "UnifiedGeometry", false);
-
-	// Allocate something dummy to force creating the GPU buffer
-	SegregatedListsGpuMemoryPoolToken token;
-	allocate(16, 4, token);
-	deferredFree(token);
-}
-
-void GpuSceneMemoryPool::init()
-{
-	const PtrSize poolSize = ConfigSet::getSingleton().getCoreGpuSceneInitialSize();
-
-	const Array classes = {32_B, 64_B, 128_B, 256_B, poolSize};
-
-	BufferUsageBit buffUsage = BufferUsageBit::kAllStorage | BufferUsageBit::kTransferDestination;
-
-	m_pool.init(buffUsage, classes, poolSize, "GpuScene", true);
-
-	// Allocate something dummy to force creating the GPU buffer
-	SegregatedListsGpuMemoryPoolToken token;
-	allocate(16, 4, token);
-	deferredFree(token);
-}
-
-RebarStagingGpuMemoryPool::~RebarStagingGpuMemoryPool()
-{
-	GrManager::getSingleton().finish();
-
-	m_buffer->unmap();
-	m_buffer.reset(nullptr);
-}
-
-void RebarStagingGpuMemoryPool::init()
-{
-	BufferInitInfo buffInit("ReBar");
-	buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
-	buffInit.m_size = ConfigSet::getSingleton().getCoreRebarGpuMemorySize();
-	buffInit.m_usage = BufferUsageBit::kAllUniform | BufferUsageBit::kAllStorage | BufferUsageBit::kVertex
-					   | BufferUsageBit::kIndex | BufferUsageBit::kShaderBindingTable;
-	m_buffer = GrManager::getSingleton().newBuffer(buffInit);
-
-	m_bufferSize = buffInit.m_size;
-
-	m_alignment = GrManager::getSingleton().getDeviceCapabilities().m_uniformBufferBindOffsetAlignment;
-	m_alignment =
-		max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment);
-	m_alignment = max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_sbtRecordAlignment);
-
-	m_mappedMem = static_cast<U8*>(m_buffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-}
-
-void* RebarStagingGpuMemoryPool::allocateFrame(PtrSize size, RebarGpuMemoryToken& token)
-{
-	void* address = tryAllocateFrame(size, token);
-	if(address == nullptr) [[unlikely]]
-	{
-		ANKI_CORE_LOGF("Out of ReBAR GPU memory");
-	}
-
-	return address;
-}
-
-void* RebarStagingGpuMemoryPool::tryAllocateFrame(PtrSize origSize, RebarGpuMemoryToken& token)
-{
-	const PtrSize size = getAlignedRoundUp(m_alignment, origSize);
-
-	// Try in a loop because we may end up with an allocation its offset crosses the buffer's end
-	PtrSize offset;
-	Bool done = false;
-	do
-	{
-		offset = m_offset.fetchAdd(size) % m_bufferSize;
-		const PtrSize end = (offset + origSize) % (m_bufferSize + 1);
-
-		done = offset < end;
-	} while(!done);
-
-	void* address = m_mappedMem + offset;
-	token.m_offset = offset;
-	token.m_range = origSize;
-
-	return address;
-}
-
-PtrSize RebarStagingGpuMemoryPool::endFrame()
-{
-	const PtrSize crntOffset = m_offset.getNonAtomically();
-
-	const PtrSize usedMemory = crntOffset - m_previousFrameEndOffset;
-	m_previousFrameEndOffset = crntOffset;
-
-	if(usedMemory >= PtrSize(0.8 * F64(m_bufferSize / kMaxFramesInFlight)))
-	{
-		ANKI_CORE_LOGW("Frame used more that 80%% of its safe limit of ReBAR memory");
-	}
-
-	ANKI_TRACE_INC_COUNTER(ReBarUsedMemory, usedMemory);
-	return usedMemory;
-}
-
-/// It packs the source and destination offsets as well as the size of the patch itself.
-class GpuSceneMicroPatcher::PatchHeader
-{
-public:
-	U32 m_dwordCountAndSrcDwordOffsetPack;
-	U32 m_dstDwordOffset;
-};
-
-GpuSceneMicroPatcher::GpuSceneMicroPatcher()
-{
-}
-
-GpuSceneMicroPatcher::~GpuSceneMicroPatcher()
-{
-	static_assert(sizeof(PatchHeader) == 8);
-}
-
-Error GpuSceneMicroPatcher::init()
-{
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuSceneMicroPatching.ankiprogbin",
-															m_copyProgram));
-	const ShaderProgramResourceVariant* variant;
-	m_copyProgram->getOrCreateVariant(variant);
-	m_grProgram = variant->getProgram();
-
-	return Error::kNone;
-}
-
-void GpuSceneMicroPatcher::newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, PtrSize dataSize,
-								   const void* data)
-{
-	ANKI_ASSERT(dataSize > 0 && (dataSize % 4) == 0);
-	ANKI_ASSERT((ptrToNumber(data) % 4) == 0);
-	ANKI_ASSERT((gpuSceneDestOffset % 4) == 0 && gpuSceneDestOffset / 4 < kMaxU32);
-
-	const U32 dataDwords = U32(dataSize / 4);
-	U32 gpuSceneDestDwordOffset = U32(gpuSceneDestOffset / 4);
-
-	const U32* patchIt = static_cast<const U32*>(data);
-	const U32* const patchEnd = patchIt + dataDwords;
-
-	// Break the data into multiple copies
-	LockGuard lock(m_mtx);
-
-	if(m_crntFramePatchHeaders.getSize() == 0)
-	{
-		m_crntFramePatchHeaders = DynamicArray<PatchHeader, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
-		m_crntFramePatchData = DynamicArray<U32, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
-	}
-
-	while(patchIt < patchEnd)
-	{
-		const U32 patchDwords = min(kDwordsPerPatch, U32(patchEnd - patchIt));
-
-		PatchHeader& header = *m_crntFramePatchHeaders.emplaceBack();
-		ANKI_ASSERT(((patchDwords - 1) & 0b111111) == (patchDwords - 1));
-		header.m_dwordCountAndSrcDwordOffsetPack = patchDwords - 1;
-		header.m_dwordCountAndSrcDwordOffsetPack <<= 26;
-		ANKI_ASSERT((m_crntFramePatchData.getSize() & 0x3FFFFFF) == m_crntFramePatchData.getSize());
-		header.m_dwordCountAndSrcDwordOffsetPack |= m_crntFramePatchData.getSize();
-		header.m_dstDwordOffset = gpuSceneDestDwordOffset;
-
-		const U32 srcOffset = m_crntFramePatchData.getSize();
-		m_crntFramePatchData.resize(srcOffset + patchDwords);
-		memcpy(&m_crntFramePatchData[srcOffset], patchIt, patchDwords * 4);
-
-		patchIt += patchDwords;
-		gpuSceneDestDwordOffset += patchDwords;
-	}
-}
-
-void GpuSceneMicroPatcher::patchGpuScene(CommandBuffer& cmdb)
-{
-	if(m_crntFramePatchHeaders.getSize() == 0)
-	{
-		return;
-	}
-
-	ANKI_ASSERT(m_crntFramePatchData.getSize() > 0);
-
-	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatches, m_crntFramePatchHeaders.getSize());
-	ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatchUploadData, m_crntFramePatchData.getSizeInBytes());
-
-	RebarGpuMemoryToken headersToken;
-	void* mapped =
-		RebarStagingGpuMemoryPool::getSingleton().allocateFrame(m_crntFramePatchHeaders.getSizeInBytes(), headersToken);
-	memcpy(mapped, &m_crntFramePatchHeaders[0], m_crntFramePatchHeaders.getSizeInBytes());
-
-	RebarGpuMemoryToken dataToken;
-	mapped = RebarStagingGpuMemoryPool::getSingleton().allocateFrame(m_crntFramePatchData.getSizeInBytes(), dataToken);
-	memcpy(mapped, &m_crntFramePatchData[0], m_crntFramePatchData.getSizeInBytes());
-
-	cmdb.bindStorageBuffer(0, 0, RebarStagingGpuMemoryPool::getSingleton().getBuffer(), headersToken.m_offset,
-						   headersToken.m_range);
-	cmdb.bindStorageBuffer(0, 1, RebarStagingGpuMemoryPool::getSingleton().getBuffer(), dataToken.m_offset,
-						   dataToken.m_range);
-	cmdb.bindStorageBuffer(0, 2, GpuSceneMemoryPool::getSingleton().getBuffer(), 0, kMaxPtrSize);
-
-	cmdb.bindShaderProgram(m_grProgram);
-
-	const U32 workgroupCountX = m_crntFramePatchHeaders.getSize();
-	cmdb.dispatchCompute(workgroupCountX, 1, 1);
-
-	// Cleanup to prepare for the new frame
-	U32* data;
-	U32 size, storage;
-	m_crntFramePatchData.moveAndReset(data, size, storage);
-	PatchHeader* datah;
-	m_crntFramePatchHeaders.moveAndReset(datah, size, storage);
-}
-
-} // end namespace anki

+ 0 - 230
AnKi/Core/GpuMemoryPools.h

@@ -1,230 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Core/Common.h>
-#include <AnKi/Gr/Buffer.h>
-#include <AnKi/Gr/Utils/StackGpuMemoryPool.h>
-#include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
-#include <AnKi/Resource/ShaderProgramResource.h>
-
-namespace anki {
-
-/// @addtogroup core
-/// @{
-
-/// Manages vertex and index memory for the whole application.
-class UnifiedGeometryMemoryPool : public MakeSingleton<UnifiedGeometryMemoryPool>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	UnifiedGeometryMemoryPool(const UnifiedGeometryMemoryPool&) = delete; // Non-copyable
-
-	UnifiedGeometryMemoryPool& operator=(const UnifiedGeometryMemoryPool&) = delete; // Non-copyable
-
-	void init();
-
-	void allocate(PtrSize size, U32 alignment, SegregatedListsGpuMemoryPoolToken& token)
-	{
-		m_pool.allocate(size, alignment, token);
-	}
-
-	void deferredFree(SegregatedListsGpuMemoryPoolToken& token)
-	{
-		m_pool.deferredFree(token);
-	}
-
-	void endFrame()
-	{
-		m_pool.endFrame();
-	}
-
-	const BufferPtr& getBuffer() const
-	{
-		return m_pool.getGpuBuffer();
-	}
-
-	void getStats(F32& externalFragmentation, PtrSize& userAllocatedSize, PtrSize& totalSize) const
-	{
-		m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
-	}
-
-private:
-	SegregatedListsGpuMemoryPool m_pool;
-
-	UnifiedGeometryMemoryPool() = default;
-
-	~UnifiedGeometryMemoryPool() = default;
-};
-
-/// Memory pool for the GPU scene.
-class GpuSceneMemoryPool : public MakeSingleton<GpuSceneMemoryPool>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	GpuSceneMemoryPool(const GpuSceneMemoryPool&) = delete; // Non-copyable
-
-	GpuSceneMemoryPool& operator=(const GpuSceneMemoryPool&) = delete; // Non-copyable
-
-	void init();
-
-	void allocate(PtrSize size, U32 alignment, SegregatedListsGpuMemoryPoolToken& token)
-	{
-		m_pool.allocate(size, alignment, token);
-	}
-
-	void deferredFree(SegregatedListsGpuMemoryPoolToken& token)
-	{
-		m_pool.deferredFree(token);
-	}
-
-	void endFrame()
-	{
-		m_pool.endFrame();
-	}
-
-	const BufferPtr& getBuffer() const
-	{
-		return m_pool.getGpuBuffer();
-	}
-
-	void getStats(F32& externalFragmentation, PtrSize& userAllocatedSize, PtrSize& totalSize) const
-	{
-		m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
-	}
-
-private:
-	SegregatedListsGpuMemoryPool m_pool;
-
-	GpuSceneMemoryPool() = default;
-
-	~GpuSceneMemoryPool() = default;
-};
-
-/// Token that gets returned when requesting for memory to write to a resource.
-class RebarGpuMemoryToken
-{
-public:
-	PtrSize m_offset = 0;
-	PtrSize m_range = 0;
-
-	RebarGpuMemoryToken() = default;
-
-	~RebarGpuMemoryToken() = default;
-
-	Bool operator==(const RebarGpuMemoryToken& b) const
-	{
-		return m_offset == b.m_offset && m_range == b.m_range;
-	}
-
-	void markUnused()
-	{
-		m_offset = m_range = kMaxU32;
-	}
-
-	Bool isUnused() const
-	{
-		return m_offset == kMaxU32 && m_range == kMaxU32;
-	}
-};
-
-/// Manages staging GPU memory.
-class RebarStagingGpuMemoryPool : public MakeSingleton<RebarStagingGpuMemoryPool>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	RebarStagingGpuMemoryPool(const RebarStagingGpuMemoryPool&) = delete; // Non-copyable
-
-	~RebarStagingGpuMemoryPool();
-
-	RebarStagingGpuMemoryPool& operator=(const RebarStagingGpuMemoryPool&) = delete; // Non-copyable
-
-	void init();
-
-	PtrSize endFrame();
-
-	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the
-	/// N-(kMaxFramesInFlight-1) frame.
-	void* allocateFrame(PtrSize size, RebarGpuMemoryToken& token);
-
-	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the
-	/// N-(kMaxFramesInFlight-1) frame.
-	void* tryAllocateFrame(PtrSize size, RebarGpuMemoryToken& token);
-
-	ANKI_PURE const BufferPtr& getBuffer() const
-	{
-		return m_buffer;
-	}
-
-	U8* getBufferMappedAddress()
-	{
-		return m_mappedMem;
-	}
-
-private:
-	BufferPtr m_buffer;
-	U8* m_mappedMem = nullptr; ///< Cache it.
-	PtrSize m_bufferSize = 0; ///< Cache it.
-	Atomic<PtrSize> m_offset = {0};
-	PtrSize m_previousFrameEndOffset = 0;
-	U32 m_alignment = 0;
-
-	RebarStagingGpuMemoryPool() = default;
-};
-
-/// Creates the copy jobs that will patch the GPU Scene.
-class GpuSceneMicroPatcher : public MakeSingleton<GpuSceneMicroPatcher>
-{
-	template<typename>
-	friend class MakeSingleton;
-
-public:
-	GpuSceneMicroPatcher(const GpuSceneMicroPatcher&) = delete;
-
-	GpuSceneMicroPatcher& operator=(const GpuSceneMicroPatcher&) = delete;
-
-	Error init();
-
-	/// Copy data for the GPU scene to a staging buffer.
-	/// @note It's thread-safe.
-	void newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, PtrSize dataSize, const void* data);
-
-	/// Check if there is a need to call patchGpuScene or if no copies are needed.
-	/// @note Not thread-safe. Nothing else should be happening before calling it.
-	Bool patchingIsNeeded() const
-	{
-		return m_crntFramePatchHeaders.getSize() > 0;
-	}
-
-	/// Copy the data to the GPU scene buffer.
-	/// @note Not thread-safe. Nothing else should be happening before calling it.
-	void patchGpuScene(CommandBuffer& cmdb);
-
-private:
-	static constexpr U32 kDwordsPerPatch = 64;
-
-	class PatchHeader;
-
-	DynamicArray<PatchHeader, MemoryPoolPtrWrapper<StackMemoryPool>> m_crntFramePatchHeaders;
-	DynamicArray<U32, MemoryPoolPtrWrapper<StackMemoryPool>> m_crntFramePatchData;
-	Mutex m_mtx;
-
-	ShaderProgramResourcePtr m_copyProgram;
-	ShaderProgramPtr m_grProgram;
-
-	GpuSceneMicroPatcher();
-
-	~GpuSceneMicroPatcher();
-};
-/// @}
-
-} // end namespace anki

+ 1 - 2
AnKi/Core/MaliHwCounters.cpp

@@ -17,8 +17,7 @@ MaliHwCounters::MaliHwCounters()
 {
 {
 #if ANKI_HWCPIPE_ENABLE
 #if ANKI_HWCPIPE_ENABLE
 	const hwcpipe::CpuCounterSet cpuCounters;
 	const hwcpipe::CpuCounterSet cpuCounters;
-	const hwcpipe::GpuCounterSet gpuCounters = {hwcpipe::GpuCounter::GpuCycles,
-												hwcpipe::GpuCounter::ExternalMemoryWriteBytes,
+	const hwcpipe::GpuCounterSet gpuCounters = {hwcpipe::GpuCounter::GpuCycles, hwcpipe::GpuCounter::ExternalMemoryWriteBytes,
 												hwcpipe::GpuCounter::ExternalMemoryReadBytes};
 												hwcpipe::GpuCounter::ExternalMemoryReadBytes};
 	hwcpipe::HWCPipe* hwc = newInstance<hwcpipe::HWCPipe>(CoreMemoryPool::getSingleton(), cpuCounters, gpuCounters);
 	hwcpipe::HWCPipe* hwc = newInstance<hwcpipe::HWCPipe>(CoreMemoryPool::getSingleton(), cpuCounters, gpuCounters);
 
 

+ 113 - 0
AnKi/Core/StatsSet.cpp

@@ -0,0 +1,113 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Core/StatsSet.h>
+
+namespace anki {
+
+#if ANKI_STATS_ENABLED
+StatsSet::~StatsSet()
+{
+	if(m_statCounterArr)
+	{
+		ANKI_ASSERT(m_statCounterArrSize > 0);
+		free(m_statCounterArr);
+		m_statCounterArr = nullptr;
+		m_statCounterArrSize = 0;
+		m_statCounterArrStorageSize = 0;
+	}
+}
+
+void StatsSet::endFrame()
+{
+	for(U32 i = 0; i < m_statCounterArrSize; ++i)
+	{
+		StatCounter& counter = *m_statCounterArr[i];
+		const Bool needsReset = !!(counter.m_flags & StatFlag::kZeroEveryFrame);
+		const Bool atomic = !(counter.m_flags & StatFlag::kMainThreadUpdates);
+		const Bool isFloat = !!(counter.m_flags & StatFlag::kFloat);
+
+		// Store the previous value
+		if(isFloat)
+		{
+			if(atomic)
+			{
+				LockGuard lock(counter.m_floatLock);
+				counter.m_prevValuef = counter.m_f;
+
+				if(needsReset)
+				{
+					counter.m_f = 0.0;
+				}
+			}
+			else
+			{
+				counter.m_prevValuef = counter.m_f;
+
+				if(needsReset)
+				{
+					counter.m_f = 0;
+				}
+			}
+		}
+		else
+		{
+			if(atomic && needsReset)
+			{
+				counter.m_prevValueu = counter.m_atomic.exchange(0);
+			}
+			else if(atomic && !needsReset)
+			{
+				counter.m_prevValueu = counter.m_atomic.load();
+			}
+			else if(!atomic && needsReset)
+			{
+				counter.m_prevValueu = counter.m_u;
+				counter.m_u = 0;
+			}
+			else if(!atomic && !needsReset)
+			{
+				counter.m_prevValueu = counter.m_u;
+			}
+		}
+	}
+}
+
+void StatsSet::registerCounter(StatCounter* counter)
+{
+	ANKI_ASSERT(counter);
+
+	// Try grow the array
+	if(m_statCounterArrSize + 1 > m_statCounterArrStorageSize)
+	{
+		m_statCounterArrStorageSize = max(2u, m_statCounterArrStorageSize * 2);
+
+		StatCounter** newArr = static_cast<StatCounter**>(malloc(sizeof(StatCounter*) * m_statCounterArrStorageSize));
+
+		if(m_statCounterArrSize > 0)
+		{
+			memcpy(newArr, m_statCounterArr, sizeof(StatCounter*) * m_statCounterArrSize);
+			free(m_statCounterArr);
+		}
+
+		m_statCounterArr = newArr;
+	}
+
+	m_statCounterArr[m_statCounterArrSize++] = counter;
+
+	std::sort(m_statCounterArr, m_statCounterArr + m_statCounterArrSize, [](const StatCounter* a, const StatCounter* b) {
+		if(a->m_category != b->m_category)
+		{
+			return a->m_category < b->m_category;
+		}
+		else
+		{
+			return strcmp(a->m_name, b->m_name) < 0;
+		}
+	});
+}
+#endif
+
+} // end namespace anki

+ 342 - 0
AnKi/Core/StatsSet.h

@@ -0,0 +1,342 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Core/Common.h>
+#include <AnKi/Util/Singleton.h>
+#include <AnKi/Util/Enum.h>
+#include <AnKi/Util/Thread.h>
+#include <AnKi/Util/String.h>
+
+namespace anki {
+
+/// @addtogroup core
+/// @{
+
+enum class StatFlag : U16
+{
+	kNone = 0,
+
+	kZeroEveryFrame = 1 << 0,
+	kMainThreadUpdates = 1 << 1, ///< Can only be updated from the main thread.
+	kFloat = 1 << 2,
+
+	kShowAverage = 1 << 3,
+	kSecond = (1 << 4) | kFloat,
+	kMilisecond = (1 << 5) | kFloat,
+	kNanoSeconds = 1 << 6,
+	kBytes = 1 << 7,
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(StatFlag)
+
+enum class StatCategory : U8
+{
+	kTime,
+	kCpuMem,
+	kGpuMem,
+	kGpuMisc,
+	kRenderer,
+	kMisc,
+
+	kCount,
+};
+
+inline constexpr Array<CString, U32(StatCategory::kCount)> kStatCategoryTexts = {"Time", "CPU memory", "GPU memory", "GPU misc", "Renderer", "Misc"};
+
+/// A stats counter.
+class StatCounter
+{
+	friend class StatsSet;
+
+public:
+	/// Construct.
+	/// @param name Name of the counter. The object will share ownership of the pointer.
+	StatCounter(StatCategory category, const Char* name, StatFlag flags);
+
+	template<std::integral T>
+	U64 increment(T value)
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!(m_flags & StatFlag::kFloat));
+		checkThread();
+		U64 orig;
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			orig = m_u;
+			m_u += value;
+		}
+		else
+		{
+			orig = m_atomic.fetchAdd(value);
+		}
+		return orig;
+#else
+		(void)value;
+		return 0;
+#endif
+	}
+
+	template<std::floating_point T>
+	F64 increment(T value)
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!!(m_flags & StatFlag::kFloat));
+		checkThread();
+		F64 orig;
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			orig = m_f;
+			m_f += value;
+		}
+		else
+		{
+			LockGuard lock(m_floatLock);
+			orig = m_f;
+			m_f += value;
+		}
+		return orig;
+#else
+		(void)value;
+		return 0.0;
+#endif
+	}
+
+	template<std::integral T>
+	U64 decrement(T value)
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!(m_flags & StatFlag::kFloat));
+		checkThread();
+		U64 orig;
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			orig = m_u;
+			m_u -= value;
+		}
+		else
+		{
+			orig = m_atomic.fetchSub(value);
+		}
+		ANKI_ASSERT(orig >= value);
+		return orig;
+#else
+		(void)value;
+		return 0;
+#endif
+	}
+
+	template<std::integral T>
+	U64 set(T value)
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!(m_flags & StatFlag::kFloat));
+		checkThread();
+		U64 orig;
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			orig = m_u;
+			m_u = value;
+		}
+		else
+		{
+			orig = m_atomic.exchange(value);
+		}
+		return orig;
+#else
+		(void)value;
+		return 0;
+#endif
+	}
+
+	template<std::floating_point T>
+	F64 set(T value)
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!!(m_flags & StatFlag::kFloat));
+		checkThread();
+		F64 orig;
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			orig = m_f;
+			m_f = value;
+		}
+		else
+		{
+			LockGuard lock(m_floatLock);
+			orig = m_f;
+			m_f = value;
+		}
+		return orig;
+#else
+		(void)value;
+		return 0.0;
+#endif
+	}
+
+	template<std::integral T>
+	U64 getValue() const
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!(m_flags & StatFlag::kFloat));
+		checkThread();
+		return !!(m_flags & StatFlag::kMainThreadUpdates) ? m_u : m_atomic.load();
+#else
+		return 0;
+#endif
+	}
+
+	template<std::floating_point T>
+	F64 getValue() const
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(!!(m_flags & StatFlag::kFloat));
+		checkThread();
+		if(!!(m_flags & StatFlag::kMainThreadUpdates))
+		{
+			return m_f;
+		}
+		else
+		{
+			LockGuard lock(m_floatLock);
+			return m_f;
+		}
+#else
+		return -1.0;
+#endif
+	}
+
+private:
+#if ANKI_STATS_ENABLED
+	union
+	{
+		Atomic<U64> m_atomic = {0};
+		U64 m_u;
+		F64 m_f;
+	};
+
+	union
+	{
+		U64 m_prevValueu = 0;
+		F64 m_prevValuef;
+	};
+
+	const Char* m_name = nullptr;
+
+	mutable SpinLock m_floatLock;
+
+	StatFlag m_flags = StatFlag::kNone;
+	StatCategory m_category = StatCategory::kCount;
+
+	void checkThread() const;
+#endif
+};
+
+/// A collection of stat counters.
+class StatsSet : public MakeSingletonSimple<StatsSet>
+{
+	friend class StatCounter;
+
+	template<typename>
+	friend class MakeSingletonSimple;
+
+public:
+	void initFromMainThread()
+	{
+#if ANKI_STATS_ENABLED
+		ANKI_ASSERT(m_mainThreadId == kMaxU64);
+		m_mainThreadId = Thread::getCurrentThreadId();
+#endif
+	}
+
+	/// @note Not thread-safe.
+	template<typename TFuncUint, typename TFuncFloat>
+	void iterateStats(TFuncUint funcUint, TFuncFloat funcFloat)
+	{
+#if ANKI_STATS_ENABLED
+		for(U32 i = 0; i < m_statCounterArrSize; ++i)
+		{
+			const StatCounter& counter = *m_statCounterArr[i];
+			if(!!(counter.m_flags & StatFlag::kFloat))
+			{
+				funcFloat(counter.m_category, counter.m_name, counter.m_prevValuef, counter.m_flags);
+			}
+			else
+			{
+				funcUint(counter.m_category, counter.m_name, counter.m_prevValueu, counter.m_flags);
+			}
+		}
+#else
+		(void)funcUint;
+		(void)funcFloat;
+#endif
+	}
+
+	/// @note Not thread-safe.
+	void endFrame()
+#if ANKI_STATS_ENABLED
+		;
+#else
+	{
+	}
+#endif
+
+	/// @note Thread-safe.
+	U32 getCounterCount() const
+	{
+#if ANKI_STATS_ENABLED
+		return m_statCounterArrSize;
+#else
+		return 0;
+#endif
+	}
+
+private:
+#if ANKI_STATS_ENABLED
+	StatCounter** m_statCounterArr = nullptr;
+	U32 m_statCounterArrSize = 0;
+	U32 m_statCounterArrStorageSize = 0;
+	U64 m_mainThreadId = kMaxU64;
+#endif
+
+	StatsSet() = default;
+
+#if ANKI_STATS_ENABLED
+	~StatsSet();
+
+	void registerCounter(StatCounter* counter);
+#endif
+};
+
+inline StatCounter::StatCounter(StatCategory category, const Char* name, StatFlag flags)
+#if ANKI_STATS_ENABLED
+	: m_name(name)
+	, m_flags(flags)
+	, m_category(category)
+{
+	ANKI_ASSERT(name);
+	ANKI_ASSERT(m_category < StatCategory::kCount);
+	StatsSet::getSingleton().registerCounter(this);
+}
+#else
+{
+	(void)category;
+	(void)name;
+	(void)flags;
+}
+#endif
+
+#if ANKI_STATS_ENABLED
+inline void StatCounter::checkThread() const
+{
+	if(!!(m_flags & StatFlag::kMainThreadUpdates))
+	{
+		ANKI_ASSERT(StatsSet::getSingleton().m_mainThreadId == Thread::getCurrentThreadId() && "Counter can only be updated from the main thread");
+	}
+}
+#endif
+/// @}
+
+} // end namespace anki

+ 0 - 153
AnKi/Core/StatsUi.cpp

@@ -1,153 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Core/StatsUi.h>
-#include <AnKi/Ui/UiManager.h>
-#include <AnKi/Ui/Font.h>
-#include <AnKi/Ui/Canvas.h>
-
-namespace anki {
-
-StatsUi::~StatsUi()
-{
-}
-
-Error StatsUi::init()
-{
-	ANKI_CHECK(UiManager::getSingleton().newInstance(m_font, "EngineAssets/UbuntuMonoRegular.ttf", Array<U32, 1>{24}));
-
-	return Error::kNone;
-}
-
-void StatsUi::labelBytes(PtrSize val, CString name) const
-{
-	PtrSize gb, mb, kb, b;
-
-	gb = val / 1_GB;
-	val -= gb * 1_GB;
-
-	mb = val / 1_MB;
-	val -= mb * 1_MB;
-
-	kb = val / 1_KB;
-	val -= kb * 1_KB;
-
-	b = val;
-
-	UiString timestamp;
-	if(gb)
-	{
-		timestamp.sprintf("%s: %zu,%04zu,%04zu,%04zu", name.cstr(), gb, mb, kb, b);
-	}
-	else if(mb)
-	{
-		timestamp.sprintf("%s: %zu,%04zu,%04zu", name.cstr(), mb, kb, b);
-	}
-	else if(kb)
-	{
-		timestamp.sprintf("%s: %zu,%04zu", name.cstr(), kb, b);
-	}
-	else
-	{
-		timestamp.sprintf("%s: %zu", name.cstr(), b);
-	}
-	ImGui::TextUnformatted(timestamp.cstr());
-}
-
-void StatsUi::setStats(const StatsUiInput& input, StatsUiDetail detail)
-{
-	Bool flush = false;
-	if(m_bufferedFrames == kBufferedFrames)
-	{
-		flush = true;
-		m_bufferedFrames = 0;
-	}
-	++m_bufferedFrames;
-
-#define ANKI_STATS_UI_BEGIN_GROUP(x)
-#define ANKI_STATS_UI_VALUE(type, name, text, flags) m_##name.update(input.m_##name, flags, flush);
-#include <AnKi/Core/StatsUi.defs.h>
-#undef ANKI_STATS_UI_BEGIN_GROUP
-#undef ANKI_STATS_UI_VALUE
-
-	m_detail = detail;
-}
-
-void StatsUi::build(CanvasPtr canvas)
-{
-	canvas->pushFont(m_font, 24);
-
-	const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
-	ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.3f;
-
-	if(ImGui::Begin("Stats", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize))
-	{
-		ImGui::SetWindowPos(Vec2(5.0f, 5.0f));
-		ImGui::SetWindowSize(Vec2(230.0f, 450.0f));
-
-		auto writeText = [this](const Value& v, const Char* text, ValueFlag flags, Bool isFloat) {
-			if(isFloat)
-			{
-				if(!!(flags & ValueFlag::kSeconds))
-				{
-					labelTime(v.m_float, text);
-				}
-				else
-				{
-					ImGui::Text("%s: %f", text, v.m_float);
-				}
-			}
-			else
-			{
-				U64 val;
-				if(!!(flags & ValueFlag::kAverage))
-				{
-					val = U64(v.m_avg);
-				}
-				else
-				{
-					val = v.m_int;
-				}
-
-				if(!!(flags & ValueFlag::kBytes))
-				{
-					labelBytes(val, text);
-				}
-				else
-				{
-					ImGui::Text("%s: %zu", text, val);
-				}
-			}
-		};
-
-		if(m_detail == StatsUiDetail::kDetailed)
-		{
-#define ANKI_STATS_UI_BEGIN_GROUP(x) \
-	ImGui::Text("----"); \
-	ImGui::Text(x); \
-	ImGui::Text("----");
-#define ANKI_STATS_UI_VALUE(type, name, text, flags) \
-	writeText(m_##name, text, flags, std::is_floating_point<type>::value);
-#include <AnKi/Core/StatsUi.defs.h>
-#undef ANKI_STATS_UI_BEGIN_GROUP
-#undef ANKI_STATS_UI_VALUE
-		}
-		else
-		{
-			const Second maxTime = max(m_cpuFrameTime.m_float, m_gpuFrameTime.m_float);
-			const F32 fps = F32(1.0 / maxTime);
-			const Bool cpuBound = m_cpuFrameTime.m_float > m_gpuFrameTime.m_float;
-			ImGui::TextColored((cpuBound) ? Vec4(1.0f, 0.5f, 0.5f, 1.0f) : Vec4(0.5f, 1.0f, 0.5f, 1.0f), "FPS %.1f",
-							   fps);
-		}
-	}
-
-	ImGui::End();
-	ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = oldWindowColor;
-
-	canvas->popFont();
-}
-
-} // end namespace anki

+ 0 - 37
AnKi/Core/StatsUi.defs.h

@@ -1,37 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-ANKI_STATS_UI_BEGIN_GROUP("CPU")
-ANKI_STATS_UI_VALUE(Second, cpuFrameTime, "Total frame", ValueFlag::kAverage | ValueFlag::kSeconds)
-ANKI_STATS_UI_VALUE(Second, rendererTime, "Renderer", ValueFlag::kAverage | ValueFlag::kSeconds)
-ANKI_STATS_UI_VALUE(Second, sceneUpdateTime, "Scene update", ValueFlag::kAverage | ValueFlag::kSeconds)
-ANKI_STATS_UI_VALUE(Second, visibilityTestsTime, "Visibility tests", ValueFlag::kAverage | ValueFlag::kSeconds)
-ANKI_STATS_UI_VALUE(Second, physicsTime, "Physics", ValueFlag::kAverage | ValueFlag::kSeconds)
-
-ANKI_STATS_UI_BEGIN_GROUP("GPU")
-ANKI_STATS_UI_VALUE(Second, gpuFrameTime, "Total frame", ValueFlag::kAverage | ValueFlag::kSeconds)
-ANKI_STATS_UI_VALUE(U64, gpuActiveCycles, "GPU cycles", ValueFlag::kAverage)
-ANKI_STATS_UI_VALUE(U64, gpuReadBandwidth, "Read bandwidth", ValueFlag::kAverage | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(U64, gpuWriteBandwidth, "Write bandwidth", ValueFlag::kAverage | ValueFlag::kBytes)
-
-ANKI_STATS_UI_BEGIN_GROUP("CPU memory")
-ANKI_STATS_UI_VALUE(PtrSize, cpuAllocatedMemory, "Total", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(PtrSize, cpuAllocationCount, "Number of allocations", ValueFlag::kNone)
-ANKI_STATS_UI_VALUE(PtrSize, cpuFreeCount, "Number of frees", ValueFlag::kNone)
-
-ANKI_STATS_UI_BEGIN_GROUP("GPU memory")
-ANKI_STATS_UI_VALUE(PtrSize, gpuDeviceMemoryAllocated, "Really allocated", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(PtrSize, gpuDeviceMemoryInUse, "Used", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(PtrSize, unifiedGeometryAllocated, "Unified geom allocated", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(PtrSize, unifiedGeometryTotal, "Unified geom total", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(F32, unifiedGometryExternalFragmentation, "Unified geom ext fragmentation", ValueFlag::kNone)
-ANKI_STATS_UI_VALUE(PtrSize, gpuSceneAllocated, "GPU scene allocated", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(PtrSize, gpuSceneTotal, "GPU scene total", ValueFlag::kNone | ValueFlag::kBytes)
-ANKI_STATS_UI_VALUE(F32, gpuSceneExternalFragmentation, "GPU scene ext fragmentation", ValueFlag::kNone)
-ANKI_STATS_UI_VALUE(PtrSize, reBar, "ReBAR", ValueFlag::kBytes)
-
-ANKI_STATS_UI_BEGIN_GROUP("Other")
-ANKI_STATS_UI_VALUE(U32, drawableCount, "Render queue drawbles", ValueFlag::kNone)
-ANKI_STATS_UI_VALUE(U32, vkCommandBufferCount, "VK command buffers", ValueFlag::kNone)

+ 0 - 136
AnKi/Core/StatsUi.h

@@ -1,136 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Core/Common.h>
-#include <AnKi/Ui/UiImmediateModeBuilder.h>
-#include <AnKi/Util/BuddyAllocatorBuilder.h>
-#include <AnKi/Gr/GrManager.h>
-
-namespace anki {
-
-/// @addtogroup core
-/// @{
-
-/// @memberof StatsUi
-class StatsUiInput
-{
-public:
-#define ANKI_STATS_UI_BEGIN_GROUP(x)
-#define ANKI_STATS_UI_VALUE(type, name, text, flags) type m_##name = {};
-#include <AnKi/Core/StatsUi.defs.h>
-#undef ANKI_STATS_UI_BEGIN_GROUP
-#undef ANKI_STATS_UI_VALUE
-};
-
-/// @memberof StatsUi
-enum class StatsUiDetail : U8
-{
-	kDetailed,
-	kFpsOnly
-};
-
-/// UI for displaying on-screen stats.
-class StatsUi : public UiImmediateModeBuilder
-{
-public:
-	StatsUi() = default;
-
-	~StatsUi();
-
-	Error init();
-
-	void build(CanvasPtr ctx) override;
-
-	void setStats(const StatsUiInput& input, StatsUiDetail detail);
-
-private:
-	static constexpr U32 kBufferedFrames = 16;
-
-	enum class ValueFlag : U8
-	{
-		kNone = 0,
-		kAverage = 1 << 0,
-		kSeconds = 1 << 1,
-		kBytes = 1 << 2,
-	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(ValueFlag)
-
-	class Value
-	{
-	public:
-		union
-		{
-			U64 m_int = 0;
-			F64 m_float;
-			F64 m_avg;
-		};
-
-		F64 m_rollingAvg = 0.0;
-
-		template<typename T, ANKI_ENABLE(std::is_floating_point<T>::value)>
-		void update(T x, ValueFlag flags, Bool flush)
-		{
-			if(!!(flags & ValueFlag::kAverage))
-			{
-				setAverage(x, flush);
-			}
-			else
-			{
-				m_float = x;
-			}
-		}
-
-		template<typename T, ANKI_ENABLE(std::is_integral<T>::value)>
-		void update(T x, ValueFlag flags, Bool flush)
-		{
-			if(!!(flags & ValueFlag::kAverage))
-			{
-				setAverage(F64(x), flush);
-			}
-			else
-			{
-				m_int = x;
-			}
-		}
-
-		void setAverage(F64 x, Bool flush)
-		{
-			m_rollingAvg += x / F64(kBufferedFrames);
-
-			if(flush)
-			{
-				m_avg = m_rollingAvg;
-				m_rollingAvg = 0.0;
-			}
-		}
-	};
-
-#define ANKI_STATS_UI_BEGIN_GROUP(x)
-#define ANKI_STATS_UI_VALUE(type, name, text, flags) Value m_##name;
-#include <AnKi/Core/StatsUi.defs.h>
-#undef ANKI_STATS_UI_BEGIN_GROUP
-#undef ANKI_STATS_UI_VALUE
-
-	FontPtr m_font;
-	U32 m_bufferedFrames = 0;
-	StatsUiDetail m_detail = StatsUiDetail::kDetailed;
-
-	static void labelTime(Second val, CString name)
-	{
-		ImGui::Text("%s: %fms", name.cstr(), val * 1000.0);
-	}
-
-	static void labelUint(U64 val, CString name)
-	{
-		ImGui::Text("%s: %lu", name.cstr(), val);
-	}
-
-	void labelBytes(PtrSize val, CString name) const;
-};
-/// @}
-
-} // end namespace anki

+ 30 - 8
AnKi/Gr/AccelerationStructure.h

@@ -18,12 +18,12 @@ namespace anki {
 class BottomLevelAccelerationStructureInitInfo
 class BottomLevelAccelerationStructureInitInfo
 {
 {
 public:
 public:
-	BufferPtr m_indexBuffer;
+	const Buffer* m_indexBuffer = nullptr;
 	PtrSize m_indexBufferOffset = 0;
 	PtrSize m_indexBufferOffset = 0;
 	U32 m_indexCount = 0;
 	U32 m_indexCount = 0;
 	IndexType m_indexType = IndexType::kCount;
 	IndexType m_indexType = IndexType::kCount;
 
 
-	BufferPtr m_positionBuffer;
+	const Buffer* m_positionBuffer = nullptr;
 	PtrSize m_positionBufferOffset = 0;
 	PtrSize m_positionBufferOffset = 0;
 	U32 m_positionStride = 0;
 	U32 m_positionStride = 0;
 	Format m_positionsFormat = Format::kNone;
 	Format m_positionsFormat = Format::kNone;
@@ -31,9 +31,8 @@ public:
 
 
 	Bool isValid() const
 	Bool isValid() const
 	{
 	{
-		if(m_indexBuffer.get() == nullptr || m_indexCount == 0 || m_indexType == IndexType::kCount
-		   || m_positionBuffer.get() == nullptr || m_positionStride == 0 || m_positionsFormat == Format::kNone
-		   || m_positionCount == 0)
+		if(m_indexBuffer == nullptr || m_indexCount == 0 || m_indexType == IndexType::kCount || m_positionBuffer == nullptr || m_positionStride == 0
+		   || m_positionsFormat == Format::kNone || m_positionCount == 0)
 		{
 		{
 			return false;
 			return false;
 		}
 		}
@@ -61,7 +60,7 @@ public:
 };
 };
 
 
 /// @memberof AccelerationStructureInitInfo
 /// @memberof AccelerationStructureInitInfo
-class AccelerationStructureInstance
+class AccelerationStructureInstanceInfo
 {
 {
 public:
 public:
 	AccelerationStructurePtr m_bottomLevel;
 	AccelerationStructurePtr m_bottomLevel;
@@ -74,11 +73,24 @@ public:
 class TopLevelAccelerationStructureInitInfo
 class TopLevelAccelerationStructureInitInfo
 {
 {
 public:
 public:
-	ConstWeakArray<AccelerationStructureInstance> m_instances;
+	class
+	{
+	public:
+		ConstWeakArray<AccelerationStructureInstanceInfo> m_instances;
+	} m_directArgs; ///< Pass some representation of the instances.
+
+	class
+	{
+	public:
+		U32 m_maxInstanceCount = 0;
+		Buffer* m_instancesBuffer = nullptr;
+		PtrSize m_instancesBufferOffset = kMaxPtrSize;
+	} m_indirectArgs; ///< Pass the instances GPU buffer directly.
 
 
 	Bool isValid() const
 	Bool isValid() const
 	{
 	{
-		return m_instances.getSize() > 0;
+		return m_directArgs.m_instances.getSize() > 0
+			   || (m_indirectArgs.m_maxInstanceCount > 0 && m_indirectArgs.m_instancesBuffer && m_indirectArgs.m_instancesBufferOffset < kMaxPtrSize);
 	}
 	}
 };
 };
 
 
@@ -121,7 +133,17 @@ public:
 		return m_type;
 		return m_type;
 	}
 	}
 
 
+	/// Get the size of the scratch buffer used in building this AS.
+	PtrSize getBuildScratchBufferSize() const
+	{
+		ANKI_ASSERT(m_scratchBufferSize != 0);
+		return m_scratchBufferSize;
+	}
+
+	U64 getGpuAddress() const;
+
 protected:
 protected:
+	PtrSize m_scratchBufferSize = 0;
 	AccelerationStructureType m_type = AccelerationStructureType::kCount;
 	AccelerationStructureType m_type = AccelerationStructureType::kCount;
 
 
 	/// Construct.
 	/// Construct.

+ 0 - 1
AnKi/Gr/CMakeLists.txt

@@ -12,7 +12,6 @@ set(common_headers
 	Buffer.h
 	Buffer.h
 	CommandBuffer.h
 	CommandBuffer.h
 	Common.h
 	Common.h
-	ConfigVars.defs.h
 	Fence.h
 	Fence.h
 	Format.defs.h
 	Format.defs.h
 	Framebuffer.h
 	Framebuffer.h

+ 77 - 54
AnKi/Gr/CommandBuffer.h

@@ -32,7 +32,7 @@ public:
 	BufferUsageBit m_previousUsage = BufferUsageBit::kNone;
 	BufferUsageBit m_previousUsage = BufferUsageBit::kNone;
 	BufferUsageBit m_nextUsage = BufferUsageBit::kNone;
 	BufferUsageBit m_nextUsage = BufferUsageBit::kNone;
 	PtrSize m_offset = 0;
 	PtrSize m_offset = 0;
-	PtrSize m_size = 0;
+	PtrSize m_range = 0;
 };
 };
 
 
 class AccelerationStructureBarrierInfo
 class AccelerationStructureBarrierInfo
@@ -73,11 +73,11 @@ ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CommandBufferFlag)
 class CommandBufferInitInfo : public GrBaseInitInfo
 class CommandBufferInitInfo : public GrBaseInitInfo
 {
 {
 public:
 public:
-	FramebufferPtr m_framebuffer; ///< For second level command buffers.
+	Framebuffer* m_framebuffer = nullptr; ///< For second level command buffers.
 	Array<TextureUsageBit, kMaxColorRenderTargets> m_colorAttachmentUsages = {};
 	Array<TextureUsageBit, kMaxColorRenderTargets> m_colorAttachmentUsages = {};
 	TextureUsageBit m_depthStencilAttachmentUsage = TextureUsageBit::kNone;
 	TextureUsageBit m_depthStencilAttachmentUsage = TextureUsageBit::kNone;
 
 
-	CommandBufferFlag m_flags = CommandBufferFlag::kNone;
+	CommandBufferFlag m_flags = CommandBufferFlag::kGeneralWork;
 
 
 	CommandBufferInitInfo(CString name = {})
 	CommandBufferInitInfo(CString name = {})
 		: GrBaseInitInfo(name)
 		: GrBaseInitInfo(name)
@@ -102,14 +102,13 @@ public:
 	/// @{
 	/// @{
 
 
 	/// Bind vertex buffer.
 	/// Bind vertex buffer.
-	void bindVertexBuffer(U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize stride,
-						  VertexStepRate stepRate = VertexStepRate::kVertex);
+	void bindVertexBuffer(U32 binding, Buffer* buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate = VertexStepRate::kVertex);
 
 
 	/// Setup a vertex attribute.
 	/// Setup a vertex attribute.
 	void setVertexAttribute(U32 location, U32 buffBinding, Format fmt, PtrSize relativeOffset);
 	void setVertexAttribute(U32 location, U32 buffBinding, Format fmt, PtrSize relativeOffset);
 
 
 	/// Bind index buffer.
 	/// Bind index buffer.
-	void bindIndexBuffer(const BufferPtr& buff, PtrSize offset, IndexType type);
+	void bindIndexBuffer(Buffer* buff, PtrSize offset, IndexType type);
 
 
 	/// Enable primitive restart.
 	/// Enable primitive restart.
 	void setPrimitiveRestart(Bool enable);
 	void setPrimitiveRestart(Bool enable);
@@ -131,8 +130,8 @@ public:
 	void setPolygonOffset(F32 factor, F32 units);
 	void setPolygonOffset(F32 factor, F32 units);
 
 
 	/// Set stencil operations. To disable stencil test put StencilOperation::KEEP to all operations.
 	/// Set stencil operations. To disable stencil test put StencilOperation::KEEP to all operations.
-	void setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail,
-							  StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass);
+	void setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
+							  StencilOperation stencilPassDepthPass);
 
 
 	/// Set stencil compare operation.
 	/// Set stencil compare operation.
 	void setStencilCompareOperation(FaceSelectionBit face, CompareOperation comp);
 	void setStencilCompareOperation(FaceSelectionBit face, CompareOperation comp);
@@ -192,22 +191,21 @@ public:
 	/// @param texView The texture view to bind.
 	/// @param texView The texture view to bind.
 	/// @param sampler The sampler to override the default sampler of the tex.
 	/// @param sampler The sampler to override the default sampler of the tex.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindTextureAndSampler(U32 set, U32 binding, const TextureViewPtr& texView, const SamplerPtr& sampler,
-							   U32 arrayIdx = 0);
+	void bindTextureAndSampler(U32 set, U32 binding, TextureView* texView, Sampler* sampler, U32 arrayIdx = 0);
 
 
 	/// Bind sampler.
 	/// Bind sampler.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
 	/// @param binding The binding to bind to.
 	/// @param binding The binding to bind to.
 	/// @param sampler The sampler to override the default sampler of the tex.
 	/// @param sampler The sampler to override the default sampler of the tex.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindSampler(U32 set, U32 binding, const SamplerPtr& sampler, U32 arrayIdx = 0);
+	void bindSampler(U32 set, U32 binding, Sampler* sampler, U32 arrayIdx = 0);
 
 
 	/// Bind a texture.
 	/// Bind a texture.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
 	/// @param binding The binding to bind to.
 	/// @param binding The binding to bind to.
 	/// @param texView The texture view to bind.
 	/// @param texView The texture view to bind.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindTexture(U32 set, U32 binding, const TextureViewPtr& texView, U32 arrayIdx = 0);
+	void bindTexture(U32 set, U32 binding, TextureView* texView, U32 arrayIdx = 0);
 
 
 	/// Bind uniform buffer.
 	/// Bind uniform buffer.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
@@ -217,8 +215,17 @@ public:
 	/// @param range The bytes to bind starting from the offset. If it's kMaxPtrSize then map from offset to the end
 	/// @param range The bytes to bind starting from the offset. If it's kMaxPtrSize then map from offset to the end
 	///              of the buffer.
 	///              of the buffer.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindUniformBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-						   U32 arrayIdx = 0);
+	void bindUniformBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx = 0);
+
+	/// Bind uniform buffer.
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param[in,out] buff The buffer to bind.
+	/// @param arrayIdx The array index if the binding is an array.
+	void bindUniformBuffer(U32 set, U32 binding, const BufferOffsetRange& buff, U32 arrayIdx = 0)
+	{
+		bindUniformBuffer(set, binding, buff.m_buffer, buff.m_offset, buff.m_range, arrayIdx);
+	}
 
 
 	/// Bind storage buffer.
 	/// Bind storage buffer.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
@@ -228,15 +235,24 @@ public:
 	/// @param range The bytes to bind starting from the offset. If it's kMaxPtrSize then map from offset to the end
 	/// @param range The bytes to bind starting from the offset. If it's kMaxPtrSize then map from offset to the end
 	///              of the buffer.
 	///              of the buffer.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindStorageBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-						   U32 arrayIdx = 0);
+	void bindStorageBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx = 0);
+
+	/// Bind storage buffer.
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param[in,out] buff The buffer to bind.
+	/// @param arrayIdx The array index if the binding is an array.
+	void bindStorageBuffer(U32 set, U32 binding, const BufferOffsetRange& buff, U32 arrayIdx = 0)
+	{
+		bindStorageBuffer(set, binding, buff.m_buffer, buff.m_offset, buff.m_range, arrayIdx);
+	}
 
 
 	/// Bind load/store image.
 	/// Bind load/store image.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
 	/// @param binding The binding to bind to.
 	/// @param binding The binding to bind to.
 	/// @param img The view to bind.
 	/// @param img The view to bind.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindImage(U32 set, U32 binding, const TextureViewPtr& img, U32 arrayIdx = 0);
+	void bindImage(U32 set, U32 binding, TextureView* img, U32 arrayIdx = 0);
 
 
 	/// Bind texture buffer.
 	/// Bind texture buffer.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
@@ -247,15 +263,14 @@ public:
 	///              of the buffer.
 	///              of the buffer.
 	/// @param fmt The format of the buffer.
 	/// @param fmt The format of the buffer.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindReadOnlyTextureBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-								   Format fmt, U32 arrayIdx = 0);
+	void bindReadOnlyTextureBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, Format fmt, U32 arrayIdx = 0);
 
 
 	/// Bind an acceleration structure.
 	/// Bind an acceleration structure.
 	/// @param set The set to bind to.
 	/// @param set The set to bind to.
 	/// @param binding The binding to bind to.
 	/// @param binding The binding to bind to.
 	/// @param[in,out] as The AS to bind.
 	/// @param[in,out] as The AS to bind.
 	/// @param arrayIdx The array index if the binding is an array.
 	/// @param arrayIdx The array index if the binding is an array.
-	void bindAccelerationStructure(U32 set, U32 binding, const AccelerationStructurePtr& as, U32 arrayIdx = 0);
+	void bindAccelerationStructure(U32 set, U32 binding, AccelerationStructure* as, U32 arrayIdx = 0);
 
 
 	/// Bind the bindless descriptor set into a slot.
 	/// Bind the bindless descriptor set into a slot.
 	void bindAllBindless(U32 set);
 	void bindAllBindless(U32 set);
@@ -264,15 +279,13 @@ public:
 	void setPushConstants(const void* data, U32 dataSize);
 	void setPushConstants(const void* data, U32 dataSize);
 
 
 	/// Bind a program.
 	/// Bind a program.
-	void bindShaderProgram(const ShaderProgramPtr& prog);
+	void bindShaderProgram(ShaderProgram* prog);
 
 
 	/// Begin renderpass.
 	/// Begin renderpass.
 	/// The minx, miny, width, height control the area that the load and store operations will happen. If the scissor is
 	/// The minx, miny, width, height control the area that the load and store operations will happen. If the scissor is
 	/// bigger than the render area the results are undefined.
 	/// bigger than the render area the results are undefined.
-	void beginRenderPass(const FramebufferPtr& fb,
-						 const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
-						 TextureUsageBit depthStencilAttachmentUsage, U32 minx = 0, U32 miny = 0, U32 width = kMaxU32,
-						 U32 height = kMaxU32);
+	void beginRenderPass(Framebuffer* fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
+						 TextureUsageBit depthStencilAttachmentUsage, U32 minx = 0, U32 miny = 0, U32 width = kMaxU32, U32 height = kMaxU32);
 
 
 	/// End renderpass.
 	/// End renderpass.
 	void endRenderPass();
 	void endRenderPass();
@@ -283,17 +296,24 @@ public:
 
 
 	/// @name Jobs
 	/// @name Jobs
 	/// @{
 	/// @{
-	void drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount = 1, U32 firstIndex = 0,
-					  U32 baseVertex = 0, U32 baseInstance = 0);
+	void drawIndexed(PrimitiveTopology topology, U32 count, U32 instanceCount = 1, U32 firstIndex = 0, U32 baseVertex = 0, U32 baseInstance = 0);
 
 
-	void drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
+	void draw(PrimitiveTopology topology, U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
 
 
-	void drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, const BufferPtr& indirectBuff);
+	void drawIndexedIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* indirectBuff);
 
 
-	void drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, const BufferPtr& indirectBuff);
+	void drawIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* indirectBuff);
+
+	void drawIndexedIndirectCount(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset, U32 argBufferStride, Buffer* countBuffer,
+								  PtrSize countBufferOffset, U32 maxDrawCount);
+
+	void drawIndirectCount(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset, U32 argBufferStride, Buffer* countBuffer,
+						   PtrSize countBufferOffset, U32 maxDrawCount);
 
 
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 
 
+	void dispatchComputeIndirect(Buffer* argBuffer, PtrSize argBufferOffset);
+
 	/// Trace rays.
 	/// Trace rays.
 	///
 	///
 	/// The 1st thing in the sbtBuffer is the ray gen shader group handle:
 	/// The 1st thing in the sbtBuffer is the ray gen shader group handle:
@@ -310,8 +330,7 @@ public:
 	/// @code HG = HG_offset + (HG_stride * (R_offset + R_stride * G_id + I_offset)) @endcode
 	/// @code HG = HG_offset + (HG_stride * (R_offset + R_stride * G_id + I_offset)) @endcode
 	/// The HG_offset is equal to sbtBufferOffset + GpuDeviceCapabilities::m_sbtRecordSize * (missShaderCount + 1).
 	/// The HG_offset is equal to sbtBufferOffset + GpuDeviceCapabilities::m_sbtRecordSize * (missShaderCount + 1).
 	/// The HG_stride is equal GpuDeviceCapabilities::m_sbtRecordSize * rayTypecount.
 	/// The HG_stride is equal GpuDeviceCapabilities::m_sbtRecordSize * rayTypecount.
-	/// The R_offset and R_stride are provided in traceRayEXT. The R_offset is the "ray type" and R_stride the number of
-	/// ray types.
+	/// The R_offset and R_stride are provided in traceRayEXT. The R_offset is the "ray type" and R_stride the number of ray types.
 	/// The G_id is always 0 ATM.
 	/// The G_id is always 0 ATM.
 	/// The I_offset is the AccelerationStructureInstance::m_hitgroupSbtRecordIndex.
 	/// The I_offset is the AccelerationStructureInstance::m_hitgroupSbtRecordIndex.
 	///
 	///
@@ -323,49 +342,48 @@ public:
 	/// @param width Width.
 	/// @param width Width.
 	/// @param height Height.
 	/// @param height Height.
 	/// @param depth Depth.
 	/// @param depth Depth.
-	void traceRays(const BufferPtr& sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize, U32 hitGroupSbtRecordCount,
-				   U32 rayTypeCount, U32 width, U32 height, U32 depth);
+	void traceRays(Buffer* sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize, U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width, U32 height,
+				   U32 depth);
 
 
 	/// Generate mipmaps for non-3D textures. You have to transition all the mip levels of this face and layer to
 	/// Generate mipmaps for non-3D textures. You have to transition all the mip levels of this face and layer to
 	/// TextureUsageBit::kGenerateMipmaps before calling this method.
 	/// TextureUsageBit::kGenerateMipmaps before calling this method.
 	/// @param texView The texture view to generate mips. It should point to a subresource that contains the whole
 	/// @param texView The texture view to generate mips. It should point to a subresource that contains the whole
 	///                mip chain and only one face and one layer.
 	///                mip chain and only one face and one layer.
-	void generateMipmaps2d(const TextureViewPtr& texView);
+	void generateMipmaps2d(TextureView* texView);
 
 
 	/// Generate mipmaps only for 3D textures.
 	/// Generate mipmaps only for 3D textures.
 	/// @param texView The texture view to generate mips.
 	/// @param texView The texture view to generate mips.
-	void generateMipmaps3d(const TextureViewPtr& tex);
+	void generateMipmaps3d(TextureView* tex);
 
 
 	/// Blit from surface to surface.
 	/// Blit from surface to surface.
 	/// @param srcView The source view that points to a surface.
 	/// @param srcView The source view that points to a surface.
 	/// @param dstView The destination view that points to a surface.
 	/// @param dstView The destination view that points to a surface.
-	void blitTextureViews(const TextureViewPtr& srcView, const TextureViewPtr& destView);
+	void blitTextureViews(TextureView* srcView, TextureView* destView);
 
 
 	/// Clear a single texture surface. Can be used for all textures except 3D.
 	/// Clear a single texture surface. Can be used for all textures except 3D.
 	/// @param[in,out] texView The texture view to clear.
 	/// @param[in,out] texView The texture view to clear.
 	/// @param[in] clearValue The value to clear it with.
 	/// @param[in] clearValue The value to clear it with.
-	void clearTextureView(const TextureViewPtr& texView, const ClearValue& clearValue);
+	void clearTextureView(TextureView* texView, const ClearValue& clearValue);
 
 
 	/// Copy a buffer to a texture surface or volume.
 	/// Copy a buffer to a texture surface or volume.
 	/// @param buff The source buffer to copy from.
 	/// @param buff The source buffer to copy from.
 	/// @param offset The offset in the buffer to start reading from.
 	/// @param offset The offset in the buffer to start reading from.
 	/// @param range The size of the buffer to read.
 	/// @param range The size of the buffer to read.
 	/// @param texView The texture view that points to a surface or volume to write to.
 	/// @param texView The texture view that points to a surface or volume to write to.
-	void copyBufferToTextureView(const BufferPtr& buff, PtrSize offset, PtrSize range, const TextureViewPtr& texView);
+	void copyBufferToTextureView(Buffer* buff, PtrSize offset, PtrSize range, TextureView* texView);
 
 
 	/// Fill a buffer with some value.
 	/// Fill a buffer with some value.
 	/// @param[in,out] buff The buffer to fill.
 	/// @param[in,out] buff The buffer to fill.
 	/// @param offset From where to start filling. Must be multiple of 4.
 	/// @param offset From where to start filling. Must be multiple of 4.
 	/// @param size The bytes to fill. Must be multiple of 4 or kMaxPtrSize to indicate the whole buffer.
 	/// @param size The bytes to fill. Must be multiple of 4 or kMaxPtrSize to indicate the whole buffer.
 	/// @param value The value to fill the buffer with.
 	/// @param value The value to fill the buffer with.
-	void fillBuffer(const BufferPtr& buff, PtrSize offset, PtrSize size, U32 value);
+	void fillBuffer(Buffer* buff, PtrSize offset, PtrSize size, U32 value);
 
 
 	/// Write the occlusion result to buffer.
 	/// Write the occlusion result to buffer.
 	/// @param[in] queries The queries to write the result of.
 	/// @param[in] queries The queries to write the result of.
 	/// @param offset The offset inside the buffer to write the result.
 	/// @param offset The offset inside the buffer to write the result.
 	/// @param buff The buffer to update.
 	/// @param buff The buffer to update.
-	void writeOcclusionQueriesResultToBuffer(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset,
-											 const BufferPtr& buff);
+	void writeOcclusionQueriesResultToBuffer(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset, Buffer* buff);
 
 
 	/// Copy buffer to buffer.
 	/// Copy buffer to buffer.
 	/// @param[in] src Source buffer.
 	/// @param[in] src Source buffer.
@@ -373,8 +391,7 @@ public:
 	/// @param[out] dst Destination buffer.
 	/// @param[out] dst Destination buffer.
 	/// @param dstOffset Offset in the destination buffer.
 	/// @param dstOffset Offset in the destination buffer.
 	/// @param range Size to copy.
 	/// @param range Size to copy.
-	void copyBufferToBuffer(const BufferPtr& src, PtrSize srcOffset, const BufferPtr& dst, PtrSize dstOffset,
-							PtrSize range)
+	void copyBufferToBuffer(Buffer* src, PtrSize srcOffset, Buffer* dst, PtrSize dstOffset, PtrSize range)
 	{
 	{
 		Array<CopyBufferToBufferInfo, 1> copies = {{{srcOffset, dstOffset, range}}};
 		Array<CopyBufferToBufferInfo, 1> copies = {{{srcOffset, dstOffset, range}}};
 		copyBufferToBuffer(src, dst, copies);
 		copyBufferToBuffer(src, dst, copies);
@@ -384,10 +401,13 @@ public:
 	/// @param[in] src Source buffer.
 	/// @param[in] src Source buffer.
 	/// @param[out] dst Destination buffer.
 	/// @param[out] dst Destination buffer.
 	/// @param copies Info on the copies.
 	/// @param copies Info on the copies.
-	void copyBufferToBuffer(const BufferPtr& src, const BufferPtr& dst, ConstWeakArray<CopyBufferToBufferInfo> copies);
+	void copyBufferToBuffer(Buffer* src, Buffer* dst, ConstWeakArray<CopyBufferToBufferInfo> copies);
 
 
 	/// Build the acceleration structure.
 	/// Build the acceleration structure.
-	void buildAccelerationStructure(const AccelerationStructurePtr& as);
+	/// @param as The AS to build.
+	/// @param scratchBuffer A scratch buffer. Ask the AS for size.
+	/// @param scratchBufferOffset Scratch buffer offset.
+	void buildAccelerationStructure(AccelerationStructure* as, Buffer* scratchBuffer, PtrSize scratchBufferOffset);
 
 
 	/// Do upscaling by an external upscaler
 	/// Do upscaling by an external upscaler
 	/// @param[in] upscaler the upscaler to use for upscaling
 	/// @param[in] upscaler the upscaler to use for upscaling
@@ -398,11 +418,10 @@ public:
 	/// @param[in] exposure 1x1 Texture containing exposure
 	/// @param[in] exposure 1x1 Texture containing exposure
 	/// @param[in] resetAccumulation Whether to clean or not any temporal history
 	/// @param[in] resetAccumulation Whether to clean or not any temporal history
 	/// @param[in] jitterOffset Jittering offset that was applied during the generation of sourceTexture
 	/// @param[in] jitterOffset Jittering offset that was applied during the generation of sourceTexture
-	/// @param[in] motionVectorsScale Any scale factor that might need to be applied to the motionVectorsTexture (i.e UV
-	///                               space to Pixel space conversion)
-	void upscale(const GrUpscalerPtr& upscaler, const TextureViewPtr& inColor, const TextureViewPtr& outUpscaledColor,
-				 const TextureViewPtr& motionVectors, const TextureViewPtr& depth, const TextureViewPtr& exposure,
-				 const Bool resetAccumulation, const Vec2& jitterOffset, const Vec2& motionVectorsScale);
+	/// @param[in] motionVectorsScale Any scale factor that might need to be applied to the motionVectorsTexture (i.e UV space to Pixel space
+	///                               conversion)
+	void upscale(GrUpscaler* upscaler, TextureView* inColor, TextureView* outUpscaledColor, TextureView* motionVectors, TextureView* depth,
+				 TextureView* exposure, Bool resetAccumulation, const Vec2& jitterOffset, const Vec2& motionVectorsScale);
 	/// @}
 	/// @}
 
 
 	/// @name Sync
 	/// @name Sync
@@ -418,21 +437,25 @@ public:
 	void resetOcclusionQueries(ConstWeakArray<OcclusionQuery*> queries);
 	void resetOcclusionQueries(ConstWeakArray<OcclusionQuery*> queries);
 
 
 	/// Begin query.
 	/// Begin query.
-	void beginOcclusionQuery(const OcclusionQueryPtr& query);
+	void beginOcclusionQuery(OcclusionQuery* query);
 
 
 	/// End query.
 	/// End query.
-	void endOcclusionQuery(const OcclusionQueryPtr& query);
+	void endOcclusionQuery(OcclusionQuery* query);
 
 
 	/// Reset timestamp queries before writeTimestamp.
 	/// Reset timestamp queries before writeTimestamp.
 	void resetTimestampQueries(ConstWeakArray<TimestampQuery*> queries);
 	void resetTimestampQueries(ConstWeakArray<TimestampQuery*> queries);
 
 
 	/// Write a timestamp.
 	/// Write a timestamp.
-	void writeTimestamp(const TimestampQueryPtr& query);
+	void writeTimestamp(TimestampQuery* query);
 
 
 	/// Append second level command buffers.
 	/// Append second level command buffers.
 	void pushSecondLevelCommandBuffers(ConstWeakArray<CommandBuffer*> cmdbs);
 	void pushSecondLevelCommandBuffers(ConstWeakArray<CommandBuffer*> cmdbs);
 
 
 	Bool isEmpty() const;
 	Bool isEmpty() const;
+
+	void pushDebugMarker(CString name, Vec3 color);
+
+	void popDebugMarker();
 	/// @}
 	/// @}
 
 
 protected:
 protected:

+ 3 - 11
AnKi/Gr/Common.cpp

@@ -11,8 +11,7 @@ namespace anki {
 
 
 /// @warning Don't use Array because the compilers can't handle it for some reason.
 /// @warning Don't use Array because the compilers can't handle it for some reason.
 inline constexpr ShaderVariableDataTypeInfo kShaderVariableDataTypeInfos[] = {
 inline constexpr ShaderVariableDataTypeInfo kShaderVariableDataTypeInfos[] = {
-#define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
-	{ANKI_STRINGIZE(type), sizeof(type), false, isIntagralType},
+#define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) {ANKI_STRINGIZE(type), sizeof(type), false, isIntagralType},
 #define ANKI_SVDT_MACRO_OPAQUE(constant, type) {ANKI_STRINGIZE(type), kMaxU32, true, false},
 #define ANKI_SVDT_MACRO_OPAQUE(constant, type) {ANKI_STRINGIZE(type), kMaxU32, true, false},
 #include <AnKi/Gr/ShaderVariableDataType.defs.h>
 #include <AnKi/Gr/ShaderVariableDataType.defs.h>
 #undef ANKI_SVDT_MACRO
 #undef ANKI_SVDT_MACRO
@@ -35,16 +34,9 @@ FormatInfo getFormatInfo(Format fmt)
 	FormatInfo out = {};
 	FormatInfo out = {};
 	switch(fmt)
 	switch(fmt)
 	{
 	{
-#define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, \
-						depthStencil) \
+#define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, depthStencil) \
 	case Format::k##type: \
 	case Format::k##type: \
-		out = {componentCount, \
-			   texelSize, \
-			   blockWidth, \
-			   blockHeight, \
-			   blockSize, \
-			   shaderType, \
-			   DepthStencilAspectBit::k##depthStencil, \
+		out = {componentCount,      texelSize, blockWidth, blockHeight, blockSize, shaderType, DepthStencilAspectBit::k##depthStencil, \
 			   ANKI_STRINGIZE(type)}; \
 			   ANKI_STRINGIZE(type)}; \
 		break;
 		break;
 #include <AnKi/Gr/Format.defs.h>
 #include <AnKi/Gr/Format.defs.h>

+ 48 - 44
AnKi/Gr/Common.h

@@ -61,7 +61,7 @@ constexpr U32 kMaxColorRenderTargets = 4;
 constexpr U32 kMaxDescriptorSets = 3; ///< Groups that can be bound at the same time.
 constexpr U32 kMaxDescriptorSets = 3; ///< Groups that can be bound at the same time.
 constexpr U32 kMaxBindingsPerDescriptorSet = 32;
 constexpr U32 kMaxBindingsPerDescriptorSet = 32;
 constexpr U32 kMaxFramesInFlight = 3; ///< Triple buffering.
 constexpr U32 kMaxFramesInFlight = 3; ///< Triple buffering.
-constexpr U32 kMaxGrObjectNameLength = 31;
+constexpr U32 kMaxGrObjectNameLength = 61;
 constexpr U32 kMaxBindlessTextures = 512;
 constexpr U32 kMaxBindlessTextures = 512;
 constexpr U32 kMaxBindlessReadonlyTextureBuffers = 512;
 constexpr U32 kMaxBindlessReadonlyTextureBuffers = 512;
 
 
@@ -136,8 +136,7 @@ enum class GpuVendor : U8
 	kCount
 	kCount
 };
 };
 
 
-inline constexpr Array<CString, U(GpuVendor::kCount)> kGPUVendorStrings = {"unknown", "ARM",   "nVidia",
-																		   "AMD",     "Intel", "Qualcomm"};
+inline constexpr Array<CString, U(GpuVendor::kCount)> kGPUVendorStrings = {"unknown", "ARM", "nVidia", "AMD", "Intel", "Qualcomm"};
 
 
 /// Device capabilities.
 /// Device capabilities.
 ANKI_BEGIN_PACKED_STRUCT
 ANKI_BEGIN_PACKED_STRUCT
@@ -168,6 +167,9 @@ public:
 	/// The max combined size of shared variables (with paddings) in compute shaders.
 	/// The max combined size of shared variables (with paddings) in compute shaders.
 	PtrSize m_computeSharedMemorySize = 16_KB;
 	PtrSize m_computeSharedMemorySize = 16_KB;
 
 
+	/// Alignment of the scratch buffer used in AS building.
+	U32 m_accelerationStructureBuildScratchOffsetAlignment = 0;
+
 	/// Each SBT record should be a multiple of this.
 	/// Each SBT record should be a multiple of this.
 	U32 m_sbtRecordAlignment = kMaxU32;
 	U32 m_sbtRecordAlignment = kMaxU32;
 
 
@@ -183,6 +185,9 @@ public:
 	/// Min size of a texel in the shading rate image.
 	/// Min size of a texel in the shading rate image.
 	U32 m_minShadingRateImageTexelSize = 0;
 	U32 m_minShadingRateImageTexelSize = 0;
 
 
+	/// The max number of drawcalls in draw indirect count calls.
+	U32 m_maxDrawIndirectCount = 0;
+
 	/// GPU vendor.
 	/// GPU vendor.
 	GpuVendor m_gpuVendor = GpuVendor::kUnknown;
 	GpuVendor m_gpuVendor = GpuVendor::kUnknown;
 
 
@@ -389,9 +394,7 @@ enum class Format : U32
 {
 {
 	kNone = 0,
 	kNone = 0,
 
 
-#define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, \
-						depthStencil) \
-	k##type = id,
+#define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, depthStencil) k##type = id,
 #include <AnKi/Gr/Format.defs.h>
 #include <AnKi/Gr/Format.defs.h>
 #undef ANKI_FORMAT_DEF
 #undef ANKI_FORMAT_DEF
 };
 };
@@ -487,19 +490,19 @@ enum class TextureUsageBit : U32
 
 
 	// Derived
 	// Derived
 	kAllSampled = kSampledGeometry | kSampledFragment | kSampledCompute | kSampledTraceRays,
 	kAllSampled = kSampledGeometry | kSampledFragment | kSampledCompute | kSampledTraceRays,
-	kAllImage = kImageGeometryRead | kImageGeometryWrite | kImageFragmentRead | kImageFragmentWrite | kImageComputeRead
-				| kImageComputeWrite | kImageTraceRaysRead | kImageTraceRaysWrite,
+	kAllImage = kImageGeometryRead | kImageGeometryWrite | kImageFragmentRead | kImageFragmentWrite | kImageComputeRead | kImageComputeWrite
+				| kImageTraceRaysRead | kImageTraceRaysWrite,
 	kAllFramebuffer = kFramebufferRead | kFramebufferWrite,
 	kAllFramebuffer = kFramebufferRead | kFramebufferWrite,
 
 
-	kAllGraphics = kSampledGeometry | kSampledFragment | kImageGeometryRead | kImageGeometryWrite | kImageFragmentRead
-				   | kImageFragmentWrite | kFramebufferRead | kFramebufferWrite | kFramebufferShadingRate,
+	kAllGraphics = kSampledGeometry | kSampledFragment | kImageGeometryRead | kImageGeometryWrite | kImageFragmentRead | kImageFragmentWrite
+				   | kFramebufferRead | kFramebufferWrite | kFramebufferShadingRate,
 	kAllCompute = kSampledCompute | kImageComputeRead | kImageComputeWrite,
 	kAllCompute = kSampledCompute | kImageComputeRead | kImageComputeWrite,
 	kAllTransfer = kTransferDestination | kGenerateMipmaps,
 	kAllTransfer = kTransferDestination | kGenerateMipmaps,
 
 
-	kAllRead = kAllSampled | kImageGeometryRead | kImageFragmentRead | kImageComputeRead | kImageTraceRaysRead
-			   | kFramebufferRead | kFramebufferShadingRate | kPresent | kGenerateMipmaps,
-	kAllWrite = kImageGeometryWrite | kImageFragmentWrite | kImageComputeWrite | kImageTraceRaysWrite
-				| kFramebufferWrite | kTransferDestination | kGenerateMipmaps,
+	kAllRead = kAllSampled | kImageGeometryRead | kImageFragmentRead | kImageComputeRead | kImageTraceRaysRead | kFramebufferRead
+			   | kFramebufferShadingRate | kPresent | kGenerateMipmaps,
+	kAllWrite = kImageGeometryWrite | kImageFragmentWrite | kImageComputeWrite | kImageTraceRaysWrite | kFramebufferWrite | kTransferDestination
+				| kGenerateMipmaps,
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit)
 
 
@@ -658,8 +661,7 @@ enum class AttachmentStoreOperation : U8
 };
 };
 
 
 /// Buffer usage modes.
 /// Buffer usage modes.
-/// The graphics work consists of the following pipes: indirect, geometry (all programmable and fixed function geometry
-/// stages) and finaly fragment.
+/// The graphics work consists of the following pipes: indirect, geometry (all programmable and fixed function geometry stages) and finaly fragment.
 /// The compute from the consists of the following: indirect and compute.
 /// The compute from the consists of the following: indirect and compute.
 /// The trace rays from the: indirect and trace_rays
 /// The trace rays from the: indirect and trace_rays
 /// !!WARNING!! If you change this remember to change PrivateBufferUsageBit.
 /// !!WARNING!! If you change this remember to change PrivateBufferUsageBit.
@@ -702,34 +704,30 @@ enum class BufferUsageBit : U64
 
 
 	kAccelerationStructureBuild = 1ull << 27ull, ///< Will be used as a position or index buffer in a BLAS build.
 	kAccelerationStructureBuild = 1ull << 27ull, ///< Will be used as a position or index buffer in a BLAS build.
 	kShaderBindingTable = 1ull << 28ull, ///< Will be used as SBT in a traceRays() command.
 	kShaderBindingTable = 1ull << 28ull, ///< Will be used as SBT in a traceRays() command.
+	kAccelerationStructureBuildScratch = 1ull << 29ull, ///< Used in buildAccelerationStructureXXX commands.
 
 
 	// Derived
 	// Derived
 	kAllUniform = kUniformGeometry | kUniformFragment | kUniformCompute | kUniformTraceRays,
 	kAllUniform = kUniformGeometry | kUniformFragment | kUniformCompute | kUniformTraceRays,
-	kAllStorage = kStorageGeometryRead | kStorageGeometryWrite | kStorageFragmentRead | kStorageFragmentWrite
-				  | kStorageComputeRead | kStorageComputeWrite | kStorageTraceRaysRead | kStorageTraceRaysWrite,
-	kAllTexture = kTextureGeometryRead | kTextureGeometryWrite | kTextureFragmentRead | kTextureFragmentWrite
-				  | kTextureComputeRead | kTextureComputeWrite | kTextureTraceRaysRead | kTextureTraceRaysWrite,
+	kAllStorage = kStorageGeometryRead | kStorageGeometryWrite | kStorageFragmentRead | kStorageFragmentWrite | kStorageComputeRead
+				  | kStorageComputeWrite | kStorageTraceRaysRead | kStorageTraceRaysWrite,
+	kAllTexture = kTextureGeometryRead | kTextureGeometryWrite | kTextureFragmentRead | kTextureFragmentWrite | kTextureComputeRead
+				  | kTextureComputeWrite | kTextureTraceRaysRead | kTextureTraceRaysWrite,
 	kAllIndirect = kIndirectCompute | kIndirectDraw | kIndirectTraceRays,
 	kAllIndirect = kIndirectCompute | kIndirectDraw | kIndirectTraceRays,
 	kAllTransfer = kTransferSource | kTransferDestination,
 	kAllTransfer = kTransferSource | kTransferDestination,
 
 
-	kAllGeometry = kUniformGeometry | kStorageGeometryRead | kStorageGeometryWrite | kTextureGeometryRead
-				   | kTextureGeometryWrite | kIndex | kVertex,
-	kAllFragment =
-		kUniformFragment | kStorageFragmentRead | kStorageFragmentWrite | kTextureFragmentRead | kTextureFragmentWrite,
+	kAllGeometry = kUniformGeometry | kStorageGeometryRead | kStorageGeometryWrite | kTextureGeometryRead | kTextureGeometryWrite | kIndex | kVertex,
+	kAllFragment = kUniformFragment | kStorageFragmentRead | kStorageFragmentWrite | kTextureFragmentRead | kTextureFragmentWrite,
 	kAllGraphics = kAllGeometry | kAllFragment | kIndirectDraw,
 	kAllGraphics = kAllGeometry | kAllFragment | kIndirectDraw,
-	kAllCompute = kUniformCompute | kStorageComputeRead | kStorageComputeWrite | kTextureComputeRead
-				  | kTextureComputeWrite | kIndirectCompute,
-	kAllTraceRays = kUniformTraceRays | kStorageTraceRaysRead | kStorageTraceRaysWrite | kTextureTraceRaysRead
-					| kTextureTraceRaysWrite | kIndirectTraceRays | kShaderBindingTable,
-
-	kAllRayTracing = kAllTraceRays | kAccelerationStructureBuild,
-	kAllRead = kAllUniform | kStorageGeometryRead | kStorageFragmentRead | kStorageComputeRead | kStorageTraceRaysRead
-			   | kTextureGeometryRead | kTextureFragmentRead | kTextureComputeRead | kTextureTraceRaysRead | kIndex
-			   | kVertex | kIndirectCompute | kIndirectDraw | kIndirectTraceRays | kTransferSource
-			   | kAccelerationStructureBuild | kShaderBindingTable,
-	kAllWrite = kStorageGeometryWrite | kStorageFragmentWrite | kStorageComputeWrite | kStorageTraceRaysWrite
-				| kTextureGeometryWrite | kTextureFragmentWrite | kTextureComputeWrite | kTextureTraceRaysWrite
-				| kTransferDestination,
+	kAllCompute = kUniformCompute | kStorageComputeRead | kStorageComputeWrite | kTextureComputeRead | kTextureComputeWrite | kIndirectCompute,
+	kAllTraceRays = kUniformTraceRays | kStorageTraceRaysRead | kStorageTraceRaysWrite | kTextureTraceRaysRead | kTextureTraceRaysWrite
+					| kIndirectTraceRays | kShaderBindingTable,
+
+	kAllRayTracing = kAllTraceRays | kAccelerationStructureBuild | kAccelerationStructureBuildScratch,
+	kAllRead = kAllUniform | kStorageGeometryRead | kStorageFragmentRead | kStorageComputeRead | kStorageTraceRaysRead | kTextureGeometryRead
+			   | kTextureFragmentRead | kTextureComputeRead | kTextureTraceRaysRead | kIndex | kVertex | kIndirectCompute | kIndirectDraw
+			   | kIndirectTraceRays | kTransferSource | kAccelerationStructureBuild | kShaderBindingTable,
+	kAllWrite = kStorageGeometryWrite | kStorageFragmentWrite | kStorageComputeWrite | kStorageTraceRaysWrite | kTextureGeometryWrite
+				| kTextureFragmentWrite | kTextureComputeWrite | kTextureTraceRaysWrite | kTransferDestination | kAccelerationStructureBuildScratch,
 	kAll = kAllRead | kAllWrite,
 	kAll = kAllRead | kAllWrite,
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit)
@@ -929,8 +927,7 @@ public:
 
 
 	TextureSubresourceInfo(const TextureSubresourceInfo&) = default;
 	TextureSubresourceInfo(const TextureSubresourceInfo&) = default;
 
 
-	constexpr TextureSubresourceInfo(const TextureSurfaceInfo& surf,
-									 DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
+	constexpr TextureSubresourceInfo(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
 		: m_firstMipmap(surf.m_level)
 		: m_firstMipmap(surf.m_level)
 		, m_mipmapCount(1)
 		, m_mipmapCount(1)
 		, m_firstLayer(surf.m_layer)
 		, m_firstLayer(surf.m_layer)
@@ -941,8 +938,7 @@ public:
 	{
 	{
 	}
 	}
 
 
-	constexpr TextureSubresourceInfo(const TextureVolumeInfo& vol,
-									 DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
+	constexpr TextureSubresourceInfo(const TextureVolumeInfo& vol, DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
 		: m_firstMipmap(vol.m_level)
 		: m_firstMipmap(vol.m_level)
 		, m_mipmapCount(1)
 		, m_mipmapCount(1)
 		, m_firstLayer(0)
 		, m_firstLayer(0)
@@ -979,9 +975,9 @@ public:
 			return (beginA < beginB) ? (beginA + countA > beginB) : (beginB + countB > beginA);
 			return (beginA < beginB) ? (beginA + countA > beginB) : (beginB + countB > beginA);
 		};
 		};
 
 
-		const Bool depthStencilOverlaps = (m_depthStencilAspect == DepthStencilAspectBit::kNone
-										   && b.m_depthStencilAspect == DepthStencilAspectBit::kNone)
-										  || !!(m_depthStencilAspect & b.m_depthStencilAspect);
+		const Bool depthStencilOverlaps =
+			(m_depthStencilAspect == DepthStencilAspectBit::kNone && b.m_depthStencilAspect == DepthStencilAspectBit::kNone)
+			|| !!(m_depthStencilAspect & b.m_depthStencilAspect);
 
 
 		return overlaps(m_firstMipmap, m_mipmapCount, b.m_firstMipmap, b.m_mipmapCount)
 		return overlaps(m_firstMipmap, m_mipmapCount, b.m_firstMipmap, b.m_mipmapCount)
 			   && overlaps(m_firstLayer, m_layerCount, b.m_firstLayer, b.m_layerCount)
 			   && overlaps(m_firstLayer, m_layerCount, b.m_firstLayer, b.m_layerCount)
@@ -989,6 +985,14 @@ public:
 	}
 	}
 };
 };
 
 
+class BufferOffsetRange
+{
+public:
+	Buffer* m_buffer = nullptr;
+	PtrSize m_offset = kMaxPtrSize;
+	PtrSize m_range = 0;
+};
+
 /// Compute max number of mipmaps for a 2D texture.
 /// Compute max number of mipmaps for a 2D texture.
 U32 computeMaxMipmapCount2d(U32 w, U32 h, U32 minSizeOfLastMip = 1);
 U32 computeMaxMipmapCount2d(U32 w, U32 h, U32 minSizeOfLastMip = 1);
 
 

+ 0 - 23
AnKi/Gr/ConfigVars.defs.h

@@ -1,23 +0,0 @@
-// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-ANKI_CONFIG_VAR_GROUP(GR)
-
-ANKI_CONFIG_VAR_BOOL(GrValidation, false, "Enable or not validation")
-ANKI_CONFIG_VAR_BOOL(GrDebugPrintf, false, "Enable or not debug printf")
-ANKI_CONFIG_VAR_BOOL(GrDebugMarkers, false, "Enable or not debug markers")
-ANKI_CONFIG_VAR_BOOL(GrVsync, false, "Enable or not vsync")
-ANKI_CONFIG_VAR_U8(GrDevice, 0, 0, 16, "Choose an available device. Devices are sorted by performance")
-
-ANKI_CONFIG_VAR_PTR_SIZE(GrDiskShaderCacheMaxSize, 128_MB, 1_MB, 1_GB, "Max size of the pipeline cache file")
-
-ANKI_CONFIG_VAR_BOOL(GrRayTracing, false, "Try enabling ray tracing")
-ANKI_CONFIG_VAR_BOOL(Gr64bitAtomics, true, "Enable or not 64bit atomics")
-ANKI_CONFIG_VAR_BOOL(GrSamplerFilterMinMax, true, "Enable or not min/max sample filtering")
-ANKI_CONFIG_VAR_BOOL(GrVrs, false, "Enable or not VRS")
-ANKI_CONFIG_VAR_BOOL(GrAsyncCompute, true, "Enable or not async compute")
-
-ANKI_CONFIG_VAR_U8(GrVkMinor, 1, 1, 1, "Vulkan minor version")
-ANKI_CONFIG_VAR_U8(GrVkMajor, 1, 1, 1, "Vulkan major version")

+ 33 - 60
AnKi/Gr/Gl/CommandBuffer.cpp

@@ -44,14 +44,11 @@ void CommandBuffer::flush(FencePtr* fence)
 
 
 	if(!self.isSecondLevel())
 	if(!self.isSecondLevel())
 	{
 	{
-		static_cast<GrManagerImpl&>(getManager())
-			.getRenderingThread()
-			.flushCommandBuffer(CommandBufferPtr(this), fence);
+		static_cast<GrManagerImpl&>(getManager()).getRenderingThread().flushCommandBuffer(CommandBufferPtr(this), fence);
 	}
 	}
 }
 }
 
 
-void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride,
-									 VertexStepRate stepRate)
+void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -350,8 +347,8 @@ void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 	}
 	}
 }
 }
 
 
-void CommandBuffer::setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail,
-										 StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass)
+void CommandBuffer::setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
+										 StencilOperation stencilPassDepthPass)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -379,8 +376,7 @@ void CommandBuffer::setStencilOperations(FaceSelectionBit face, StencilOperation
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_GL_SELF(CommandBufferImpl);
 	if(self.m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass))
 	if(self.m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass))
 	{
 	{
-		self.pushBackNewCommand<Cmd>(convertFaceMode(face), convertStencilOperation(stencilFail),
-									 convertStencilOperation(stencilPassDepthFail),
+		self.pushBackNewCommand<Cmd>(convertFaceMode(face), convertStencilOperation(stencilFail), convertStencilOperation(stencilPassDepthFail),
 									 convertStencilOperation(stencilPassDepthPass));
 									 convertStencilOperation(stencilPassDepthPass));
 	}
 	}
 }
 }
@@ -540,8 +536,7 @@ void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 	}
 	}
 }
 }
 
 
-void CommandBuffer::setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA,
-									BlendFactor dstA)
+void CommandBuffer::setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -571,8 +566,8 @@ void CommandBuffer::setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFac
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_GL_SELF(CommandBufferImpl);
 	if(self.m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA))
 	if(self.m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA))
 	{
 	{
-		self.pushBackNewCommand<Cmd>(attachment, convertBlendFactor(srcRgb), convertBlendFactor(dstRgb),
-									 convertBlendFactor(srcA), convertBlendFactor(dstA));
+		self.pushBackNewCommand<Cmd>(attachment, convertBlendFactor(srcRgb), convertBlendFactor(dstRgb), convertBlendFactor(srcA),
+									 convertBlendFactor(dstA));
 	}
 	}
 }
 }
 
 
@@ -606,8 +601,7 @@ void CommandBuffer::setBlendOperation(U32 attachment, BlendOperation funcRgb, Bl
 	}
 	}
 }
 }
 
 
-void CommandBuffer::bindTextureAndSampler(U32 set, U32 binding, TextureViewPtr texView, SamplerPtr sampler,
-										  TextureUsageBit usage)
+void CommandBuffer::bindTextureAndSampler(U32 set, U32 binding, TextureViewPtr texView, SamplerPtr sampler, TextureUsageBit usage)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -831,10 +825,8 @@ void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 	}
 	}
 }
 }
 
 
-void CommandBuffer::beginRenderPass(FramebufferPtr fb,
-									const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
-									TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width,
-									U32 height)
+void CommandBuffer::beginRenderPass(FramebufferPtr fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
+									TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height)
 {
 {
 	class BindFramebufferCommand final : public GlCommand
 	class BindFramebufferCommand final : public GlCommand
 	{
 	{
@@ -850,8 +842,7 @@ void CommandBuffer::beginRenderPass(FramebufferPtr fb,
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			static_cast<const FramebufferImpl&>(*m_fb).bind(state, m_renderArea[0], m_renderArea[1], m_renderArea[2],
-															m_renderArea[3]);
+			static_cast<const FramebufferImpl&>(*m_fb).bind(state, m_renderArea[0], m_renderArea[1], m_renderArea[2], m_renderArea[3]);
 			return Error::kNone;
 			return Error::kNone;
 		}
 		}
 	};
 	};
@@ -888,8 +879,7 @@ void CommandBuffer::endRenderPass()
 	self.m_state.endRenderPass();
 	self.m_state.endRenderPass();
 }
 }
 
 
-void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex,
-								 U32 baseVertex, U32 baseInstance)
+void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -907,9 +897,8 @@ void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 inst
 
 
 		Error operator()(GlState&)
 		Error operator()(GlState&)
 		{
 		{
-			glDrawElementsInstancedBaseVertexBaseInstance(
-				m_topology, m_info.m_count, m_indexType, numberToPtr<void*>(m_info.m_firstIndex),
-				m_info.m_instanceCount, m_info.m_baseVertex, m_info.m_baseInstance);
+			glDrawElementsInstancedBaseVertexBaseInstance(m_topology, m_info.m_count, m_indexType, numberToPtr<void*>(m_info.m_firstIndex),
+														  m_info.m_instanceCount, m_info.m_baseVertex, m_info.m_baseInstance);
 
 
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
 			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
 			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
@@ -955,8 +944,7 @@ void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instan
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			glDrawArraysInstancedBaseInstance(m_topology, m_info.m_first, m_info.m_count, m_info.m_instanceCount,
-											  m_info.m_baseInstance);
+			glDrawArraysInstancedBaseInstance(m_topology, m_info.m_first, m_info.m_count, m_info.m_instanceCount, m_info.m_baseInstance);
 
 
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
 			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
 			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
 			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
@@ -973,8 +961,7 @@ void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instan
 	self.pushBackNewCommand<DrawArraysCommand>(convertPrimitiveTopology(topology), info);
 	self.pushBackNewCommand<DrawArraysCommand>(convertPrimitiveTopology(topology), info);
 }
 }
 
 
-void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset,
-										 BufferPtr indirectBuff)
+void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
 {
 {
 	class DrawElementsIndirectCommand final : public GlCommand
 	class DrawElementsIndirectCommand final : public GlCommand
 	{
 	{
@@ -1004,8 +991,7 @@ void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCou
 
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 
 
-			glMultiDrawElementsIndirect(m_topology, m_indexType, numberToPtr<void*>(m_offset), m_drawCount,
-										sizeof(DrawElementsIndirectInfo));
+			glMultiDrawElementsIndirect(m_topology, m_indexType, numberToPtr<void*>(m_offset), m_drawCount, sizeof(DrawElementsIndirectInfo));
 
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
 			return Error::kNone;
 			return Error::kNone;
@@ -1016,12 +1002,11 @@ void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCou
 
 
 	self.m_state.checkIndexedDracall();
 	self.m_state.checkIndexedDracall();
 	self.flushDrawcall(*this);
 	self.flushDrawcall(*this);
-	self.pushBackNewCommand<DrawElementsIndirectCommand>(
-		convertPrimitiveTopology(topology), self.m_state.m_idx.m_indexType, drawCount, offset, indirectBuff);
+	self.pushBackNewCommand<DrawElementsIndirectCommand>(convertPrimitiveTopology(topology), self.m_state.m_idx.m_indexType, drawCount, offset,
+														 indirectBuff);
 }
 }
 
 
-void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset,
-									   BufferPtr indirectBuff)
+void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
 {
 {
 	class DrawArraysIndirectCommand final : public GlCommand
 	class DrawArraysIndirectCommand final : public GlCommand
 	{
 	{
@@ -1049,8 +1034,7 @@ void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount
 
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 
 
-			glMultiDrawArraysIndirect(m_topology, numberToPtr<void*>(m_offset), m_drawCount,
-									  sizeof(DrawArraysIndirectInfo));
+			glMultiDrawArraysIndirect(m_topology, numberToPtr<void*>(m_offset), m_drawCount, sizeof(DrawArraysIndirectInfo));
 
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
 			return Error::kNone;
 			return Error::kNone;
@@ -1060,8 +1044,7 @@ void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_GL_SELF(CommandBufferImpl);
 	self.m_state.checkNonIndexedDrawcall();
 	self.m_state.checkNonIndexedDrawcall();
 	self.flushDrawcall(*this);
 	self.flushDrawcall(*this);
-	self.pushBackNewCommand<DrawArraysIndirectCommand>(convertPrimitiveTopology(topology), drawCount, offset,
-													   indirectBuff);
+	self.pushBackNewCommand<DrawArraysIndirectCommand>(convertPrimitiveTopology(topology), drawCount, offset, indirectBuff);
 }
 }
 
 
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
@@ -1164,8 +1147,7 @@ void CommandBuffer::copyBufferToTextureView(BufferPtr buff, PtrSize offset, PtrS
 			const TextureViewImpl& viewImpl = static_cast<TextureViewImpl&>(*m_texView);
 			const TextureViewImpl& viewImpl = static_cast<TextureViewImpl&>(*m_texView);
 			const TextureImpl& texImpl = static_cast<TextureImpl&>(*viewImpl.m_tex);
 			const TextureImpl& texImpl = static_cast<TextureImpl&>(*viewImpl.m_tex);
 
 
-			texImpl.copyFromBuffer(viewImpl.getSubresource(), static_cast<const BufferImpl&>(*m_buff).getGlName(),
-								   m_offset, m_range);
+			texImpl.copyFromBuffer(viewImpl.getSubresource(), static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
 			return Error::kNone;
 			return Error::kNone;
 		}
 		}
 	};
 	};
@@ -1179,8 +1161,7 @@ void CommandBuffer::copyBufferToTextureView(BufferPtr buff, PtrSize offset, PtrS
 	self.pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, texView);
 	self.pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, texView);
 }
 }
 
 
-void CommandBuffer::copyBufferToBuffer(BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset,
-									   PtrSize range)
+void CommandBuffer::copyBufferToBuffer(BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset, PtrSize range)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -1202,8 +1183,7 @@ void CommandBuffer::copyBufferToBuffer(BufferPtr src, PtrSize srcOffset, BufferP
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			static_cast<BufferImpl&>(*m_dst).write(static_cast<const BufferImpl&>(*m_src).getGlName(), m_srcOffset,
-												   m_dstOffset, m_range);
+			static_cast<BufferImpl&>(*m_dst).write(static_cast<const BufferImpl&>(*m_src).getGlName(), m_srcOffset, m_dstOffset, m_range);
 			return Error::kNone;
 			return Error::kNone;
 		}
 		}
 	};
 	};
@@ -1284,8 +1264,7 @@ void CommandBuffer::blitTextureViews(TextureViewPtr srcView, TextureViewPtr dest
 	ANKI_ASSERT(!"TODO");
 	ANKI_ASSERT(!"TODO");
 }
 }
 
 
-void CommandBuffer::setBufferBarrier(BufferPtr buff, BufferUsageBit prevUsage, BufferUsageBit nextUsage, PtrSize offset,
-									 PtrSize size)
+void CommandBuffer::setBufferBarrier(BufferPtr buff, BufferUsageBit prevUsage, BufferUsageBit nextUsage, PtrSize offset, PtrSize size)
 {
 {
 	class SetBufferMemBarrierCommand final : public GlCommand
 	class SetBufferMemBarrierCommand final : public GlCommand
 	{
 	{
@@ -1332,8 +1311,7 @@ void CommandBuffer::setBufferBarrier(BufferPtr buff, BufferUsageBit prevUsage, B
 		d |= GL_COMMAND_BARRIER_BIT;
 		d |= GL_COMMAND_BARRIER_BIT;
 	}
 	}
 
 
-	if(!!(all
-		  & (BufferUsageBit::FILL | BufferUsageBit::BUFFER_UPLOAD_SOURCE | BufferUsageBit::BUFFER_UPLOAD_DESTINATION)))
+	if(!!(all & (BufferUsageBit::FILL | BufferUsageBit::BUFFER_UPLOAD_SOURCE | BufferUsageBit::BUFFER_UPLOAD_DESTINATION)))
 	{
 	{
 		d |= GL_BUFFER_UPDATE_BARRIER_BIT;
 		d |= GL_BUFFER_UPDATE_BARRIER_BIT;
 	}
 	}
@@ -1348,22 +1326,19 @@ void CommandBuffer::setBufferBarrier(BufferPtr buff, BufferUsageBit prevUsage, B
 	self.pushBackNewCommand<SetBufferMemBarrierCommand>(d);
 	self.pushBackNewCommand<SetBufferMemBarrierCommand>(d);
 }
 }
 
 
-void CommandBuffer::setTextureSurfaceBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
-											 const TextureSurfaceInfo& surf)
+void CommandBuffer::setTextureSurfaceBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureSurfaceInfo& surf)
 {
 {
 	TextureSubresourceInfo subresource;
 	TextureSubresourceInfo subresource;
 	setTextureBarrier(tex, prevUsage, nextUsage, subresource);
 	setTextureBarrier(tex, prevUsage, nextUsage, subresource);
 }
 }
 
 
-void CommandBuffer::setTextureVolumeBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
-											const TextureVolumeInfo& vol)
+void CommandBuffer::setTextureVolumeBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureVolumeInfo& vol)
 {
 {
 	TextureSubresourceInfo subresource;
 	TextureSubresourceInfo subresource;
 	setTextureBarrier(tex, prevUsage, nextUsage, subresource);
 	setTextureBarrier(tex, prevUsage, nextUsage, subresource);
 }
 }
 
 
-void CommandBuffer::setTextureBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
-									  const TextureSubresourceInfo& subresource)
+void CommandBuffer::setTextureBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureSubresourceInfo& subresource)
 {
 {
 	class Cmd final : public GlCommand
 	class Cmd final : public GlCommand
 	{
 	{
@@ -1505,8 +1480,7 @@ void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, P
 			ANKI_ASSERT(m_offset + 4 <= buff.getSize());
 			ANKI_ASSERT(m_offset + 4 <= buff.getSize());
 
 
 			glBindBuffer(GL_QUERY_BUFFER, buff.getGlName());
 			glBindBuffer(GL_QUERY_BUFFER, buff.getGlName());
-			glGetQueryObjectuiv(static_cast<const OcclusionQueryImpl&>(*m_query).getGlName(), GL_QUERY_RESULT,
-								numberToPtr<GLuint*>(m_offset));
+			glGetQueryObjectuiv(static_cast<const OcclusionQueryImpl&>(*m_query).getGlName(), GL_QUERY_RESULT, numberToPtr<GLuint*>(m_offset));
 			glBindBuffer(GL_QUERY_BUFFER, 0);
 			glBindBuffer(GL_QUERY_BUFFER, 0);
 
 
 			return Error::kNone;
 			return Error::kNone;
@@ -1534,8 +1508,7 @@ void CommandBuffer::setPushConstants(const void* data, U32 dataSize)
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			const ShaderProgramImplReflection& refl =
-				static_cast<ShaderProgramImpl&>(*state.m_crntProg).getReflection();
+			const ShaderProgramImplReflection& refl = static_cast<ShaderProgramImpl&>(*state.m_crntProg).getReflection();
 			ANKI_ASSERT(refl.m_uniformDataSize == m_data.getSizeInBytes());
 			ANKI_ASSERT(refl.m_uniformDataSize == m_data.getSizeInBytes());
 
 
 			const Bool transpose = true;
 			const Bool transpose = true;

+ 5 - 6
AnKi/Gr/Gl/CommandBufferImpl.cpp

@@ -24,8 +24,8 @@ void CommandBufferImpl::init(const CommandBufferInitInfo& init)
 {
 {
 	auto& pool = getManager().getAllocator().getMemoryPool();
 	auto& pool = getManager().getAllocator().getMemoryPool();
 
 
-	m_alloc = CommandBufferAllocator<GlCommand*>(pool.getAllocationCallback(), pool.getAllocationCallbackUserData(),
-												 init.m_hints.m_chunkSize, 1.0, 0, false);
+	m_alloc = CommandBufferAllocator<GlCommand*>(pool.getAllocationCallback(), pool.getAllocationCallbackUserData(), init.m_hints.m_chunkSize, 1.0, 0,
+												 false);
 
 
 	m_flags = init.m_flags;
 	m_flags = init.m_flags;
 
 
@@ -59,8 +59,7 @@ void CommandBufferImpl::destroy()
 		command = next;
 		command = next;
 	}
 	}
 
 
-	ANKI_ASSERT(m_alloc.getMemoryPool().getUsersCount() == 1
-				&& "Someone is holding a reference to the command buffer's allocator");
+	ANKI_ASSERT(m_alloc.getMemoryPool().getUsersCount() == 1 && "Someone is holding a reference to the command buffer's allocator");
 
 
 	m_alloc = CommandBufferAllocator<U8>();
 	m_alloc = CommandBufferAllocator<U8>();
 }
 }
@@ -215,8 +214,8 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 	{
 	{
 		if(m_state.m_glStencilFuncSeparateDirty[i])
 		if(m_state.m_glStencilFuncSeparateDirty[i])
 		{
 		{
-			pushBackNewCommand<StencilCmd>(GL_FRONT + i, convertCompareOperation(m_state.m_stencilCompare[i]),
-										   m_state.m_stencilRef[i], m_state.m_stencilCompareMask[i]);
+			pushBackNewCommand<StencilCmd>(GL_FRONT + i, convertCompareOperation(m_state.m_stencilCompare[i]), m_state.m_stencilRef[i],
+										   m_state.m_stencilCompareMask[i]);
 
 
 			m_state.m_glStencilFuncSeparateDirty[i] = false;
 			m_state.m_glStencilFuncSeparateDirty[i] = false;
 		}
 		}

+ 1 - 2
AnKi/Gr/Gl/Common.cpp

@@ -270,8 +270,7 @@ GLenum convertBlendFactor(BlendFactor in)
 	return out;
 	return out;
 }
 }
 
 
-void convertTextureInformation(Format pf, Bool& compressed, GLenum& format, GLenum& internalFormat, GLenum& type,
-							   DepthStencilAspectBit& dsAspect)
+void convertTextureInformation(Format pf, Bool& compressed, GLenum& format, GLenum& internalFormat, GLenum& type, DepthStencilAspectBit& dsAspect)
 {
 {
 	compressed = formatIsCompressed(pf);
 	compressed = formatIsCompressed(pf);
 	dsAspect = computeFormatAspect(pf);
 	dsAspect = computeFormatAspect(pf);

+ 1 - 2
AnKi/Gr/Gl/Common.h

@@ -177,8 +177,7 @@ inline GLenum convertPrimitiveTopology(PrimitiveTopology ak)
 	return out;
 	return out;
 }
 }
 
 
-void convertTextureInformation(Format pf, Bool& compressed, GLenum& format, GLenum& internalFormat, GLenum& type,
-							   DepthStencilAspectBit& dsAspect);
+void convertTextureInformation(Format pf, Bool& compressed, GLenum& format, GLenum& internalFormat, GLenum& type, DepthStencilAspectBit& dsAspect);
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 4
AnKi/Gr/Gl/Fence.cpp

@@ -82,8 +82,7 @@ Bool Fence::clientWait(Second seconds)
 	{
 	{
 		// Send a cmd that will update the fence's status in case someone calls clientWait with seconds==0.0 all the
 		// Send a cmd that will update the fence's status in case someone calls clientWait with seconds==0.0 all the
 		// time
 		// time
-		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, 0.0,
-																					 nullptr);
+		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, 0.0, nullptr);
 		static_cast<CommandBufferImpl&>(*cmdb).flush();
 		static_cast<CommandBufferImpl&>(*cmdb).flush();
 
 
 		return false;
 		return false;
@@ -94,8 +93,7 @@ Bool Fence::clientWait(Second seconds)
 
 
 		Second flushTime = HighRezTimer::getCurrentTime();
 		Second flushTime = HighRezTimer::getCurrentTime();
 
 
-		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, flushTime,
-																					 &barrier);
+		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, flushTime, &barrier);
 		static_cast<CommandBufferImpl&>(*cmdb).flush();
 		static_cast<CommandBufferImpl&>(*cmdb).flush();
 
 
 		barrier.wait();
 		barrier.wait();

+ 1 - 2
AnKi/Gr/Gl/Framebuffer.cpp

@@ -29,8 +29,7 @@ Framebuffer* Framebuffer::newInstance(GrManager* manager, const FramebufferInitI
 			FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_fb);
 			FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_fb);
 			Error err = impl.init(m_init);
 			Error err = impl.init(m_init);
 
 
-			GlObject::State oldState =
-				impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+			GlObject::State oldState = impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
 			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
 			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
 			(void)oldState;
 			(void)oldState;
 
 

+ 9 - 12
AnKi/Gr/Gl/FramebufferImpl.cpp

@@ -114,8 +114,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
-void FramebufferImpl::attachTextureInternal(GLenum attachment, const TextureViewImpl& view,
-											const FramebufferAttachmentInfo& info)
+void FramebufferImpl::attachTextureInternal(GLenum attachment, const TextureViewImpl& view, const FramebufferAttachmentInfo& info)
 {
 {
 	const GLenum target = GL_FRAMEBUFFER;
 	const GLenum target = GL_FRAMEBUFFER;
 	const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
 	const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
@@ -129,12 +128,11 @@ void FramebufferImpl::attachTextureInternal(GLenum attachment, const TextureView
 		glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), view.getSubresource().m_firstMipmap);
 		glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), view.getSubresource().m_firstMipmap);
 		break;
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 	case GL_TEXTURE_CUBE_MAP:
-		glFramebufferTexture2D(target, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + view.getSubresource().m_firstFace,
-							   tex.getGlName(), view.getSubresource().m_firstMipmap);
+		glFramebufferTexture2D(target, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + view.getSubresource().m_firstFace, tex.getGlName(),
+							   view.getSubresource().m_firstMipmap);
 		break;
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_2D_ARRAY:
-		glFramebufferTextureLayer(target, attachment, tex.getGlName(), view.getSubresource().m_firstMipmap,
-								  view.getSubresource().m_firstLayer);
+		glFramebufferTextureLayer(target, attachment, tex.getGlName(), view.getSubresource().m_firstMipmap, view.getSubresource().m_firstLayer);
 		break;
 		break;
 	case GL_TEXTURE_3D:
 	case GL_TEXTURE_3D:
 		ANKI_ASSERT(!"TODO");
 		ANKI_ASSERT(!"TODO");
@@ -178,8 +176,7 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 	// Invalidate
 	// Invalidate
 	if(m_invalidateBuffersCount)
 	if(m_invalidateBuffersCount)
 	{
 	{
-		glInvalidateSubFramebuffer(GL_FRAMEBUFFER, m_invalidateBuffersCount, &m_invalidateBuffers[0], minx, miny, width,
-								   height);
+		glInvalidateSubFramebuffer(GL_FRAMEBUFFER, m_invalidateBuffersCount, &m_invalidateBuffers[0], minx, miny, width, height);
 	}
 	}
 
 
 	// Clear buffers
 	// Clear buffers
@@ -191,8 +188,8 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 		{
 		{
 			// Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
 			// Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
 			Bool restore = false;
 			Bool restore = false;
-			if(state.m_colorWriteMasks[i][0] != true || state.m_colorWriteMasks[i][1] != true
-			   || state.m_colorWriteMasks[i][2] != true || state.m_colorWriteMasks[i][3] != true)
+			if(state.m_colorWriteMasks[i][0] != true || state.m_colorWriteMasks[i][1] != true || state.m_colorWriteMasks[i][2] != true
+			   || state.m_colorWriteMasks[i][3] != true)
 			{
 			{
 				glColorMaski(i, true, true, true, true);
 				glColorMaski(i, true, true, true, true);
 				restore = true;
 				restore = true;
@@ -202,8 +199,8 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 
 
 			if(restore)
 			if(restore)
 			{
 			{
-				glColorMaski(i, state.m_colorWriteMasks[i][0], state.m_colorWriteMasks[i][1],
-							 state.m_colorWriteMasks[i][2], state.m_colorWriteMasks[i][3]);
+				glColorMaski(i, state.m_colorWriteMasks[i][0], state.m_colorWriteMasks[i][1], state.m_colorWriteMasks[i][2],
+							 state.m_colorWriteMasks[i][3]);
 			}
 			}
 		}
 		}
 	}
 	}

+ 2 - 4
AnKi/Gr/Gl/FramebufferImpl.h

@@ -52,12 +52,10 @@ private:
 	Bool m_clearStencil = false;
 	Bool m_clearStencil = false;
 
 
 	/// Attach a texture
 	/// Attach a texture
-	static void attachTextureInternal(GLenum attachment, const TextureViewImpl& view,
-									  const FramebufferAttachmentInfo& info);
+	static void attachTextureInternal(GLenum attachment, const TextureViewImpl& view, const FramebufferAttachmentInfo& info);
 
 
 	/// Create the FBO
 	/// Create the FBO
-	ANKI_USE_RESULT Error createFbo(const Array<U, kMaxColorRenderTargets + 1>& layers,
-									GLenum depthStencilBindingPoint);
+	ANKI_USE_RESULT Error createFbo(const Array<U, kMaxColorRenderTargets + 1>& layers, GLenum depthStencilBindingPoint);
 };
 };
 /// @}
 /// @}
 
 

+ 3 - 5
AnKi/Gr/Gl/GlState.cpp

@@ -8,7 +8,7 @@
 #include <AnKi/Gr/GrManager.h>
 #include <AnKi/Gr/GrManager.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Core/Trace.h>
 #include <AnKi/Core/Trace.h>
-#include <AnKi/Core/ConfigSet.h>
+#include <AnKi/Core/CVarSet.h>
 #include <algorithm>
 #include <algorithm>
 #include <cstring>
 #include <cstring>
 
 
@@ -43,8 +43,7 @@ static const GlDbg gldbgseverity[] = {{GL_DEBUG_SEVERITY_LOW, "GL_DEBUG_SEVERITY
 __stdcall
 __stdcall
 #	endif
 #	endif
 	void
 	void
-	oglMessagesCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message,
-						const GLvoid* userParam)
+	oglMessagesCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const GLvoid* userParam)
 {
 {
 	using namespace anki;
 	using namespace anki;
 
 
@@ -122,8 +121,7 @@ void GlState::initRenderThread()
 			{
 			{
 				for(U sv = 0; sv < sizeof(gldbgseverity) / sizeof(GlDbg); sv++)
 				for(U sv = 0; sv < sizeof(gldbgseverity) / sizeof(GlDbg); sv++)
 				{
 				{
-					glDebugMessageControl(gldbgsource[s].token, gldbgtype[t].token, gldbgseverity[sv].token, 0, nullptr,
-										  GL_TRUE);
+					glDebugMessageControl(gldbgsource[s].token, gldbgtype[t].token, gldbgseverity[sv].token, 0, nullptr, GL_TRUE);
 				}
 				}
 			}
 			}
 		}
 		}

+ 2 - 4
AnKi/Gr/Gl/GlState.h

@@ -42,10 +42,8 @@ public:
 
 
 	/// @name FB
 	/// @name FB
 	/// @{
 	/// @{
-	Array2d<Bool, kMaxColorRenderTargets, 4> m_colorWriteMasks = {{{{true, true, true, true}},
-																   {{true, true, true, true}},
-																   {{true, true, true, true}},
-																   {{true, true, true, true}}}};
+	Array2d<Bool, kMaxColorRenderTargets, 4> m_colorWriteMasks = {
+		{{{true, true, true, true}}, {{true, true, true, true}}, {{true, true, true, true}}, {{true, true, true, true}}}};
 
 
 	Bool m_depthWriteMask = true;
 	Bool m_depthWriteMask = true;
 
 

+ 1 - 2
AnKi/Gr/Gl/GrManagerImpl.cpp

@@ -82,8 +82,7 @@ void GrManagerImpl::initFakeDefaultFb(GrManagerInitInfo& init)
 	texinit.m_width = defaultFbWidth;
 	texinit.m_width = defaultFbWidth;
 	texinit.m_height = defaultFbHeight;
 	texinit.m_height = defaultFbHeight;
 	texinit.m_format = Format::kR8G8B8A8_Unorm;
 	texinit.m_format = Format::kR8G8B8A8_Unorm;
-	texinit.m_usage =
-		TextureUsageBit::kFramebufferWrite | TextureUsageBit::kImageComputeWrite | TextureUsageBit::kPresent;
+	texinit.m_usage = TextureUsageBit::kFramebufferWrite | TextureUsageBit::kImageComputeWrite | TextureUsageBit::kPresent;
 	m_fakeFbTex = newTexture(texinit);
 	m_fakeFbTex = newTexture(texinit);
 
 
 	TextureViewPtr view = newTextureView(TextureViewInitInfo(m_fakeFbTex, "FB view"));
 	TextureViewPtr view = newTextureView(TextureViewInitInfo(m_fakeFbTex, "FB view"));

+ 1 - 2
AnKi/Gr/Gl/GrManagerImplSdl.cpp

@@ -34,8 +34,7 @@ public:
 	{
 	{
 		m_window = init.m_window->getNative().m_window;
 		m_window = init.m_window->getNative().m_window;
 
 
-		ANKI_GL_LOGI("Creating GL %u.%u context...", U(init.m_config->getNumber("gr.glmajor")),
-					 U(init.m_config->getNumber("gr.glminor")));
+		ANKI_GL_LOGI("Creating GL %u.%u context...", U(init.m_config->getNumber("gr.glmajor")), U(init.m_config->getNumber("gr.glminor")));
 
 
 		if(init.m_config->getNumber("gr_debugContext"))
 		if(init.m_config->getNumber("gr_debugContext"))
 		{
 		{

+ 2 - 4
AnKi/Gr/Gl/RenderingThread.cpp

@@ -55,8 +55,7 @@ public:
 		const FramebufferImpl& fb = static_cast<FramebufferImpl&>(*gr.m_fakeDefaultFb);
 		const FramebufferImpl& fb = static_cast<FramebufferImpl&>(*gr.m_fakeDefaultFb);
 		const U width = gr.m_fakeFbTex->getWidth();
 		const U width = gr.m_fakeFbTex->getWidth();
 		const U height = gr.m_fakeFbTex->getHeight();
 		const U height = gr.m_fakeFbTex->getHeight();
-		glBlitNamedFramebuffer(fb.getGlName(), 0, 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
-							   GL_NEAREST);
+		glBlitNamedFramebuffer(fb.getGlName(), 0, 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
 
 
 		// Swap buffers
 		// Swap buffers
 		m_renderingThread->swapBuffersInternal();
 		m_renderingThread->swapBuffersInternal();
@@ -184,8 +183,7 @@ void RenderingThread::prepare()
 	// Ignore the first error
 	// Ignore the first error
 	glGetError();
 	glGetError();
 
 
-	ANKI_GL_LOGI("OpenGL async thread started: OpenGL version \"%s\", GLSL version \"%s\"",
-				 reinterpret_cast<const char*>(glGetString(GL_VERSION)),
+	ANKI_GL_LOGI("OpenGL async thread started: OpenGL version \"%s\", GLSL version \"%s\"", reinterpret_cast<const char*>(glGetString(GL_VERSION)),
 				 reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
 				 reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
 
 
 	// Get thread id
 	// Get thread id

+ 2 - 4
AnKi/Gr/Gl/Shader.cpp

@@ -19,8 +19,7 @@ Shader* Shader::newInstance(GrManager* manager, const ShaderInitInfo& init)
 		StringRaii m_source;
 		StringRaii m_source;
 		DynamicArrayRaii<ShaderSpecializationConstValue> m_constValues;
 		DynamicArrayRaii<ShaderSpecializationConstValue> m_constValues;
 
 
-		ShaderCreateCommand(Shader* shader, ConstWeakArray<U8> bin,
-							ConstWeakArray<ShaderSpecializationConstValue> constValues,
+		ShaderCreateCommand(Shader* shader, ConstWeakArray<U8> bin, ConstWeakArray<ShaderSpecializationConstValue> constValues,
 							const CommandBufferAllocator<U8>& alloc)
 							const CommandBufferAllocator<U8>& alloc)
 			: m_shader(shader)
 			: m_shader(shader)
 			, m_source(alloc)
 			, m_source(alloc)
@@ -41,8 +40,7 @@ Shader* Shader::newInstance(GrManager* manager, const ShaderInitInfo& init)
 
 
 			Error err = impl.init(m_source.toCString(), m_constValues);
 			Error err = impl.init(m_source.toCString(), m_constValues);
 
 
-			GlObject::State oldState =
-				impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+			GlObject::State oldState = impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
 			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
 			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
 			(void)oldState;
 			(void)oldState;
 
 

+ 2 - 2
AnKi/Gr/Gl/ShaderImpl.cpp

@@ -37,8 +37,8 @@ Error ShaderImpl::init(CString source, ConstWeakArray<ShaderSpecializationConstV
 	ANKI_ASSERT(source);
 	ANKI_ASSERT(source);
 	ANKI_ASSERT(!isCreated());
 	ANKI_ASSERT(!isCreated());
 
 
-	static const Array<GLenum, 6> gltype = {{GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER,
-											 GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER, GL_COMPUTE_SHADER}};
+	static const Array<GLenum, 6> gltype = {
+		{GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER, GL_COMPUTE_SHADER}};
 
 
 	m_glType = gltype[U(m_shaderType)];
 	m_glType = gltype[U(m_shaderType)];
 
 

+ 3 - 4
AnKi/Gr/Gl/ShaderProgram.cpp

@@ -24,8 +24,7 @@ ShaderProgram* ShaderProgram::newInstance(GrManager* manager, const ShaderProgra
 		ShaderPtr m_frag;
 		ShaderPtr m_frag;
 		ShaderPtr m_comp;
 		ShaderPtr m_comp;
 
 
-		CreateCommand(ShaderProgram* prog, ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom,
-					  ShaderPtr frag, ShaderPtr comp)
+		CreateCommand(ShaderProgram* prog, ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag, ShaderPtr comp)
 			: m_prog(prog)
 			: m_prog(prog)
 			, m_vert(vert)
 			, m_vert(vert)
 			, m_tessc(tessc)
 			, m_tessc(tessc)
@@ -57,8 +56,8 @@ ShaderProgram* ShaderProgram::newInstance(GrManager* manager, const ShaderProgra
 	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
 	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
 	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateCommand>(
 	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateCommand>(
 		impl, init.m_shaders[ShaderType::kVertex], init.m_shaders[ShaderType::kTessellationControl],
 		impl, init.m_shaders[ShaderType::kVertex], init.m_shaders[ShaderType::kTessellationControl],
-		init.m_shaders[ShaderType::kTessellationEvaluation], init.m_shaders[ShaderType::kGeometry],
-		init.m_shaders[ShaderType::kFragment], init.m_shaders[ShaderType::kCompute]);
+		init.m_shaders[ShaderType::kTessellationEvaluation], init.m_shaders[ShaderType::kGeometry], init.m_shaders[ShaderType::kFragment],
+		init.m_shaders[ShaderType::kCompute]);
 	static_cast<CommandBufferImpl&>(*cmdb).flush();
 	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
 
 	return impl;
 	return impl;

+ 1 - 2
AnKi/Gr/Gl/ShaderProgramImpl.h

@@ -39,8 +39,7 @@ public:
 
 
 	~ShaderProgramImpl();
 	~ShaderProgramImpl();
 
 
-	ANKI_USE_RESULT Error initGraphics(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom,
-									   ShaderPtr frag);
+	ANKI_USE_RESULT Error initGraphics(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag);
 	ANKI_USE_RESULT Error initCompute(ShaderPtr comp);
 	ANKI_USE_RESULT Error initCompute(ShaderPtr comp);
 
 
 	// Do that only when is needed to avoid serializing the thread the driver is using for compilation.
 	// Do that only when is needed to avoid serializing the thread the driver is using for compilation.

+ 8 - 13
AnKi/Gr/Gl/StateTracker.h

@@ -139,8 +139,7 @@ public:
 
 
 	Bool setScissor(GLsizei minx, GLsizei miny, GLsizei width, GLsizei height)
 	Bool setScissor(GLsizei minx, GLsizei miny, GLsizei width, GLsizei height)
 	{
 	{
-		if(!m_scissorSet
-		   || (m_scissor[0] != minx || m_scissor[1] != miny || m_scissor[2] != width || m_scissor[3] != height))
+		if(!m_scissorSet || (m_scissor[0] != minx || m_scissor[1] != miny || m_scissor[2] != width || m_scissor[3] != height))
 		{
 		{
 			m_scissor = {{minx, miny, width, height}};
 			m_scissor = {{minx, miny, width, height}};
 			m_scissorSet = true;
 			m_scissorSet = true;
@@ -197,11 +196,8 @@ public:
 
 
 	Bool maybeEnableStencilTest()
 	Bool maybeEnableStencilTest()
 	{
 	{
-		Bool enable = !stencilTestDisabled(m_stencilFail[0], m_stencilPassDepthFail[0], m_stencilPassDepthPass[0],
-										   m_stencilCompare[0]);
-		enable = enable
-				 || !stencilTestDisabled(m_stencilFail[1], m_stencilPassDepthFail[1], m_stencilPassDepthPass[1],
-										 m_stencilCompare[1]);
+		Bool enable = !stencilTestDisabled(m_stencilFail[0], m_stencilPassDepthFail[0], m_stencilPassDepthPass[0], m_stencilCompare[0]);
+		enable = enable || !stencilTestDisabled(m_stencilFail[1], m_stencilPassDepthFail[1], m_stencilPassDepthPass[1], m_stencilCompare[1]);
 
 
 		if(enable != m_stencilTestEnabled)
 		if(enable != m_stencilTestEnabled)
 		{
 		{
@@ -215,8 +211,8 @@ public:
 	Array<StencilOperation, 2> m_stencilPassDepthFail = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 	Array<StencilOperation, 2> m_stencilPassDepthFail = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 	Array<StencilOperation, 2> m_stencilPassDepthPass = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 	Array<StencilOperation, 2> m_stencilPassDepthPass = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 
 
-	Bool setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail,
-							  StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass)
+	Bool setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
+							  StencilOperation stencilPassDepthPass)
 	{
 	{
 		Bool changed = false;
 		Bool changed = false;
 		if(!!(face & FaceSelectionBit::FRONT)
 		if(!!(face & FaceSelectionBit::FRONT)
@@ -395,8 +391,8 @@ public:
 	Bool maybeEnableBlend(U attidx)
 	Bool maybeEnableBlend(U attidx)
 	{
 	{
 		ColorAttachment& att = m_colorAtt[attidx];
 		ColorAttachment& att = m_colorAtt[attidx];
-		Bool wantBlend = !blendingDisabled(att.m_blendSrcFactorRgb, att.m_blendDstFactorRgb, att.m_blendSrcFactorA,
-										   att.m_blendDstFactorA, att.m_blendOpRgb, att.m_blendOpA);
+		Bool wantBlend = !blendingDisabled(att.m_blendSrcFactorRgb, att.m_blendDstFactorRgb, att.m_blendSrcFactorA, att.m_blendDstFactorA,
+										   att.m_blendOpRgb, att.m_blendOpA);
 
 
 		if(wantBlend != att.m_enableBlend)
 		if(wantBlend != att.m_enableBlend)
 		{
 		{
@@ -409,8 +405,7 @@ public:
 	Bool setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 	Bool setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 	{
 	{
 		auto& att = m_colorAtt[attachment];
 		auto& att = m_colorAtt[attachment];
-		if(att.m_blendSrcFactorRgb != srcRgb || att.m_blendDstFactorRgb != dstRgb || att.m_blendSrcFactorA != srcA
-		   || att.m_blendDstFactorA != dstA)
+		if(att.m_blendSrcFactorRgb != srcRgb || att.m_blendDstFactorRgb != dstRgb || att.m_blendSrcFactorA != srcA || att.m_blendDstFactorA != dstA)
 		{
 		{
 			att.m_blendSrcFactorRgb = srcRgb;
 			att.m_blendSrcFactorRgb = srcRgb;
 			att.m_blendDstFactorRgb = dstRgb;
 			att.m_blendDstFactorRgb = dstRgb;

+ 11 - 19
AnKi/Gr/Gl/TextureImpl.cpp

@@ -93,8 +93,7 @@ TextureImpl::~TextureImpl()
 		CommandBufferPtr commands;
 		CommandBufferPtr commands;
 
 
 		commands = manager.newCommandBuffer(CommandBufferInitInfo());
 		commands = manager.newCommandBuffer(CommandBufferInitInfo());
-		static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteTextureCommand>(m_glName, m_viewsMap,
-																							getAllocator());
+		static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteTextureCommand>(m_glName, m_viewsMap, getAllocator());
 		static_cast<CommandBufferImpl&>(*commands).flush();
 		static_cast<CommandBufferImpl&>(*commands).flush();
 	}
 	}
 	else
 	else
@@ -208,8 +207,7 @@ void TextureImpl::init(const TextureInitInfo& init)
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::copyFromBuffer(const TextureSubresourceInfo& subresource, GLuint pbo, PtrSize offset,
-								 PtrSize dataSize) const
+void TextureImpl::copyFromBuffer(const TextureSubresourceInfo& subresource, GLuint pbo, PtrSize offset, PtrSize dataSize) const
 {
 {
 	ANKI_ASSERT(isSubresourceGoodForCopyFromBuffer(subresource));
 	ANKI_ASSERT(isSubresourceGoodForCopyFromBuffer(subresource));
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(dataSize > 0);
@@ -242,13 +240,11 @@ void TextureImpl::copyFromBuffer(const TextureSubresourceInfo& subresource, GLui
 		const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, subresource.m_firstFace, 0));
 		const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, subresource.m_firstFace, 0));
 		if(!m_compressed)
 		if(!m_compressed)
 		{
 		{
-			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, m_glType,
-							ptrOffset);
+			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, m_glType, ptrOffset);
 		}
 		}
 		else
 		else
 		{
 		{
-			glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat,
-									  dataSize, ptrOffset);
+			glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, dataSize, ptrOffset);
 		}
 		}
 		break;
 		break;
 	}
 	}
@@ -333,15 +329,13 @@ void TextureImpl::clear(const TextureSubresourceInfo& subresource, const ClearVa
 	{
 	{
 		for(U face = subresource.m_firstFace; face < subresource.m_firstFace + subresource.m_faceCount; ++face)
 		for(U face = subresource.m_firstFace; face < subresource.m_firstFace + subresource.m_faceCount; ++face)
 		{
 		{
-			for(U layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount;
-				++layer)
+			for(U layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount; ++layer)
 			{
 			{
 				const U surfaceIdx = computeSurfaceIdx(TextureSurfaceInfo(mip, 0, face, layer));
 				const U surfaceIdx = computeSurfaceIdx(TextureSurfaceInfo(mip, 0, face, layer));
 				const U width = m_width >> mip;
 				const U width = m_width >> mip;
 				const U height = m_height >> mip;
 				const U height = m_height >> mip;
 
 
-				glClearTexSubImage(m_glName, mip, 0, 0, surfaceIdx, width, height, 1, format, GL_FLOAT,
-								   &clearValue.m_colorf[0]);
+				glClearTexSubImage(m_glName, mip, 0, 0, surfaceIdx, width, height, 1, format, GL_FLOAT, &clearValue.m_colorf[0]);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -402,19 +396,17 @@ MicroTextureView TextureImpl::getOrCreateView(const TextureSubresourceInfo& subr
 			glTarget = GL_TEXTURE_2D;
 			glTarget = GL_TEXTURE_2D;
 		}
 		}
 
 
-		const U firstSurf = computeSurfaceIdx(
-			TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace, subresource.m_firstLayer));
-		const U lastSurf = computeSurfaceIdx(
-			TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace + subresource.m_faceCount - 1,
-							   subresource.m_firstLayer + subresource.m_layerCount - 1));
+		const U firstSurf = computeSurfaceIdx(TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace, subresource.m_firstLayer));
+		const U lastSurf = computeSurfaceIdx(TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace + subresource.m_faceCount - 1,
+																subresource.m_firstLayer + subresource.m_layerCount - 1));
 		ANKI_ASSERT(firstSurf <= lastSurf);
 		ANKI_ASSERT(firstSurf <= lastSurf);
 
 
 		MicroTextureView view;
 		MicroTextureView view;
 		view.m_aspect = subresource.m_depthStencilAspect;
 		view.m_aspect = subresource.m_depthStencilAspect;
 
 
 		glGenTextures(1, &view.m_glName);
 		glGenTextures(1, &view.m_glName);
-		glTextureView(view.m_glName, glTarget, m_glName, m_internalFormat, subresource.m_firstMipmap,
-					  subresource.m_mipmapCount, firstSurf, lastSurf - firstSurf + 1);
+		glTextureView(view.m_glName, glTarget, m_glName, m_internalFormat, subresource.m_firstMipmap, subresource.m_mipmapCount, firstSurf,
+					  lastSurf - firstSurf + 1);
 
 
 		m_viewsMap.emplace(getAllocator(), subresource, view);
 		m_viewsMap.emplace(getAllocator(), subresource, view);
 
 

+ 4 - 16
AnKi/Gr/GrManager.h

@@ -8,11 +8,15 @@
 #include <AnKi/Gr/Common.h>
 #include <AnKi/Gr/Common.h>
 #include <AnKi/Gr/GrObject.h>
 #include <AnKi/Gr/GrObject.h>
 #include <AnKi/Util/String.h>
 #include <AnKi/Util/String.h>
+#include <AnKi/Core/CVarSet.h>
 
 
 namespace anki {
 namespace anki {
 
 
 // Forward
 // Forward
 class NativeWindow;
 class NativeWindow;
+extern BoolCVar g_vsyncCVar;
+extern BoolCVar g_validationCVar;
+extern BoolCVar g_debugMarkersCVar;
 
 
 /// @addtogroup graphics
 /// @addtogroup graphics
 /// @{
 /// @{
@@ -27,20 +31,6 @@ public:
 	CString m_cacheDirectory;
 	CString m_cacheDirectory;
 };
 };
 
 
-/// Graphics statistics.
-class GrManagerStats
-{
-public:
-	PtrSize m_deviceMemoryAllocated = 0;
-	PtrSize m_deviceMemoryInUse = 0;
-	U32 m_deviceMemoryAllocationCount = 0;
-	PtrSize m_hostMemoryAllocated = 0;
-	PtrSize m_hostMemoryInUse = 0;
-	U32 m_hostMemoryAllocationCount = 0;
-
-	U32 m_commandBufferCount = 0;
-};
-
 /// The graphics manager, owner of all graphics objects.
 /// The graphics manager, owner of all graphics objects.
 class GrManager : public MakeSingletonPtr<GrManager>
 class GrManager : public MakeSingletonPtr<GrManager>
 {
 {
@@ -82,8 +72,6 @@ public:
 	[[nodiscard]] AccelerationStructurePtr newAccelerationStructure(const AccelerationStructureInitInfo& init);
 	[[nodiscard]] AccelerationStructurePtr newAccelerationStructure(const AccelerationStructureInitInfo& init);
 	/// @}
 	/// @}
 
 
-	GrManagerStats getStats() const;
-
 	ANKI_INTERNAL CString getCacheDirectory() const
 	ANKI_INTERNAL CString getCacheDirectory() const
 	{
 	{
 		return m_cacheDir.toCString();
 		return m_cacheDir.toCString();

+ 151 - 151
AnKi/Gr/RenderGraph.cpp

@@ -14,6 +14,7 @@
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/StringList.h>
 #include <AnKi/Util/StringList.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Util/HighRezTimer.h>
+#include <AnKi/Core/Common.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -41,7 +42,7 @@ public:
 };
 };
 
 
 /// Same as RT but for buffers.
 /// Same as RT but for buffers.
-class RenderGraph::Buffer
+class RenderGraph::BufferRange
 {
 {
 public:
 public:
 	BufferUsageBit m_usage;
 	BufferUsageBit m_usage;
@@ -67,8 +68,7 @@ public:
 	TextureSurfaceInfo m_surface;
 	TextureSurfaceInfo m_surface;
 	DepthStencilAspectBit m_dsAspect;
 	DepthStencilAspectBit m_dsAspect;
 
 
-	TextureBarrier(U32 rtIdx, TextureUsageBit usageBefore, TextureUsageBit usageAfter, const TextureSurfaceInfo& surf,
-				   DepthStencilAspectBit dsAspect)
+	TextureBarrier(U32 rtIdx, TextureUsageBit usageBefore, TextureUsageBit usageAfter, const TextureSurfaceInfo& surf, DepthStencilAspectBit dsAspect)
 		: m_idx(rtIdx)
 		: m_idx(rtIdx)
 		, m_usageBefore(usageBefore)
 		, m_usageBefore(usageBefore)
 		, m_usageAfter(usageAfter)
 		, m_usageAfter(usageAfter)
@@ -122,12 +122,15 @@ public:
 	Function<void(RenderPassWorkContext&), MemoryPoolPtrWrapper<StackMemoryPool>> m_callback;
 	Function<void(RenderPassWorkContext&), MemoryPoolPtrWrapper<StackMemoryPool>> m_callback;
 
 
 	DynamicArray<CommandBufferPtr, MemoryPoolPtrWrapper<StackMemoryPool>> m_secondLevelCmdbs;
 	DynamicArray<CommandBufferPtr, MemoryPoolPtrWrapper<StackMemoryPool>> m_secondLevelCmdbs;
-	/// Will reuse the m_secondLevelCmdbInitInfo.m_framebuffer to get the framebuffer.
 	CommandBufferInitInfo m_secondLevelCmdbInitInfo;
 	CommandBufferInitInfo m_secondLevelCmdbInitInfo;
 	Array<U32, 4> m_fbRenderArea;
 	Array<U32, 4> m_fbRenderArea;
 	Array<TextureUsageBit, kMaxColorRenderTargets> m_colorUsages = {}; ///< For beginRender pass
 	Array<TextureUsageBit, kMaxColorRenderTargets> m_colorUsages = {}; ///< For beginRender pass
 	TextureUsageBit m_dsUsage = TextureUsageBit::kNone; ///< For beginRender pass
 	TextureUsageBit m_dsUsage = TextureUsageBit::kNone; ///< For beginRender pass
 
 
+	FramebufferPtr m_framebuffer;
+
+	BaseString<MemoryPoolPtrWrapper<StackMemoryPool>> m_name;
+
 	U32 m_batchIdx ANKI_DEBUG_CODE(= kMaxU32);
 	U32 m_batchIdx ANKI_DEBUG_CODE(= kMaxU32);
 	Bool m_drawsToPresentable = false;
 	Bool m_drawsToPresentable = false;
 
 
@@ -135,18 +138,9 @@ public:
 		: m_dependsOn(pool)
 		: m_dependsOn(pool)
 		, m_consumedTextures(pool)
 		, m_consumedTextures(pool)
 		, m_secondLevelCmdbs(pool)
 		, m_secondLevelCmdbs(pool)
+		, m_name(pool)
 	{
 	{
 	}
 	}
-
-	FramebufferPtr& fb()
-	{
-		return m_secondLevelCmdbInitInfo.m_framebuffer;
-	}
-
-	const FramebufferPtr& fb() const
-	{
-		return m_secondLevelCmdbInitInfo.m_framebuffer;
-	}
 };
 };
 
 
 /// A batch of render passes. These passes can run in parallel.
 /// A batch of render passes. These passes can run in parallel.
@@ -177,7 +171,7 @@ public:
 	BitSet<kMaxRenderGraphPasses, U64> m_passIsInBatch{false};
 	BitSet<kMaxRenderGraphPasses, U64> m_passIsInBatch{false};
 	DynamicArray<Batch, MemoryPoolPtrWrapper<StackMemoryPool>> m_batches;
 	DynamicArray<Batch, MemoryPoolPtrWrapper<StackMemoryPool>> m_batches;
 	DynamicArray<RT, MemoryPoolPtrWrapper<StackMemoryPool>> m_rts;
 	DynamicArray<RT, MemoryPoolPtrWrapper<StackMemoryPool>> m_rts;
-	DynamicArray<Buffer, MemoryPoolPtrWrapper<StackMemoryPool>> m_buffers;
+	DynamicArray<BufferRange, MemoryPoolPtrWrapper<StackMemoryPool>> m_buffers;
 	DynamicArray<AS, MemoryPoolPtrWrapper<StackMemoryPool>> m_as;
 	DynamicArray<AS, MemoryPoolPtrWrapper<StackMemoryPool>> m_as;
 
 
 	DynamicArray<CommandBufferPtr, MemoryPoolPtrWrapper<StackMemoryPool>> m_graphicsCmdbs;
 	DynamicArray<CommandBufferPtr, MemoryPoolPtrWrapper<StackMemoryPool>> m_graphicsCmdbs;
@@ -278,8 +272,7 @@ void FramebufferDescription::bake()
 		sriToHash.m_sriTexelHeight = m_shadingRateAttachmentTexelHeight;
 		sriToHash.m_sriTexelHeight = m_shadingRateAttachmentTexelHeight;
 		sriToHash.m_surface = m_shadingRateAttachmentSurface;
 		sriToHash.m_surface = m_shadingRateAttachmentSurface;
 
 
-		m_hash = (m_hash != 0) ? appendHash(&sriToHash, sizeof(sriToHash), m_hash)
-							   : computeHash(&sriToHash, sizeof(sriToHash));
+		m_hash = (m_hash != 0) ? appendHash(&sriToHash, sizeof(sriToHash), m_hash) : computeHash(&sriToHash, sizeof(sriToHash));
 	}
 	}
 
 
 	ANKI_ASSERT(m_hash != 0 && m_hash != 1);
 	ANKI_ASSERT(m_hash != 0 && m_hash != 1);
@@ -350,7 +343,7 @@ void RenderGraph::reset()
 		rt.m_texture.reset(nullptr);
 		rt.m_texture.reset(nullptr);
 	}
 	}
 
 
-	for(Buffer& buff : m_ctx->m_buffers)
+	for(BufferRange& buff : m_ctx->m_buffers)
 	{
 	{
 		buff.m_buffer.reset(nullptr);
 		buff.m_buffer.reset(nullptr);
 	}
 	}
@@ -367,9 +360,10 @@ void RenderGraph::reset()
 
 
 	for(Pass& p : m_ctx->m_passes)
 	for(Pass& p : m_ctx->m_passes)
 	{
 	{
-		p.fb().reset(nullptr);
+		p.m_framebuffer.reset(nullptr);
 		p.m_secondLevelCmdbs.destroy();
 		p.m_secondLevelCmdbs.destroy();
 		p.m_callback.destroy();
 		p.m_callback.destroy();
+		p.m_name.destroy();
 	}
 	}
 
 
 	m_ctx->m_graphicsCmdbs.destroy();
 	m_ctx->m_graphicsCmdbs.destroy();
@@ -422,8 +416,7 @@ TexturePtr RenderGraph::getOrCreateRenderTarget(const TextureInitInfo& initInf,
 	return tex;
 	return tex;
 }
 }
 
 
-FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription& fbDescr,
-												   const RenderTargetHandle* rtHandles, CString name,
+FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription& fbDescr, const RenderTargetHandle* rtHandles, CString name,
 												   Bool& drawsToPresentable)
 												   Bool& drawsToPresentable)
 {
 {
 	ANKI_ASSERT(rtHandles);
 	ANKI_ASSERT(rtHandles);
@@ -482,8 +475,8 @@ FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription&
 			outAtt.m_storeOperation = inAtt.m_storeOperation;
 			outAtt.m_storeOperation = inAtt.m_storeOperation;
 
 
 			// Create texture view
 			// Create texture view
-			TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[i].m_idx].m_texture,
-										 TextureSubresourceInfo(inAtt.m_surface), "RenderGraph");
+			const TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[i].m_idx].m_texture.get(), TextureSubresourceInfo(inAtt.m_surface),
+											   "RenderGraph");
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 
 
 			outAtt.m_textureView = std::move(view);
 			outAtt.m_textureView = std::move(view);
@@ -501,8 +494,8 @@ FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription&
 			outAtt.m_stencilStoreOperation = inAtt.m_stencilStoreOperation;
 			outAtt.m_stencilStoreOperation = inAtt.m_stencilStoreOperation;
 
 
 			// Create texture view
 			// Create texture view
-			TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[kMaxColorRenderTargets].m_idx].m_texture,
-										 TextureSubresourceInfo(inAtt.m_surface, inAtt.m_aspect), "RenderGraph");
+			const TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[kMaxColorRenderTargets].m_idx].m_texture.get(),
+											   TextureSubresourceInfo(inAtt.m_surface, inAtt.m_aspect), "RenderGraph");
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 
 
 			outAtt.m_textureView = std::move(view);
 			outAtt.m_textureView = std::move(view);
@@ -510,8 +503,8 @@ FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription&
 
 
 		if(fbDescr.m_shadingRateAttachmentTexelWidth > 0)
 		if(fbDescr.m_shadingRateAttachmentTexelWidth > 0)
 		{
 		{
-			TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[kMaxColorRenderTargets + 1].m_idx].m_texture,
-										 fbDescr.m_shadingRateAttachmentSurface, "RenderGraph SRI");
+			const TextureViewInitInfo viewInit(m_ctx->m_rts[rtHandles[kMaxColorRenderTargets + 1].m_idx].m_texture.get(),
+											   fbDescr.m_shadingRateAttachmentSurface, "RenderGraph SRI");
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 			TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 
 
 			fbInit.m_shadingRateImage.m_texelWidth = fbDescr.m_shadingRateAttachmentTexelWidth;
 			fbInit.m_shadingRateImage.m_texelWidth = fbDescr.m_shadingRateAttachmentTexelWidth;
@@ -532,8 +525,7 @@ FramebufferPtr RenderGraph::getOrCreateFramebuffer(const FramebufferDescription&
 
 
 Bool RenderGraph::overlappingTextureSubresource(const TextureSubresourceInfo& suba, const TextureSubresourceInfo& subb)
 Bool RenderGraph::overlappingTextureSubresource(const TextureSubresourceInfo& suba, const TextureSubresourceInfo& subb)
 {
 {
-#define ANKI_OVERLAPPING(first, count) \
-	((suba.first < subb.first + subb.count) && (subb.first < suba.first + suba.count))
+#define ANKI_OVERLAPPING(first, count) ((suba.first < subb.first + subb.count) && (subb.first < suba.first + suba.count))
 
 
 	const Bool overlappingFaces = ANKI_OVERLAPPING(m_firstFace, m_faceCount);
 	const Bool overlappingFaces = ANKI_OVERLAPPING(m_firstFace, m_faceCount);
 	const Bool overlappingMips = ANKI_OVERLAPPING(m_firstMipmap, m_mipmapCount);
 	const Bool overlappingMips = ANKI_OVERLAPPING(m_firstMipmap, m_mipmapCount);
@@ -554,7 +546,7 @@ Bool RenderGraph::passADependsOnB(const RenderPassDescriptionBase& a, const Rend
 
 
 		const BitSet<kMaxRenderGraphRenderTargets, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
 		const BitSet<kMaxRenderGraphRenderTargets, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
 
 
-		if(fullDep.getAny())
+		if(fullDep.getAnySet())
 		{
 		{
 			// There might be an overlap
 			// There might be an overlap
 
 
@@ -596,7 +588,7 @@ Bool RenderGraph::passADependsOnB(const RenderPassDescriptionBase& a, const Rend
 
 
 		const BitSet<kMaxRenderGraphBuffers, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
 		const BitSet<kMaxRenderGraphBuffers, U64> fullDep = aReadBWrite | aWriteBRead | aWriteBWrite;
 
 
-		if(fullDep.getAny())
+		if(fullDep.getAnySet())
 		{
 		{
 			// There might be an overlap
 			// There might be an overlap
 
 
@@ -800,6 +792,7 @@ void RenderGraph::initRenderPassesAndSetDeps(const RenderGraphDescription& descr
 		Pass& outPass = *ctx.m_passes.emplaceBack(ctx.m_as.getMemoryPool().m_pool);
 		Pass& outPass = *ctx.m_passes.emplaceBack(ctx.m_as.getMemoryPool().m_pool);
 
 
 		outPass.m_callback = inPass.m_callback;
 		outPass.m_callback = inPass.m_callback;
+		outPass.m_name = inPass.m_name;
 
 
 		// Create consumer info
 		// Create consumer info
 		outPass.m_consumedTextures.resize(inPass.m_rtDeps.getSize());
 		outPass.m_consumedTextures.resize(inPass.m_rtDeps.getSize());
@@ -817,14 +810,13 @@ void RenderGraph::initRenderPassesAndSetDeps(const RenderGraphDescription& descr
 		// Create command buffers and framebuffer
 		// Create command buffers and framebuffer
 		if(inPass.m_type == RenderPassDescriptionBase::Type::kGraphics)
 		if(inPass.m_type == RenderPassDescriptionBase::Type::kGraphics)
 		{
 		{
-			const GraphicsRenderPassDescription& graphicsPass =
-				static_cast<const GraphicsRenderPassDescription&>(inPass);
+			const GraphicsRenderPassDescription& graphicsPass = static_cast<const GraphicsRenderPassDescription&>(inPass);
 
 
 			if(graphicsPass.hasFramebuffer())
 			if(graphicsPass.hasFramebuffer())
 			{
 			{
 				Bool drawsToPresentable;
 				Bool drawsToPresentable;
-				outPass.fb() = getOrCreateFramebuffer(graphicsPass.m_fbDescr, &graphicsPass.m_rtHandles[0],
-													  inPass.m_name.cstr(), drawsToPresentable);
+				outPass.m_framebuffer =
+					getOrCreateFramebuffer(graphicsPass.m_fbDescr, &graphicsPass.m_rtHandles[0], inPass.m_name.cstr(), drawsToPresentable);
 
 
 				outPass.m_fbRenderArea = graphicsPass.m_fbRenderArea;
 				outPass.m_fbRenderArea = graphicsPass.m_fbRenderArea;
 				outPass.m_drawsToPresentable = drawsToPresentable;
 				outPass.m_drawsToPresentable = drawsToPresentable;
@@ -881,8 +873,8 @@ void RenderGraph::initBatches()
 		}
 		}
 
 
 		// Get or create cmdb for the batch.
 		// Get or create cmdb for the batch.
-		// Create a new cmdb if the batch is writing to swapchain. This will help Vulkan to have a dependency of the
-		// swap chain image acquire to the 2nd command buffer instead of adding it to a single big cmdb.
+		// Create a new cmdb if the batch is writing to swapchain. This will help Vulkan to have a dependency of the swap chain image acquire to the
+		// 2nd command buffer instead of adding it to a single big cmdb.
 		if(m_ctx->m_graphicsCmdbs.isEmpty() || drawsToPresentable)
 		if(m_ctx->m_graphicsCmdbs.isEmpty() || drawsToPresentable)
 		{
 		{
 			CommandBufferInitInfo cmdbInit;
 			CommandBufferInitInfo cmdbInit;
@@ -900,7 +892,7 @@ void RenderGraph::initBatches()
 				TimestampQueryPtr query = GrManager::getSingleton().newTimestampQuery();
 				TimestampQueryPtr query = GrManager::getSingleton().newTimestampQuery();
 				TimestampQuery* pQuery = query.get();
 				TimestampQuery* pQuery = query.get();
 				cmdb->resetTimestampQueries({&pQuery, 1});
 				cmdb->resetTimestampQueries({&pQuery, 1});
-				cmdb->writeTimestamp(query);
+				cmdb->writeTimestamp(query.get());
 
 
 				m_statistics.m_nextTimestamp = (m_statistics.m_nextTimestamp + 1) % kMaxBufferedTimestamps;
 				m_statistics.m_nextTimestamp = (m_statistics.m_nextTimestamp + 1) % kMaxBufferedTimestamps;
 				m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2] = query;
 				m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2] = query;
@@ -934,8 +926,7 @@ void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr)
 		// Create command buffers and framebuffer
 		// Create command buffers and framebuffer
 		if(inPass.m_type == RenderPassDescriptionBase::Type::kGraphics)
 		if(inPass.m_type == RenderPassDescriptionBase::Type::kGraphics)
 		{
 		{
-			const GraphicsRenderPassDescription& graphicsPass =
-				static_cast<const GraphicsRenderPassDescription&>(inPass);
+			const GraphicsRenderPassDescription& graphicsPass = static_cast<const GraphicsRenderPassDescription&>(inPass);
 
 
 			if(graphicsPass.hasFramebuffer())
 			if(graphicsPass.hasFramebuffer())
 			{
 			{
@@ -951,12 +942,10 @@ void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr)
 
 
 				if(!!graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect)
 				if(!!graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect)
 				{
 				{
-					TextureSubresourceInfo subresource =
-						TextureSubresourceInfo(graphicsPass.m_fbDescr.m_depthStencilAttachment.m_surface,
-											   graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect);
+					TextureSubresourceInfo subresource = TextureSubresourceInfo(graphicsPass.m_fbDescr.m_depthStencilAttachment.m_surface,
+																				graphicsPass.m_fbDescr.m_depthStencilAttachment.m_aspect);
 
 
-					getCrntUsage(graphicsPass.m_rtHandles[kMaxColorRenderTargets], outPass.m_batchIdx, subresource,
-								 usage);
+					getCrntUsage(graphicsPass.m_rtHandles[kMaxColorRenderTargets], outPass.m_batchIdx, subresource, usage);
 
 
 					outPass.m_dsUsage = usage;
 					outPass.m_dsUsage = usage;
 				}
 				}
@@ -967,7 +956,7 @@ void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr)
 					outPass.m_secondLevelCmdbs.resize(inPass.m_secondLevelCmdbsCount);
 					outPass.m_secondLevelCmdbs.resize(inPass.m_secondLevelCmdbsCount);
 					CommandBufferInitInfo& cmdbInit = outPass.m_secondLevelCmdbInitInfo;
 					CommandBufferInitInfo& cmdbInit = outPass.m_secondLevelCmdbInitInfo;
 					cmdbInit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSecondLevel;
 					cmdbInit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSecondLevel;
-					ANKI_ASSERT(cmdbInit.m_framebuffer.isCreated());
+					cmdbInit.m_framebuffer = outPass.m_framebuffer.get();
 					cmdbInit.m_colorAttachmentUsages = outPass.m_colorUsages;
 					cmdbInit.m_colorAttachmentUsages = outPass.m_colorUsages;
 					cmdbInit.m_depthStencilAttachmentUsage = outPass.m_dsUsage;
 					cmdbInit.m_depthStencilAttachmentUsage = outPass.m_dsUsage;
 				}
 				}
@@ -985,18 +974,17 @@ void RenderGraph::initGraphicsPasses(const RenderGraphDescription& descr)
 }
 }
 
 
 template<typename TFunc>
 template<typename TFunc>
-void RenderGraph::iterateSurfsOrVolumes(const TexturePtr& tex, const TextureSubresourceInfo& subresource, TFunc func)
+void RenderGraph::iterateSurfsOrVolumes(const Texture& tex, const TextureSubresourceInfo& subresource, TFunc func)
 {
 {
 	for(U32 mip = subresource.m_firstMipmap; mip < subresource.m_firstMipmap + subresource.m_mipmapCount; ++mip)
 	for(U32 mip = subresource.m_firstMipmap; mip < subresource.m_firstMipmap + subresource.m_mipmapCount; ++mip)
 	{
 	{
 		for(U32 layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount; ++layer)
 		for(U32 layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount; ++layer)
 		{
 		{
-			for(U32 face = subresource.m_firstFace; face < U32(subresource.m_firstFace + subresource.m_faceCount);
-				++face)
+			for(U32 face = subresource.m_firstFace; face < U32(subresource.m_firstFace + subresource.m_faceCount); ++face)
 			{
 			{
 				// Compute surf or vol idx
 				// Compute surf or vol idx
-				const U32 faceCount = textureTypeIsCube(tex->getTextureType()) ? 6 : 1;
-				const U32 idx = (faceCount * tex->getLayerCount()) * mip + faceCount * layer + face;
+				const U32 faceCount = textureTypeIsCube(tex.getTextureType()) ? 6 : 1;
+				const U32 idx = (faceCount * tex.getLayerCount()) * mip + faceCount * layer + face;
 				const TextureSurfaceInfo surf(mip, 0, face, layer);
 				const TextureSurfaceInfo surf(mip, 0, face, layer);
 
 
 				if(!func(idx, surf))
 				if(!func(idx, surf))
@@ -1018,45 +1006,43 @@ void RenderGraph::setTextureBarrier(Batch& batch, const RenderPassDependency& de
 	const TextureUsageBit depUsage = dep.m_texture.m_usage;
 	const TextureUsageBit depUsage = dep.m_texture.m_usage;
 	RT& rt = ctx.m_rts[rtIdx];
 	RT& rt = ctx.m_rts[rtIdx];
 
 
-	iterateSurfsOrVolumes(
-		rt.m_texture, dep.m_texture.m_subresource, [&](U32 surfOrVolIdx, const TextureSurfaceInfo& surf) {
-			TextureUsageBit& crntUsage = rt.m_surfOrVolUsages[surfOrVolIdx];
-			if(crntUsage != depUsage)
+	iterateSurfsOrVolumes(*rt.m_texture, dep.m_texture.m_subresource, [&](U32 surfOrVolIdx, const TextureSurfaceInfo& surf) {
+		TextureUsageBit& crntUsage = rt.m_surfOrVolUsages[surfOrVolIdx];
+		if(crntUsage != depUsage)
+		{
+			// Check if we can merge barriers
+			if(rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] == batchIdx)
 			{
 			{
-				// Check if we can merge barriers
-				if(rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] == batchIdx)
-				{
-					// Will merge the barriers
+				// Will merge the barriers
 
 
-					crntUsage |= depUsage;
+				crntUsage |= depUsage;
 
 
-					[[maybe_unused]] Bool found = false;
-					for(TextureBarrier& b : batch.m_textureBarriersBefore)
+				[[maybe_unused]] Bool found = false;
+				for(TextureBarrier& b : batch.m_textureBarriersBefore)
+				{
+					if(b.m_idx == rtIdx && b.m_surface == surf)
 					{
 					{
-						if(b.m_idx == rtIdx && b.m_surface == surf)
-						{
-							b.m_usageAfter |= depUsage;
-							found = true;
-							break;
-						}
+						b.m_usageAfter |= depUsage;
+						found = true;
+						break;
 					}
 					}
-
-					ANKI_ASSERT(found);
 				}
 				}
-				else
-				{
-					// Create a new barrier for this surface
 
 
-					batch.m_textureBarriersBefore.emplaceBack(rtIdx, crntUsage, depUsage, surf,
-															  dep.m_texture.m_subresource.m_depthStencilAspect);
+				ANKI_ASSERT(found);
+			}
+			else
+			{
+				// Create a new barrier for this surface
 
 
-					crntUsage = depUsage;
-					rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] = U16(batchIdx);
-				}
+				batch.m_textureBarriersBefore.emplaceBack(rtIdx, crntUsage, depUsage, surf, dep.m_texture.m_subresource.m_depthStencilAspect);
+
+				crntUsage = depUsage;
+				rt.m_lastBatchThatTransitionedIt[surfOrVolIdx] = U16(batchIdx);
 			}
 			}
+		}
 
 
-			return true;
-		});
+		return true;
+	});
 }
 }
 
 
 void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr)
 void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr)
@@ -1204,10 +1190,9 @@ void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr)
 					  return a.m_idx < b.m_idx;
 					  return a.m_idx < b.m_idx;
 				  });
 				  });
 
 
-		std::sort(batch.m_asBarriersBefore.getBegin(), batch.m_asBarriersBefore.getEnd(),
-				  [&](const ASBarrier& a, const ASBarrier& b) {
-					  return a.m_idx < b.m_idx;
-				  });
+		std::sort(batch.m_asBarriersBefore.getBegin(), batch.m_asBarriersBefore.getEnd(), [&](const ASBarrier& a, const ASBarrier& b) {
+			return a.m_idx < b.m_idx;
+		});
 #endif
 #endif
 	} // For all batches
 	} // For all batches
 }
 }
@@ -1240,56 +1225,66 @@ void RenderGraph::compileNewGraph(const RenderGraphDescription& descr, StackMemo
 #endif
 #endif
 }
 }
 
 
-TexturePtr RenderGraph::getTexture(RenderTargetHandle handle) const
+Texture& RenderGraph::getTexture(RenderTargetHandle handle) const
 {
 {
 	ANKI_ASSERT(m_ctx->m_rts[handle.m_idx].m_texture.isCreated());
 	ANKI_ASSERT(m_ctx->m_rts[handle.m_idx].m_texture.isCreated());
-	return m_ctx->m_rts[handle.m_idx].m_texture;
+	return *m_ctx->m_rts[handle.m_idx].m_texture;
 }
 }
 
 
-BufferPtr RenderGraph::getBuffer(BufferHandle handle) const
+void RenderGraph::getCachedBuffer(BufferHandle handle, Buffer*& buff, PtrSize& offset, PtrSize& range) const
 {
 {
-	ANKI_ASSERT(m_ctx->m_buffers[handle.m_idx].m_buffer.isCreated());
-	return m_ctx->m_buffers[handle.m_idx].m_buffer;
+	const BufferRange& record = m_ctx->m_buffers[handle.m_idx];
+	buff = record.m_buffer.get();
+	offset = record.m_offset;
+	range = record.m_range;
 }
 }
 
 
-AccelerationStructurePtr RenderGraph::getAs(AccelerationStructureHandle handle) const
+AccelerationStructure* RenderGraph::getAs(AccelerationStructureHandle handle) const
 {
 {
 	ANKI_ASSERT(m_ctx->m_as[handle.m_idx].m_as.isCreated());
 	ANKI_ASSERT(m_ctx->m_as[handle.m_idx].m_as.isCreated());
-	return m_ctx->m_as[handle.m_idx].m_as;
+	return m_ctx->m_as[handle.m_idx].m_as.get();
 }
 }
 
 
-void RenderGraph::runSecondLevel(U32 threadIdx)
+void RenderGraph::runSecondLevel()
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(GrRenderGraph2ndLevel);
 	ANKI_TRACE_SCOPED_EVENT(GrRenderGraph2ndLevel);
 	ANKI_ASSERT(m_ctx);
 	ANKI_ASSERT(m_ctx);
 
 
-	RenderPassWorkContext ctx;
-	ctx.m_rgraph = this;
-	ctx.m_currentSecondLevelCommandBufferIndex = threadIdx;
+	StackMemoryPool& pool = *m_ctx->m_rts.getMemoryPool().m_pool;
 
 
-	for(Pass& p : m_ctx->m_passes)
+	// Gather the tasks
+	for(Pass& pass : m_ctx->m_passes)
 	{
 	{
-		const U32 size = p.m_secondLevelCmdbs.getSize();
-		if(threadIdx < size)
+		for(U32 cmdIdx = 0; cmdIdx < pass.m_secondLevelCmdbs.getSize(); ++cmdIdx)
 		{
 		{
-			ANKI_ASSERT(!p.m_secondLevelCmdbs[threadIdx].isCreated());
-			p.m_secondLevelCmdbs[threadIdx] = GrManager::getSingleton().newCommandBuffer(p.m_secondLevelCmdbInitInfo);
-
-			ctx.m_commandBuffer = p.m_secondLevelCmdbs[threadIdx];
-			ctx.m_secondLevelCommandBufferCount = size;
-			ctx.m_passIdx = U32(&p - &m_ctx->m_passes[0]);
-			ctx.m_batchIdx = p.m_batchIdx;
+			RenderPassWorkContext* ctx = anki::newInstance<RenderPassWorkContext>(pool);
+			ctx->m_rgraph = this;
+			ctx->m_currentSecondLevelCommandBufferIndex = cmdIdx;
+			ctx->m_secondLevelCommandBufferCount = pass.m_secondLevelCmdbs.getSize();
+			ctx->m_passIdx = U32(&pass - &m_ctx->m_passes[0]);
+			ctx->m_batchIdx = pass.m_batchIdx;
+
+			CoreThreadJobManager::getSingleton().dispatchTask([ctx]([[maybe_unused]] U32 tid) {
+				ANKI_TRACE_SCOPED_EVENT(GrExecuteSecondaryCmdb);
+
+				// Create the command buffer in the thread
+				Pass& pass = ctx->m_rgraph->m_ctx->m_passes[ctx->m_passIdx];
+				ANKI_ASSERT(!pass.m_secondLevelCmdbs[ctx->m_currentSecondLevelCommandBufferIndex].isCreated());
+				pass.m_secondLevelCmdbs[ctx->m_currentSecondLevelCommandBufferIndex] =
+					GrManager::getSingleton().newCommandBuffer(pass.m_secondLevelCmdbInitInfo);
+				ctx->m_commandBuffer = pass.m_secondLevelCmdbs[ctx->m_currentSecondLevelCommandBufferIndex].get();
 
 
-			ANKI_ASSERT(ctx.m_commandBuffer.isCreated());
-
-			{
-				ANKI_TRACE_SCOPED_EVENT(GrRenderGraphCallback);
-				p.m_callback(ctx);
-			}
+				{
+					ANKI_TRACE_SCOPED_EVENT(GrRenderGraphCallback);
+					pass.m_callback(*ctx);
+				}
 
 
-			ctx.m_commandBuffer->flush();
+				ctx->m_commandBuffer->flush();
+			});
 		}
 		}
 	}
 	}
+
+	CoreThreadJobManager::getSingleton().waitForAllTasksToFinish();
 }
 }
 
 
 void RenderGraph::run() const
 void RenderGraph::run() const
@@ -1306,8 +1301,8 @@ void RenderGraph::run() const
 
 
 	for(const Batch& batch : m_ctx->m_batches)
 	for(const Batch& batch : m_ctx->m_batches)
 	{
 	{
-		ctx.m_commandBuffer.reset(batch.m_cmdb);
-		CommandBufferPtr& cmdb = ctx.m_commandBuffer;
+		ctx.m_commandBuffer = batch.m_cmdb;
+		CommandBuffer& cmdb = *ctx.m_commandBuffer;
 
 
 		// Set the barriers
 		// Set the barriers
 		DynamicArray<TextureBarrierInfo, MemoryPoolPtrWrapper<StackMemoryPool>> texBarriers(pool);
 		DynamicArray<TextureBarrierInfo, MemoryPoolPtrWrapper<StackMemoryPool>> texBarriers(pool);
@@ -1329,7 +1324,7 @@ void RenderGraph::run() const
 			inf.m_previousUsage = barrier.m_usageBefore;
 			inf.m_previousUsage = barrier.m_usageBefore;
 			inf.m_nextUsage = barrier.m_usageAfter;
 			inf.m_nextUsage = barrier.m_usageAfter;
 			inf.m_offset = m_ctx->m_buffers[barrier.m_idx].m_offset;
 			inf.m_offset = m_ctx->m_buffers[barrier.m_idx].m_offset;
-			inf.m_size = m_ctx->m_buffers[barrier.m_idx].m_range;
+			inf.m_range = m_ctx->m_buffers[barrier.m_idx].m_range;
 			inf.m_buffer = m_ctx->m_buffers[barrier.m_idx].m_buffer.get();
 			inf.m_buffer = m_ctx->m_buffers[barrier.m_idx].m_buffer.get();
 		}
 		}
 		DynamicArray<AccelerationStructureBarrierInfo, MemoryPoolPtrWrapper<StackMemoryPool>> asBarriers(pool);
 		DynamicArray<AccelerationStructureBarrierInfo, MemoryPoolPtrWrapper<StackMemoryPool>> asBarriers(pool);
@@ -1340,19 +1335,31 @@ void RenderGraph::run() const
 			inf.m_nextUsage = barrier.m_usageAfter;
 			inf.m_nextUsage = barrier.m_usageAfter;
 			inf.m_as = m_ctx->m_as[barrier.m_idx].m_as.get();
 			inf.m_as = m_ctx->m_as[barrier.m_idx].m_as.get();
 		}
 		}
-		cmdb->setPipelineBarrier(texBarriers, buffBarriers, asBarriers);
+
+		cmdb.pushDebugMarker("Barrier", Vec3(1.0f, 0.0f, 0.0f));
+		cmdb.setPipelineBarrier(texBarriers, buffBarriers, asBarriers);
+		cmdb.popDebugMarker();
 
 
 		// Call the passes
 		// Call the passes
 		for(U32 passIdx : batch.m_passIndices)
 		for(U32 passIdx : batch.m_passIndices)
 		{
 		{
 			const Pass& pass = m_ctx->m_passes[passIdx];
 			const Pass& pass = m_ctx->m_passes[passIdx];
 
 
-			if(pass.fb().isCreated())
+			Vec3 passColor;
+			if(pass.m_framebuffer)
 			{
 			{
-				cmdb->beginRenderPass(pass.fb(), pass.m_colorUsages, pass.m_dsUsage, pass.m_fbRenderArea[0],
-									  pass.m_fbRenderArea[1], pass.m_fbRenderArea[2], pass.m_fbRenderArea[3]);
+				cmdb.beginRenderPass(pass.m_framebuffer.get(), pass.m_colorUsages, pass.m_dsUsage, pass.m_fbRenderArea[0], pass.m_fbRenderArea[1],
+									 pass.m_fbRenderArea[2], pass.m_fbRenderArea[3]);
+
+				passColor = Vec3(0.0f, 1.0f, 0.0f);
+			}
+			else
+			{
+				passColor = Vec3(1.0f, 1.0f, 0.0f);
 			}
 			}
 
 
+			cmdb.pushDebugMarker(pass.m_name, passColor);
+
 			const U32 size = pass.m_secondLevelCmdbs.getSize();
 			const U32 size = pass.m_secondLevelCmdbs.getSize();
 			if(size == 0)
 			if(size == 0)
 			{
 			{
@@ -1370,18 +1377,20 @@ void RenderGraph::run() const
 				{
 				{
 					cmdbs.emplaceBack(cmdb2nd.get());
 					cmdbs.emplaceBack(cmdb2nd.get());
 				}
 				}
-				cmdb->pushSecondLevelCommandBuffers(cmdbs);
+				cmdb.pushSecondLevelCommandBuffers(cmdbs);
 			}
 			}
 
 
-			if(pass.fb().isCreated())
+			if(pass.m_framebuffer)
 			{
 			{
-				cmdb->endRenderPass();
+				cmdb.endRenderPass();
 			}
 			}
+
+			cmdb.popDebugMarker();
 		}
 		}
 	}
 	}
 }
 }
 
 
-void RenderGraph::flush()
+void RenderGraph::flush(FencePtr* optionalFence)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(GrRenderGraphFlush);
 	ANKI_TRACE_SCOPED_EVENT(GrRenderGraphFlush);
 
 
@@ -1394,19 +1403,18 @@ void RenderGraph::flush()
 			TimestampQueryPtr query = GrManager::getSingleton().newTimestampQuery();
 			TimestampQueryPtr query = GrManager::getSingleton().newTimestampQuery();
 			TimestampQuery* pQuery = query.get();
 			TimestampQuery* pQuery = query.get();
 			m_ctx->m_graphicsCmdbs[i]->resetTimestampQueries({&pQuery, 1});
 			m_ctx->m_graphicsCmdbs[i]->resetTimestampQueries({&pQuery, 1});
-			m_ctx->m_graphicsCmdbs[i]->writeTimestamp(query);
+			m_ctx->m_graphicsCmdbs[i]->writeTimestamp(pQuery);
 
 
 			m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2 + 1] = query;
 			m_statistics.m_timestamps[m_statistics.m_nextTimestamp * 2 + 1] = query;
 			m_statistics.m_cpuStartTimes[m_statistics.m_nextTimestamp] = HighRezTimer::getCurrentTime();
 			m_statistics.m_cpuStartTimes[m_statistics.m_nextTimestamp] = HighRezTimer::getCurrentTime();
 		}
 		}
 
 
 		// Flush
 		// Flush
-		m_ctx->m_graphicsCmdbs[i]->flush();
+		m_ctx->m_graphicsCmdbs[i]->flush({}, (i == m_ctx->m_graphicsCmdbs.getSize() - 1) ? optionalFence : nullptr);
 	}
 	}
 }
 }
 
 
-void RenderGraph::getCrntUsage(RenderTargetHandle handle, U32 batchIdx, const TextureSubresourceInfo& subresource,
-							   TextureUsageBit& usage) const
+void RenderGraph::getCrntUsage(RenderTargetHandle handle, U32 batchIdx, const TextureSubresourceInfo& subresource, TextureUsageBit& usage) const
 {
 {
 	usage = TextureUsageBit::kNone;
 	usage = TextureUsageBit::kNone;
 	const Batch& batch = m_ctx->m_batches[batchIdx];
 	const Batch& batch = m_ctx->m_batches[batchIdx];
@@ -1616,8 +1624,7 @@ StringRaii RenderGraph::asUsageToStr(StackMemoryPool& pool, AccelerationStructur
 	return str;
 	return str;
 }
 }
 
 
-Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, const BakeContext& ctx,
-										 CString path) const
+Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, const BakeContext& ctx, CString path) const
 {
 {
 	ANKI_GR_LOGW("Running with debug code");
 	ANKI_GR_LOGW("Running with debug code");
 
 
@@ -1643,9 +1650,8 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 		{
 		{
 			CString passName = descr.m_passes[passIdx]->m_name.toCString();
 			CString passName = descr.m_passes[passIdx]->m_name.toCString();
 
 
-			slist.pushBackSprintf(
-				"\t\"%s\"[color=%s,style=%s,shape=box];\n", passName.cstr(), COLORS[batchIdx % COLORS.getSize()],
-				(descr.m_passes[passIdx]->m_type == RenderPassDescriptionBase::Type::kGraphics) ? "bold" : "dashed");
+			slist.pushBackSprintf("\t\"%s\"[color=%s,style=%s,shape=box];\n", passName.cstr(), COLORS[batchIdx % COLORS.getSize()],
+								  (descr.m_passes[passIdx]->m_type == RenderPassDescriptionBase::Type::kGraphics) ? "bold" : "dashed");
 
 
 			for(U32 depIdx : ctx.m_passes[passIdx].m_dependsOn)
 			for(U32 depIdx : ctx.m_passes[passIdx].m_dependsOn)
 			{
 			{
@@ -1686,17 +1692,15 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 			const TextureBarrier& barrier = batch.m_textureBarriersBefore[barrierIdx];
 			const TextureBarrier& barrier = batch.m_textureBarriersBefore[barrierIdx];
 
 
 			StringRaii barrierLabel(&pool);
 			StringRaii barrierLabel(&pool);
-			barrierLabel.sprintf("<b>%s</b> (mip,dp,f,l)=(%u,%u,%u,%u)<br/>%s <b>to</b> %s",
-								 &descr.m_renderTargets[barrier.m_idx].m_name[0], barrier.m_surface.m_level,
-								 barrier.m_surface.m_depth, barrier.m_surface.m_face, barrier.m_surface.m_layer,
-								 textureUsageToStr(pool, barrier.m_usageBefore).cstr(),
-								 textureUsageToStr(pool, barrier.m_usageAfter).cstr());
+			barrierLabel.sprintf("<b>%s</b> (mip,dp,f,l)=(%u,%u,%u,%u)<br/>%s <b>to</b> %s", &descr.m_renderTargets[barrier.m_idx].m_name[0],
+								 barrier.m_surface.m_level, barrier.m_surface.m_depth, barrier.m_surface.m_face, barrier.m_surface.m_layer,
+								 textureUsageToStr(pool, barrier.m_usageBefore).cstr(), textureUsageToStr(pool, barrier.m_usageAfter).cstr());
 
 
 			StringRaii barrierName(&pool);
 			StringRaii barrierName(&pool);
 			barrierName.sprintf("%s tex barrier%u", batchName.cstr(), barrierIdx);
 			barrierName.sprintf("%s tex barrier%u", batchName.cstr(), barrierIdx);
 
 
-			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
-								  COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
+			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(), COLORS[batchIdx % COLORS.getSize()],
+								  barrierLabel.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 
 
 			prevBubble = barrierName;
 			prevBubble = barrierName;
@@ -1708,14 +1712,13 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 
 
 			StringRaii barrierLabel(&pool);
 			StringRaii barrierLabel(&pool);
 			barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", &descr.m_buffers[barrier.m_idx].m_name[0],
 			barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", &descr.m_buffers[barrier.m_idx].m_name[0],
-								 bufferUsageToStr(pool, barrier.m_usageBefore).cstr(),
-								 bufferUsageToStr(pool, barrier.m_usageAfter).cstr());
+								 bufferUsageToStr(pool, barrier.m_usageBefore).cstr(), bufferUsageToStr(pool, barrier.m_usageAfter).cstr());
 
 
 			StringRaii barrierName(&pool);
 			StringRaii barrierName(&pool);
 			barrierName.sprintf("%s buff barrier%u", batchName.cstr(), barrierIdx);
 			barrierName.sprintf("%s buff barrier%u", batchName.cstr(), barrierIdx);
 
 
-			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
-								  COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
+			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(), COLORS[batchIdx % COLORS.getSize()],
+								  barrierLabel.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 
 
 			prevBubble = barrierName;
 			prevBubble = barrierName;
@@ -1727,14 +1730,13 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 
 
 			StringRaii barrierLabel(&pool);
 			StringRaii barrierLabel(&pool);
 			barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", descr.m_as[barrier.m_idx].m_name.getBegin(),
 			barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s", descr.m_as[barrier.m_idx].m_name.getBegin(),
-								 asUsageToStr(pool, barrier.m_usageBefore).cstr(),
-								 asUsageToStr(pool, barrier.m_usageAfter).cstr());
+								 asUsageToStr(pool, barrier.m_usageBefore).cstr(), asUsageToStr(pool, barrier.m_usageAfter).cstr());
 
 
 			StringRaii barrierName(&pool);
 			StringRaii barrierName(&pool);
 			barrierName.sprintf("%s AS barrier%u", batchName.cstr(), barrierIdx);
 			barrierName.sprintf("%s AS barrier%u", batchName.cstr(), barrierIdx);
 
 
-			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(),
-								  COLORS[batchIdx % COLORS.getSize()], barrierLabel.cstr());
+			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n", barrierName.cstr(), COLORS[batchIdx % COLORS.getSize()],
+								  barrierLabel.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 
 
 			prevBubble = barrierName;
 			prevBubble = barrierName;
@@ -1745,8 +1747,7 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 			const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
 			const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
 			StringRaii passName(&pool);
 			StringRaii passName(&pool);
 			passName.sprintf("%s pass", pass.m_name.cstr());
 			passName.sprintf("%s pass", pass.m_name.cstr());
-			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold];\n", passName.cstr(),
-								  COLORS[batchIdx % COLORS.getSize()]);
+			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold];\n", passName.cstr(), COLORS[batchIdx % COLORS.getSize()]);
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), passName.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), passName.cstr());
 
 
 			prevBubble = passName;
 			prevBubble = passName;
@@ -1757,8 +1758,7 @@ Error RenderGraph::dumpDependencyDotFile(const RenderGraphDescription& descr, co
 	slist.pushBackSprintf("}");
 	slist.pushBackSprintf("}");
 
 
 	File file;
 	File file;
-	ANKI_CHECK(file.open(StringRaii(&pool).sprintf("%s/rgraph_%05u.dot", &path[0], m_version).toCString(),
-						 FileOpenFlag::kWrite));
+	ANKI_CHECK(file.open(StringRaii(&pool).sprintf("%s/rgraph_%05u.dot", &path[0], m_version).toCString(), FileOpenFlag::kWrite));
 	for(const String& s : slist)
 	for(const String& s : slist)
 	{
 	{
 		ANKI_CHECK(file.writeTextf("%s", &s[0]));
 		ANKI_CHECK(file.writeTextf("%s", &s[0]));

+ 69 - 75
AnKi/Gr/RenderGraph.h

@@ -29,9 +29,9 @@ class RenderGraphDescription;
 
 
 /// @name RenderGraph constants
 /// @name RenderGraph constants
 /// @{
 /// @{
-constexpr U32 kMaxRenderGraphPasses = 128;
+constexpr U32 kMaxRenderGraphPasses = 256;
 constexpr U32 kMaxRenderGraphRenderTargets = 64; ///< Max imported or not render targets in RenderGraph.
 constexpr U32 kMaxRenderGraphRenderTargets = 64; ///< Max imported or not render targets in RenderGraph.
-constexpr U32 kMaxRenderGraphBuffers = 64;
+constexpr U32 kMaxRenderGraphBuffers = 256;
 constexpr U32 kMaxRenderGraphAccelerationStructures = 32;
 constexpr U32 kMaxRenderGraphAccelerationStructures = 32;
 /// @}
 /// @}
 
 
@@ -117,106 +117,104 @@ class RenderPassWorkContext
 	friend class RenderGraph;
 	friend class RenderGraph;
 
 
 public:
 public:
-	CommandBufferPtr m_commandBuffer;
-	U32 m_currentSecondLevelCommandBufferIndex ANKI_DEBUG_CODE(= 0);
-	U32 m_secondLevelCommandBufferCount ANKI_DEBUG_CODE(= 0);
+	CommandBuffer* m_commandBuffer = nullptr;
+	U32 m_currentSecondLevelCommandBufferIndex = 0;
+	U32 m_secondLevelCommandBufferCount = 0;
 
 
-	void getBufferState(BufferHandle handle, BufferPtr& buff) const;
+	void getBufferState(BufferHandle handle, Buffer*& buff, PtrSize& offset, PtrSize& range) const;
 
 
-	void getRenderTargetState(RenderTargetHandle handle, const TextureSubresourceInfo& subresource,
-							  TexturePtr& tex) const;
+	void getRenderTargetState(RenderTargetHandle handle, const TextureSubresourceInfo& subresource, Texture*& tex) const;
 
 
 	/// Create a whole texture view from a handle
 	/// Create a whole texture view from a handle
 	TextureViewPtr createTextureView(RenderTargetHandle handle)
 	TextureViewPtr createTextureView(RenderTargetHandle handle)
 	{
 	{
-		TexturePtr tex = getTexture(handle);
+		Texture* tex = &getTexture(handle);
 		TextureViewInitInfo viewInit(tex, "TmpRenderGraph"); // Use the whole texture
 		TextureViewInitInfo viewInit(tex, "TmpRenderGraph"); // Use the whole texture
 		getRenderTargetState(handle, viewInit, tex);
 		getRenderTargetState(handle, viewInit, tex);
 		return GrManager::getSingleton().newTextureView(viewInit);
 		return GrManager::getSingleton().newTextureView(viewInit);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
-	void bindTextureAndSampler(U32 set, U32 binding, RenderTargetHandle handle,
-							   const TextureSubresourceInfo& subresource, const SamplerPtr& sampler)
+	void bindTextureAndSampler(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource, Sampler* sampler)
 	{
 	{
-		TexturePtr tex;
+		Texture* tex;
 		getRenderTargetState(handle, subresource, tex);
 		getRenderTargetState(handle, subresource, tex);
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindTextureAndSampler(set, binding, view, sampler);
+		m_commandBuffer->bindTextureAndSampler(set, binding, view.get(), sampler);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
 	void bindTexture(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource)
 	void bindTexture(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource)
 	{
 	{
-		TexturePtr tex;
+		Texture* tex;
 		getRenderTargetState(handle, subresource, tex);
 		getRenderTargetState(handle, subresource, tex);
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindTexture(set, binding, view);
+		m_commandBuffer->bindTexture(set, binding, view.get());
 	}
 	}
 
 
 	/// Convenience method to bind the whole texture as color.
 	/// Convenience method to bind the whole texture as color.
-	void bindColorTextureAndSampler(U32 set, U32 binding, RenderTargetHandle handle, const SamplerPtr& sampler)
+	void bindColorTextureAndSampler(U32 set, U32 binding, RenderTargetHandle handle, Sampler* sampler)
 	{
 	{
-		TexturePtr tex = getTexture(handle);
+		Texture* tex = &getTexture(handle);
 		TextureViewInitInfo viewInit(tex); // Use the whole texture
 		TextureViewInitInfo viewInit(tex); // Use the whole texture
 		getRenderTargetState(handle, viewInit, tex);
 		getRenderTargetState(handle, viewInit, tex);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindTextureAndSampler(set, binding, view, sampler);
+		m_commandBuffer->bindTextureAndSampler(set, binding, view.get(), sampler);
 	}
 	}
 
 
 	/// Convenience method to bind the whole texture as color.
 	/// Convenience method to bind the whole texture as color.
 	void bindColorTexture(U32 set, U32 binding, RenderTargetHandle handle, U32 arrayIdx = 0)
 	void bindColorTexture(U32 set, U32 binding, RenderTargetHandle handle, U32 arrayIdx = 0)
 	{
 	{
-		TexturePtr tex = getTexture(handle);
+		Texture* tex = &getTexture(handle);
 		TextureViewInitInfo viewInit(tex); // Use the whole texture
 		TextureViewInitInfo viewInit(tex); // Use the whole texture
 		getRenderTargetState(handle, viewInit, tex);
 		getRenderTargetState(handle, viewInit, tex);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindTexture(set, binding, view, arrayIdx);
+		m_commandBuffer->bindTexture(set, binding, view.get(), arrayIdx);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
-	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource,
-				   U32 arrayIdx = 0)
+	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource, U32 arrayIdx = 0)
 	{
 	{
-		TexturePtr tex;
+		Texture* tex;
 		getRenderTargetState(handle, subresource, tex);
 		getRenderTargetState(handle, subresource, tex);
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindImage(set, binding, view, arrayIdx);
+		m_commandBuffer->bindImage(set, binding, view.get(), arrayIdx);
 	}
 	}
 
 
 	/// Convenience method to bind the whole image.
 	/// Convenience method to bind the whole image.
 	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, U32 arrayIdx = 0)
 	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, U32 arrayIdx = 0)
 	{
 	{
-		TexturePtr tex;
-#if ANKI_ENABLE_ASSERTIONS
-		tex = getTexture(handle);
-		ANKI_ASSERT(tex->getLayerCount() == 1 && tex->getMipmapCount() == 1
-					&& tex->getDepthStencilAspect() == DepthStencilAspectBit::kNone);
+		Texture* tex;
+#if ANKI_ASSERTIONS_ENABLED
+		tex = &getTexture(handle);
+		ANKI_ASSERT(tex->getLayerCount() == 1 && tex->getMipmapCount() == 1 && tex->getDepthStencilAspect() == DepthStencilAspectBit::kNone);
 #endif
 #endif
 		const TextureSubresourceInfo subresource;
 		const TextureSubresourceInfo subresource;
 		getRenderTargetState(handle, subresource, tex);
 		getRenderTargetState(handle, subresource, tex);
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
 		TextureViewPtr view = GrManager::getSingleton().newTextureView(viewInit);
-		m_commandBuffer->bindImage(set, binding, view, arrayIdx);
+		m_commandBuffer->bindImage(set, binding, view.get(), arrayIdx);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
 	void bindStorageBuffer(U32 set, U32 binding, BufferHandle handle)
 	void bindStorageBuffer(U32 set, U32 binding, BufferHandle handle)
 	{
 	{
-		BufferPtr buff;
-		getBufferState(handle, buff);
-		m_commandBuffer->bindStorageBuffer(set, binding, buff, 0, kMaxPtrSize);
+		Buffer* buff;
+		PtrSize offset, range;
+		getBufferState(handle, buff, offset, range);
+		m_commandBuffer->bindStorageBuffer(set, binding, buff, offset, range);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
 	void bindUniformBuffer(U32 set, U32 binding, BufferHandle handle)
 	void bindUniformBuffer(U32 set, U32 binding, BufferHandle handle)
 	{
 	{
-		BufferPtr buff;
-		getBufferState(handle, buff);
-		m_commandBuffer->bindUniformBuffer(set, binding, buff, 0, kMaxPtrSize);
+		Buffer* buff;
+		PtrSize offset, range;
+		getBufferState(handle, buff, offset, range);
+		m_commandBuffer->bindUniformBuffer(set, binding, buff, offset, range);
 	}
 	}
 
 
 	/// Convenience method.
 	/// Convenience method.
@@ -227,7 +225,7 @@ private:
 	U32 m_passIdx ANKI_DEBUG_CODE(= kMaxU32);
 	U32 m_passIdx ANKI_DEBUG_CODE(= kMaxU32);
 	U32 m_batchIdx ANKI_DEBUG_CODE(= kMaxU32);
 	U32 m_batchIdx ANKI_DEBUG_CODE(= kMaxU32);
 
 
-	TexturePtr getTexture(RenderTargetHandle handle) const;
+	Texture& getTexture(RenderTargetHandle handle) const;
 };
 };
 
 
 /// RenderGraph pass dependency.
 /// RenderGraph pass dependency.
@@ -247,8 +245,7 @@ public:
 	}
 	}
 
 
 	/// Dependency to the whole texture.
 	/// Dependency to the whole texture.
-	RenderPassDependency(RenderTargetHandle handle, TextureUsageBit usage,
-						 DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
+	RenderPassDependency(RenderTargetHandle handle, TextureUsageBit usage, DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
 		: m_texture({handle, usage, TextureSubresourceInfo()})
 		: m_texture({handle, usage, TextureSubresourceInfo()})
 		, m_type(Type::kTexture)
 		, m_type(Type::kTexture)
 	{
 	{
@@ -333,14 +330,12 @@ public:
 		setWork(0, func);
 		setWork(0, func);
 	}
 	}
 
 
-	void newTextureDependency(RenderTargetHandle handle, TextureUsageBit usage,
-							  const TextureSubresourceInfo& subresource)
+	void newTextureDependency(RenderTargetHandle handle, TextureUsageBit usage, const TextureSubresourceInfo& subresource)
 	{
 	{
 		newDependency<RenderPassDependency::Type::kTexture>(RenderPassDependency(handle, usage, subresource));
 		newDependency<RenderPassDependency::Type::kTexture>(RenderPassDependency(handle, usage, subresource));
 	}
 	}
 
 
-	void newTextureDependency(RenderTargetHandle handle, TextureUsageBit usage,
-							  DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
+	void newTextureDependency(RenderTargetHandle handle, TextureUsageBit usage, DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone)
 	{
 	{
 		newDependency<RenderPassDependency::Type::kTexture>(RenderPassDependency(handle, usage, aspect));
 		newDependency<RenderPassDependency::Type::kTexture>(RenderPassDependency(handle, usage, aspect));
 	}
 	}
@@ -463,17 +458,13 @@ public:
 		memset(&m_rtHandles[0], 0xFF, sizeof(m_rtHandles));
 		memset(&m_rtHandles[0], 0xFF, sizeof(m_rtHandles));
 	}
 	}
 
 
-	void setFramebufferInfo(const FramebufferDescription& fbInfo,
-							ConstWeakArray<RenderTargetHandle> colorRenderTargetHandles,
-							RenderTargetHandle depthStencilRenderTargetHandle = {},
-							RenderTargetHandle shadingRateRenderTargetHandle = {}, U32 minx = 0, U32 miny = 0,
-							U32 maxx = kMaxU32, U32 maxy = kMaxU32);
+	void setFramebufferInfo(const FramebufferDescription& fbInfo, ConstWeakArray<RenderTargetHandle> colorRenderTargetHandles,
+							RenderTargetHandle depthStencilRenderTargetHandle = {}, RenderTargetHandle shadingRateRenderTargetHandle = {},
+							U32 minx = 0, U32 miny = 0, U32 maxx = kMaxU32, U32 maxy = kMaxU32);
 
 
-	void setFramebufferInfo(const FramebufferDescription& fbInfo,
-							std::initializer_list<RenderTargetHandle> colorRenderTargetHandles,
-							RenderTargetHandle depthStencilRenderTargetHandle = {},
-							RenderTargetHandle shadingRateRenderTargetHandle = {}, U32 minx = 0, U32 miny = 0,
-							U32 maxx = kMaxU32, U32 maxy = kMaxU32);
+	void setFramebufferInfo(const FramebufferDescription& fbInfo, std::initializer_list<RenderTargetHandle> colorRenderTargetHandles,
+							RenderTargetHandle depthStencilRenderTargetHandle = {}, RenderTargetHandle shadingRateRenderTargetHandle = {},
+							U32 minx = 0, U32 miny = 0, U32 maxx = kMaxU32, U32 maxy = kMaxU32);
 
 
 private:
 private:
 	Array<RenderTargetHandle, kMaxColorRenderTargets + 2> m_rtHandles;
 	Array<RenderTargetHandle, kMaxColorRenderTargets + 2> m_rtHandles;
@@ -521,21 +512,25 @@ public:
 	ComputeRenderPassDescription& newComputeRenderPass(CString name);
 	ComputeRenderPassDescription& newComputeRenderPass(CString name);
 
 
 	/// Import an existing render target and let the render graph know about it's up-to-date usage.
 	/// Import an existing render target and let the render graph know about it's up-to-date usage.
-	RenderTargetHandle importRenderTarget(TexturePtr tex, TextureUsageBit usage);
+	RenderTargetHandle importRenderTarget(Texture* tex, TextureUsageBit usage);
 
 
-	/// Import an existing render target and let the render graph find it's current usage by looking at the previous
-	/// frame.
-	RenderTargetHandle importRenderTarget(TexturePtr tex);
+	/// Import an existing render target and let the render graph find it's current usage by looking at the previous frame.
+	RenderTargetHandle importRenderTarget(Texture* tex);
 
 
 	/// Get or create a new render target.
 	/// Get or create a new render target.
 	RenderTargetHandle newRenderTarget(const RenderTargetDescription& initInf);
 	RenderTargetHandle newRenderTarget(const RenderTargetDescription& initInf);
 
 
 	/// Import a buffer.
 	/// Import a buffer.
-	BufferHandle importBuffer(BufferPtr buff, BufferUsageBit usage, PtrSize offset = 0, PtrSize range = kMaxPtrSize);
+	BufferHandle importBuffer(Buffer* buff, BufferUsageBit usage, PtrSize offset = 0, PtrSize range = kMaxPtrSize);
+
+	/// Import a buffer.
+	BufferHandle importBuffer(BufferUsageBit usage, const BufferOffsetRange& buff)
+	{
+		return importBuffer(buff.m_buffer, usage, buff.m_offset, buff.m_range);
+	}
 
 
 	/// Import an AS.
 	/// Import an AS.
-	AccelerationStructureHandle importAccelerationStructure(AccelerationStructurePtr as,
-															AccelerationStructureUsageBit usage);
+	AccelerationStructureHandle importAccelerationStructure(AccelerationStructure* as, AccelerationStructureUsageBit usage);
 
 
 	/// Gather statistics.
 	/// Gather statistics.
 	void setStatisticsEnabled(Bool gather)
 	void setStatisticsEnabled(Bool gather)
@@ -569,7 +564,7 @@ private:
 		Bool m_importedAndUndefinedUsage = false;
 		Bool m_importedAndUndefinedUsage = false;
 	};
 	};
 
 
-	class Buffer : public Resource
+	class BufferRsrc : public Resource
 	{
 	{
 	public:
 	public:
 		BufferUsageBit m_usage;
 		BufferUsageBit m_usage;
@@ -588,7 +583,7 @@ private:
 	StackMemoryPool* m_pool = nullptr;
 	StackMemoryPool* m_pool = nullptr;
 	DynamicArray<RenderPassDescriptionBase*, MemoryPoolPtrWrapper<StackMemoryPool>> m_passes{m_pool};
 	DynamicArray<RenderPassDescriptionBase*, MemoryPoolPtrWrapper<StackMemoryPool>> m_passes{m_pool};
 	DynamicArray<RT, MemoryPoolPtrWrapper<StackMemoryPool>> m_renderTargets{m_pool};
 	DynamicArray<RT, MemoryPoolPtrWrapper<StackMemoryPool>> m_renderTargets{m_pool};
-	DynamicArray<Buffer, MemoryPoolPtrWrapper<StackMemoryPool>> m_buffers{m_pool};
+	DynamicArray<BufferRsrc, MemoryPoolPtrWrapper<StackMemoryPool>> m_buffers{m_pool};
 	DynamicArray<AS, MemoryPoolPtrWrapper<StackMemoryPool>> m_as{m_pool};
 	DynamicArray<AS, MemoryPoolPtrWrapper<StackMemoryPool>> m_as{m_pool};
 	Bool m_gatherStatistics = false;
 	Bool m_gatherStatistics = false;
 
 
@@ -602,11 +597,11 @@ private:
 		}
 		}
 		else if(offsetA <= offsetB)
 		else if(offsetA <= offsetB)
 		{
 		{
-			return offsetA + rangeA >= offsetB;
+			return offsetA + rangeA > offsetB;
 		}
 		}
 		else
 		else
 		{
 		{
-			return offsetB + rangeB >= offsetA;
+			return offsetB + rangeB > offsetA;
 		}
 		}
 	}
 	}
 };
 };
@@ -648,7 +643,7 @@ public:
 	/// @{
 	/// @{
 
 
 	/// Will call a number of RenderPassWorkCallback that populate 2nd level command buffers.
 	/// Will call a number of RenderPassWorkCallback that populate 2nd level command buffers.
-	void runSecondLevel(U32 threadIdx);
+	void runSecondLevel();
 	/// @}
 	/// @}
 
 
 	/// @name 3rd step methods
 	/// @name 3rd step methods
@@ -660,7 +655,7 @@ public:
 
 
 	/// @name 3rd step methods
 	/// @name 3rd step methods
 	/// @{
 	/// @{
-	void flush();
+	void flush(FencePtr* optionalFence = nullptr);
 	/// @}
 	/// @}
 
 
 	/// @name 4th step methods
 	/// @name 4th step methods
@@ -685,7 +680,7 @@ private:
 	class Pass;
 	class Pass;
 	class Batch;
 	class Batch;
 	class RT;
 	class RT;
-	class Buffer;
+	class BufferRange;
 	class AS;
 	class AS;
 	class TextureBarrier;
 	class TextureBarrier;
 	class BufferBarrier;
 	class BufferBarrier;
@@ -735,8 +730,8 @@ private:
 	void setBatchBarriers(const RenderGraphDescription& descr);
 	void setBatchBarriers(const RenderGraphDescription& descr);
 
 
 	TexturePtr getOrCreateRenderTarget(const TextureInitInfo& initInf, U64 hash);
 	TexturePtr getOrCreateRenderTarget(const TextureInitInfo& initInf, U64 hash);
-	FramebufferPtr getOrCreateFramebuffer(const FramebufferDescription& fbDescr, const RenderTargetHandle* rtHandles,
-										  CString name, Bool& drawsToPresentableTex);
+	FramebufferPtr getOrCreateFramebuffer(const FramebufferDescription& fbDescr, const RenderTargetHandle* rtHandles, CString name,
+										  Bool& drawsToPresentableTex);
 
 
 	/// Every N number of frames clean unused cached items.
 	/// Every N number of frames clean unused cached items.
 	void periodicCleanup();
 	void periodicCleanup();
@@ -750,10 +745,9 @@ private:
 	void setTextureBarrier(Batch& batch, const RenderPassDependency& consumer);
 	void setTextureBarrier(Batch& batch, const RenderPassDependency& consumer);
 
 
 	template<typename TFunc>
 	template<typename TFunc>
-	static void iterateSurfsOrVolumes(const TexturePtr& tex, const TextureSubresourceInfo& subresource, TFunc func);
+	static void iterateSurfsOrVolumes(const Texture& tex, const TextureSubresourceInfo& subresource, TFunc func);
 
 
-	void getCrntUsage(RenderTargetHandle handle, U32 batchIdx, const TextureSubresourceInfo& subresource,
-					  TextureUsageBit& usage) const;
+	void getCrntUsage(RenderTargetHandle handle, U32 batchIdx, const TextureSubresourceInfo& subresource, TextureUsageBit& usage) const;
 
 
 	/// @name Dump the dependency graph into a file.
 	/// @name Dump the dependency graph into a file.
 	/// @{
 	/// @{
@@ -763,9 +757,9 @@ private:
 	static GrString asUsageToStr(StackMemoryPool& pool, AccelerationStructureUsageBit usage);
 	static GrString asUsageToStr(StackMemoryPool& pool, AccelerationStructureUsageBit usage);
 	/// @}
 	/// @}
 
 
-	TexturePtr getTexture(RenderTargetHandle handle) const;
-	BufferPtr getBuffer(BufferHandle handle) const;
-	AccelerationStructurePtr getAs(AccelerationStructureHandle handle) const;
+	Texture& getTexture(RenderTargetHandle handle) const;
+	void getCachedBuffer(BufferHandle handle, Buffer*& buff, PtrSize& offset, PtrSize& range) const;
+	AccelerationStructure* getAs(AccelerationStructureHandle handle) const;
 };
 };
 /// @}
 /// @}
 
 

+ 35 - 36
AnKi/Gr/RenderGraph.inl.h

@@ -12,21 +12,19 @@ inline void RenderPassWorkContext::bindAccelerationStructure(U32 set, U32 bindin
 	m_commandBuffer->bindAccelerationStructure(set, binding, m_rgraph->getAs(handle));
 	m_commandBuffer->bindAccelerationStructure(set, binding, m_rgraph->getAs(handle));
 }
 }
 
 
-inline void RenderPassWorkContext::getBufferState(BufferHandle handle, BufferPtr& buff) const
+inline void RenderPassWorkContext::getBufferState(BufferHandle handle, Buffer*& buff, PtrSize& offset, PtrSize& range) const
 {
 {
-	buff = m_rgraph->getBuffer(handle);
+	m_rgraph->getCachedBuffer(handle, buff, offset, range);
 }
 }
 
 
-inline void RenderPassWorkContext::getRenderTargetState(RenderTargetHandle handle,
-														const TextureSubresourceInfo& subresource,
-														TexturePtr& tex) const
+inline void RenderPassWorkContext::getRenderTargetState(RenderTargetHandle handle, const TextureSubresourceInfo& subresource, Texture*& tex) const
 {
 {
 	TextureUsageBit usage;
 	TextureUsageBit usage;
 	m_rgraph->getCrntUsage(handle, m_batchIdx, subresource, usage);
 	m_rgraph->getCrntUsage(handle, m_batchIdx, subresource, usage);
-	tex = m_rgraph->getTexture(handle);
+	tex = &m_rgraph->getTexture(handle);
 }
 }
 
 
-inline TexturePtr RenderPassWorkContext::getTexture(RenderTargetHandle handle) const
+inline Texture& RenderPassWorkContext::getTexture(RenderTargetHandle handle) const
 {
 {
 	return m_rgraph->getTexture(handle);
 	return m_rgraph->getTexture(handle);
 }
 }
@@ -145,7 +143,7 @@ inline void RenderPassDescriptionBase::newDependency(const RenderPassDependency&
 		m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx].m_usageDerivedByDeps |= dep.m_texture.m_usage;
 		m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx].m_usageDerivedByDeps |= dep.m_texture.m_usage;
 
 
 		// Checks
 		// Checks
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 		const RenderGraphDescription::RT& rt = m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx];
 		const RenderGraphDescription::RT& rt = m_descr->m_renderTargets[dep.m_texture.m_handle.m_idx];
 		if((!rt.m_importedTex.isCreated() && !!getFormatInfo(rt.m_initInfo.m_format).m_depthStencil)
 		if((!rt.m_importedTex.isCreated() && !!getFormatInfo(rt.m_initInfo.m_format).m_depthStencil)
 		   || (rt.m_importedTex.isCreated() && !!rt.m_importedTex->getDepthStencilAspect()))
 		   || (rt.m_importedTex.isCreated() && !!rt.m_importedTex->getDepthStencilAspect()))
@@ -157,6 +155,8 @@ inline void RenderPassDescriptionBase::newDependency(const RenderPassDependency&
 	}
 	}
 	else if(kType == RenderPassDependency::Type::kBuffer)
 	else if(kType == RenderPassDependency::Type::kBuffer)
 	{
 	{
+		ANKI_ASSERT(!!(m_descr->m_buffers[dep.m_buffer.m_handle.m_idx].m_importedBuff->getBufferUsage() & dep.m_buffer.m_usage));
+
 		m_buffDeps.emplaceBack(dep);
 		m_buffDeps.emplaceBack(dep);
 
 
 		if(!!(dep.m_buffer.m_usage & BufferUsageBit::kAllRead))
 		if(!!(dep.m_buffer.m_usage & BufferUsageBit::kAllRead))
@@ -186,10 +186,11 @@ inline void RenderPassDescriptionBase::newDependency(const RenderPassDependency&
 	}
 	}
 }
 }
 
 
-inline void GraphicsRenderPassDescription::setFramebufferInfo(
-	const FramebufferDescription& fbInfo, std::initializer_list<RenderTargetHandle> colorRenderTargetHandles,
-	RenderTargetHandle depthStencilRenderTargetHandle, RenderTargetHandle shadingRateRenderTargetHandle, U32 minx,
-	U32 miny, U32 maxx, U32 maxy)
+inline void GraphicsRenderPassDescription::setFramebufferInfo(const FramebufferDescription& fbInfo,
+															  std::initializer_list<RenderTargetHandle> colorRenderTargetHandles,
+															  RenderTargetHandle depthStencilRenderTargetHandle,
+															  RenderTargetHandle shadingRateRenderTargetHandle, U32 minx, U32 miny, U32 maxx,
+															  U32 maxy)
 {
 {
 	Array<RenderTargetHandle, kMaxColorRenderTargets> rts;
 	Array<RenderTargetHandle, kMaxColorRenderTargets> rts;
 	U32 count = 0;
 	U32 count = 0;
@@ -197,16 +198,17 @@ inline void GraphicsRenderPassDescription::setFramebufferInfo(
 	{
 	{
 		rts[count++] = h;
 		rts[count++] = h;
 	}
 	}
-	setFramebufferInfo(fbInfo, ConstWeakArray<RenderTargetHandle>(&rts[0], count), depthStencilRenderTargetHandle,
-					   shadingRateRenderTargetHandle, minx, miny, maxx, maxy);
+	setFramebufferInfo(fbInfo, ConstWeakArray<RenderTargetHandle>(&rts[0], count), depthStencilRenderTargetHandle, shadingRateRenderTargetHandle,
+					   minx, miny, maxx, maxy);
 }
 }
 
 
-inline void GraphicsRenderPassDescription::setFramebufferInfo(
-	const FramebufferDescription& fbInfo, ConstWeakArray<RenderTargetHandle> colorRenderTargetHandles,
-	RenderTargetHandle depthStencilRenderTargetHandle, RenderTargetHandle shadingRateRenderTargetHandle, U32 minx,
-	U32 miny, U32 maxx, U32 maxy)
+inline void GraphicsRenderPassDescription::setFramebufferInfo(const FramebufferDescription& fbInfo,
+															  ConstWeakArray<RenderTargetHandle> colorRenderTargetHandles,
+															  RenderTargetHandle depthStencilRenderTargetHandle,
+															  RenderTargetHandle shadingRateRenderTargetHandle, U32 minx, U32 miny, U32 maxx,
+															  U32 maxy)
 {
 {
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	ANKI_ASSERT(fbInfo.isBacked() && "Forgot call GraphicsRenderPassFramebufferInfo::bake");
 	ANKI_ASSERT(fbInfo.isBacked() && "Forgot call GraphicsRenderPassFramebufferInfo::bake");
 	for(U32 i = 0; i < colorRenderTargetHandles.getSize(); ++i)
 	for(U32 i = 0; i < colorRenderTargetHandles.getSize(); ++i)
 	{
 	{
@@ -270,15 +272,15 @@ inline ComputeRenderPassDescription& RenderGraphDescription::newComputeRenderPas
 	return *pass;
 	return *pass;
 }
 }
 
 
-inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr tex, TextureUsageBit usage)
+inline RenderTargetHandle RenderGraphDescription::importRenderTarget(Texture* tex, TextureUsageBit usage)
 {
 {
 	for([[maybe_unused]] const RT& rt : m_renderTargets)
 	for([[maybe_unused]] const RT& rt : m_renderTargets)
 	{
 	{
-		ANKI_ASSERT(rt.m_importedTex != tex && "Already imported");
+		ANKI_ASSERT(rt.m_importedTex.tryGet() != tex && "Already imported");
 	}
 	}
 
 
 	RT& rt = *m_renderTargets.emplaceBack();
 	RT& rt = *m_renderTargets.emplaceBack();
-	rt.m_importedTex = tex;
+	rt.m_importedTex.reset(tex);
 	rt.m_importedLastKnownUsage = usage;
 	rt.m_importedLastKnownUsage = usage;
 	rt.m_usageDerivedByDeps = TextureUsageBit::kNone;
 	rt.m_usageDerivedByDeps = TextureUsageBit::kNone;
 	rt.setName(tex->getName());
 	rt.setName(tex->getName());
@@ -288,7 +290,7 @@ inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr
 	return out;
 	return out;
 }
 }
 
 
-inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr tex)
+inline RenderTargetHandle RenderGraphDescription::importRenderTarget(Texture* tex)
 {
 {
 	RenderTargetHandle out = importRenderTarget(tex, TextureUsageBit::kNone);
 	RenderTargetHandle out = importRenderTarget(tex, TextureUsageBit::kNone);
 	m_renderTargets.getBack().m_importedAndUndefinedUsage = true;
 	m_renderTargets.getBack().m_importedAndUndefinedUsage = true;
@@ -298,8 +300,7 @@ inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr
 inline RenderTargetHandle RenderGraphDescription::newRenderTarget(const RenderTargetDescription& initInf)
 inline RenderTargetHandle RenderGraphDescription::newRenderTarget(const RenderTargetDescription& initInf)
 {
 {
 	ANKI_ASSERT(initInf.m_hash && "Forgot to call RenderTargetDescription::bake");
 	ANKI_ASSERT(initInf.m_hash && "Forgot to call RenderTargetDescription::bake");
-	ANKI_ASSERT(initInf.m_usage == TextureUsageBit::kNone
-				&& "Don't need to supply the usage. Render grap will find it");
+	ANKI_ASSERT(initInf.m_usage == TextureUsageBit::kNone && "Don't need to supply the usage. Render grap will find it");
 	RT& rt = *m_renderTargets.emplaceBack();
 	RT& rt = *m_renderTargets.emplaceBack();
 	rt.m_initInfo = initInf;
 	rt.m_initInfo = initInf;
 	rt.m_hash = initInf.m_hash;
 	rt.m_hash = initInf.m_hash;
@@ -312,10 +313,10 @@ inline RenderTargetHandle RenderGraphDescription::newRenderTarget(const RenderTa
 	return out;
 	return out;
 }
 }
 
 
-inline BufferHandle RenderGraphDescription::importBuffer(BufferPtr buff, BufferUsageBit usage, PtrSize offset,
-														 PtrSize range)
+inline BufferHandle RenderGraphDescription::importBuffer(Buffer* buff, BufferUsageBit usage, PtrSize offset, PtrSize range)
 {
 {
 	// Checks
 	// Checks
+	ANKI_ASSERT(buff);
 	if(range == kMaxPtrSize)
 	if(range == kMaxPtrSize)
 	{
 	{
 		ANKI_ASSERT(offset < buff->getSize());
 		ANKI_ASSERT(offset < buff->getSize());
@@ -327,16 +328,15 @@ inline BufferHandle RenderGraphDescription::importBuffer(BufferPtr buff, BufferU
 
 
 	ANKI_ASSERT(range > 0);
 	ANKI_ASSERT(range > 0);
 
 
-	for([[maybe_unused]] const Buffer& bb : m_buffers)
+	for([[maybe_unused]] const BufferRsrc& bb : m_buffers)
 	{
 	{
-		ANKI_ASSERT((bb.m_importedBuff != buff || !bufferRangeOverlaps(bb.m_offset, bb.m_range, offset, range))
-					&& "Range already imported");
+		ANKI_ASSERT((bb.m_importedBuff.get() != buff || !bufferRangeOverlaps(bb.m_offset, bb.m_range, offset, range)) && "Range already imported");
 	}
 	}
 
 
-	Buffer& b = *m_buffers.emplaceBack();
+	BufferRsrc& b = *m_buffers.emplaceBack();
 	b.setName(buff->getName());
 	b.setName(buff->getName());
 	b.m_usage = usage;
 	b.m_usage = usage;
-	b.m_importedBuff = std::move(buff);
+	b.m_importedBuff.reset(buff);
 	b.m_offset = offset;
 	b.m_offset = offset;
 	b.m_range = range;
 	b.m_range = range;
 
 
@@ -345,17 +345,16 @@ inline BufferHandle RenderGraphDescription::importBuffer(BufferPtr buff, BufferU
 	return out;
 	return out;
 }
 }
 
 
-inline AccelerationStructureHandle
-RenderGraphDescription::importAccelerationStructure(AccelerationStructurePtr as, AccelerationStructureUsageBit usage)
+inline AccelerationStructureHandle RenderGraphDescription::importAccelerationStructure(AccelerationStructure* as, AccelerationStructureUsageBit usage)
 {
 {
 	for([[maybe_unused]] const AS& a : m_as)
 	for([[maybe_unused]] const AS& a : m_as)
 	{
 	{
-		ANKI_ASSERT(a.m_importedAs != as && "Already imported");
+		ANKI_ASSERT(a.m_importedAs.get() != as && "Already imported");
 	}
 	}
 
 
 	AS& a = *m_as.emplaceBack();
 	AS& a = *m_as.emplaceBack();
 	a.setName(as->getName());
 	a.setName(as->getName());
-	a.m_importedAs = std::move(as);
+	a.m_importedAs.reset(as);
 	a.m_usage = usage;
 	a.m_usage = usage;
 
 
 	AccelerationStructureHandle handle;
 	AccelerationStructureHandle handle;

+ 1 - 3
AnKi/Gr/Sampler.h

@@ -38,9 +38,7 @@ public:
 		const U8* first = reinterpret_cast<const U8*>(&m_minLod);
 		const U8* first = reinterpret_cast<const U8*>(&m_minLod);
 		const U8* last = reinterpret_cast<const U8*>(&m_addressing) + sizeof(m_addressing);
 		const U8* last = reinterpret_cast<const U8*>(&m_addressing) + sizeof(m_addressing);
 		const U32 size = U32(last - first);
 		const U32 size = U32(last - first);
-		ANKI_ASSERT(size
-					== sizeof(F32) * 3 + sizeof(SamplingFilter) * 2 + sizeof(CompareOperation) + sizeof(I8)
-						   + sizeof(SamplingAddressing));
+		ANKI_ASSERT(size == sizeof(F32) * 3 + sizeof(SamplingFilter) * 2 + sizeof(CompareOperation) + sizeof(I8) + sizeof(SamplingAddressing));
 		return anki::computeHash(first, size);
 		return anki::computeHash(first, size);
 	}
 	}
 };
 };

+ 3 - 5
AnKi/Gr/ShaderProgram.cpp

@@ -22,9 +22,7 @@ Bool ShaderProgramInitInfo::isValid() const
 		}
 		}
 	}
 	}
 
 
-	if(!!graphicsMask
-	   && (graphicsMask & (ShaderTypeBit::kVertex | ShaderTypeBit::kFragment))
-			  != (ShaderTypeBit::kVertex | ShaderTypeBit::kFragment))
+	if(!!graphicsMask && (graphicsMask & (ShaderTypeBit::kVertex | ShaderTypeBit::kFragment)) != (ShaderTypeBit::kVertex | ShaderTypeBit::kFragment))
 	{
 	{
 		return false;
 		return false;
 	}
 	}
@@ -45,7 +43,7 @@ Bool ShaderProgramInitInfo::isValid() const
 	}
 	}
 
 
 	ShaderTypeBit rtMask = ShaderTypeBit::kNone;
 	ShaderTypeBit rtMask = ShaderTypeBit::kNone;
-	for(const ShaderPtr& s : m_rayTracingShaders.m_rayGenShaders)
+	for(const Shader* s : m_rayTracingShaders.m_rayGenShaders)
 	{
 	{
 		if(s->getShaderType() != ShaderType::kRayGen)
 		if(s->getShaderType() != ShaderType::kRayGen)
 		{
 		{
@@ -54,7 +52,7 @@ Bool ShaderProgramInitInfo::isValid() const
 		rtMask |= ShaderTypeBit::kRayGen;
 		rtMask |= ShaderTypeBit::kRayGen;
 	}
 	}
 
 
-	for(const ShaderPtr& s : m_rayTracingShaders.m_missShaders)
+	for(const Shader* s : m_rayTracingShaders.m_missShaders)
 	{
 	{
 		if(s->getShaderType() != ShaderType::kMiss)
 		if(s->getShaderType() != ShaderType::kMiss)
 		{
 		{

+ 13 - 11
AnKi/Gr/ShaderProgram.h

@@ -17,16 +17,16 @@ namespace anki {
 class RayTracingHitGroup
 class RayTracingHitGroup
 {
 {
 public:
 public:
-	ShaderPtr m_closestHitShader;
-	ShaderPtr m_anyHitShader;
+	Shader* m_closestHitShader = nullptr;
+	Shader* m_anyHitShader = nullptr;
 };
 };
 
 
 /// @memberof ShaderProgramInitInfo
 /// @memberof ShaderProgramInitInfo
 class RayTracingShaders
 class RayTracingShaders
 {
 {
 public:
 public:
-	WeakArray<ShaderPtr> m_rayGenShaders;
-	WeakArray<ShaderPtr> m_missShaders;
+	WeakArray<Shader*> m_rayGenShaders;
+	WeakArray<Shader*> m_missShaders;
 	WeakArray<RayTracingHitGroup> m_hitGroups;
 	WeakArray<RayTracingHitGroup> m_hitGroups;
 	U32 m_maxRecursionDepth = 1;
 	U32 m_maxRecursionDepth = 1;
 };
 };
@@ -36,10 +36,10 @@ class ShaderProgramInitInfo : public GrBaseInitInfo
 {
 {
 public:
 public:
 	/// Option 1
 	/// Option 1
-	Array<ShaderPtr, U32(ShaderType::kLastGraphics + 1)> m_graphicsShaders;
+	Array<Shader*, U32(ShaderType::kLastGraphics + 1)> m_graphicsShaders = {};
 
 
 	/// Option 2
 	/// Option 2
-	ShaderPtr m_computeShader;
+	Shader* m_computeShader = nullptr;
 
 
 	/// Option 3
 	/// Option 3
 	RayTracingShaders m_rayTracingShaders;
 	RayTracingShaders m_rayTracingShaders;
@@ -60,17 +60,19 @@ class ShaderProgram : public GrObject
 public:
 public:
 	static constexpr GrObjectType kClassType = GrObjectType::kShaderProgram;
 	static constexpr GrObjectType kClassType = GrObjectType::kShaderProgram;
 
 
-	/// Get the shader group handles that will be used in the SBTs. The size of each handle is
-	/// GpuDeviceCapabilities::m_shaderGroupHandleSize. To access a handle use:
+	/// Get the shader group handles that will be used in the SBTs. The size of each handle is GpuDeviceCapabilities::m_shaderGroupHandleSize. To
+	/// access a handle use:
 	/// @code
 	/// @code
 	/// const U8* handleBegin = &getShaderGroupHandles()[handleIdx * devCapabilities.m_shaderGroupHandleSize];
 	/// const U8* handleBegin = &getShaderGroupHandles()[handleIdx * devCapabilities.m_shaderGroupHandleSize];
 	/// const U8* handleEnd = &getShaderGroupHandles()[(handleIdx + 1) * devCapabilities.m_shaderGroupHandleSize];
 	/// const U8* handleEnd = &getShaderGroupHandles()[(handleIdx + 1) * devCapabilities.m_shaderGroupHandleSize];
 	/// @endcode
 	/// @endcode
-	/// The handleIdx is defined via a convention. The ray gen shaders appear first where handleIdx is in the same order
-	/// as the shader in RayTracingShaders::m_rayGenShaders. Then miss shaders follow with a similar rule. Then hit
-	/// groups follow.
+	/// The handleIdx is defined via a convention. The ray gen shaders appear first where handleIdx is in the same order as the shader in
+	/// RayTracingShaders::m_rayGenShaders. Then miss shaders follow with a similar rule. Then hit groups follow.
 	ConstWeakArray<U8> getShaderGroupHandles() const;
 	ConstWeakArray<U8> getShaderGroupHandles() const;
 
 
+	/// Same as getShaderGroupHandles but the data live in a GPU buffer.
+	Buffer& getShaderGroupHandlesGpuBuffer() const;
+
 protected:
 protected:
 	/// Construct.
 	/// Construct.
 	ShaderProgram(CString name)
 	ShaderProgram(CString name)

+ 4 - 5
AnKi/Gr/Texture.h

@@ -45,8 +45,8 @@ public:
 		const U8* last = reinterpret_cast<const U8*>(&m_samples) + sizeof(m_samples);
 		const U8* last = reinterpret_cast<const U8*>(&m_samples) + sizeof(m_samples);
 		const U size = U(last - first);
 		const U size = U(last - first);
 		ANKI_ASSERT(size
 		ANKI_ASSERT(size
-					== sizeof(m_width) + sizeof(m_height) + sizeof(m_depth) + sizeof(m_layerCount) + sizeof(m_format)
-						   + sizeof(m_usage) + sizeof(m_type) + sizeof(m_mipmapCount) + sizeof(m_samples));
+					== sizeof(m_width) + sizeof(m_height) + sizeof(m_depth) + sizeof(m_layerCount) + sizeof(m_format) + sizeof(m_usage)
+						   + sizeof(m_type) + sizeof(m_mipmapCount) + sizeof(m_samples));
 		return anki::computeHash(first, size);
 		return anki::computeHash(first, size);
 	}
 	}
 
 
@@ -198,9 +198,8 @@ public:
 		ANKI_ASSERT(isSubresourceValid(subresource));
 		ANKI_ASSERT(isSubresourceValid(subresource));
 		if(m_texType != TextureType::k3D)
 		if(m_texType != TextureType::k3D)
 		{
 		{
-			return subresource.m_firstMipmap == 0 && subresource.m_mipmapCount == m_mipCount
-				   && subresource.m_faceCount == 1 && subresource.m_layerCount == 1
-				   && subresource.m_depthStencilAspect == m_aspect;
+			return subresource.m_firstMipmap == 0 && subresource.m_mipmapCount == m_mipCount && subresource.m_faceCount == 1
+				   && subresource.m_layerCount == 1 && subresource.m_depthStencilAspect == m_aspect;
 		}
 		}
 		else
 		else
 		{
 		{

+ 8 - 11
AnKi/Gr/TextureView.h

@@ -17,9 +17,9 @@ namespace anki {
 class TextureViewInitInfo : public GrBaseInitInfo, public TextureSubresourceInfo
 class TextureViewInitInfo : public GrBaseInitInfo, public TextureSubresourceInfo
 {
 {
 public:
 public:
-	TexturePtr m_texture;
+	Texture* m_texture = nullptr;
 
 
-	TextureViewInitInfo(TexturePtr tex, CString name = {})
+	TextureViewInitInfo(Texture* tex, CString name = {})
 		: GrBaseInitInfo(name)
 		: GrBaseInitInfo(name)
 		, m_texture(tex)
 		, m_texture(tex)
 	{
 	{
@@ -28,8 +28,7 @@ public:
 		m_firstLayer = 0;
 		m_firstLayer = 0;
 		m_layerCount = tex->getLayerCount();
 		m_layerCount = tex->getLayerCount();
 		m_firstFace = 0;
 		m_firstFace = 0;
-		m_faceCount =
-			(tex->getTextureType() == TextureType::kCubeArray || tex->getTextureType() == TextureType::kCube) ? 6 : 1;
+		m_faceCount = (tex->getTextureType() == TextureType::kCubeArray || tex->getTextureType() == TextureType::kCube) ? 6 : 1;
 
 
 		m_depthStencilAspect = getFormatInfo(tex->getFormat()).m_depthStencil;
 		m_depthStencilAspect = getFormatInfo(tex->getFormat()).m_depthStencil;
 	}
 	}
@@ -39,8 +38,7 @@ public:
 	{
 	{
 	}
 	}
 
 
-	TextureViewInitInfo(TexturePtr tex, const TextureSurfaceInfo& surf,
-						DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone, CString name = {})
+	TextureViewInitInfo(Texture* tex, const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect = DepthStencilAspectBit::kNone, CString name = {})
 		: GrBaseInitInfo(name)
 		: GrBaseInitInfo(name)
 		, m_texture(tex)
 		, m_texture(tex)
 	{
 	{
@@ -54,7 +52,7 @@ public:
 		ANKI_ASSERT(isValid());
 		ANKI_ASSERT(isValid());
 	}
 	}
 
 
-	TextureViewInitInfo(TexturePtr tex, const TextureSubresourceInfo& subresource, CString name = {})
+	TextureViewInitInfo(Texture* tex, const TextureSubresourceInfo& subresource, CString name = {})
 		: GrBaseInitInfo(name)
 		: GrBaseInitInfo(name)
 		, m_texture(tex)
 		, m_texture(tex)
 	{
 	{
@@ -64,7 +62,7 @@ public:
 
 
 	Bool isValid() const
 	Bool isValid() const
 	{
 	{
-		return m_texture.isCreated() && m_texture->isSubresourceValid(*this);
+		return m_texture != nullptr && m_texture->isSubresourceValid(*this);
 	}
 	}
 };
 };
 
 
@@ -119,9 +117,8 @@ protected:
 
 
 	Bool initialized() const
 	Bool initialized() const
 	{
 	{
-		return m_texType != TextureType::kCount && m_subresource.m_firstMipmap < kMaxU32
-			   && m_subresource.m_mipmapCount < kMaxU32 && m_subresource.m_firstLayer < kMaxU32
-			   && m_subresource.m_layerCount < kMaxU32 && m_subresource.m_firstFace < kMaxU8
+		return m_texType != TextureType::kCount && m_subresource.m_firstMipmap < kMaxU32 && m_subresource.m_mipmapCount < kMaxU32
+			   && m_subresource.m_firstLayer < kMaxU32 && m_subresource.m_layerCount < kMaxU32 && m_subresource.m_firstFace < kMaxU8
 			   && m_subresource.m_faceCount < kMaxU8;
 			   && m_subresource.m_faceCount < kMaxU8;
 	}
 	}
 
 

+ 9 - 12
AnKi/Gr/Utils/Functions.cpp

@@ -8,8 +8,7 @@
 namespace anki {
 namespace anki {
 
 
 template<typename T>
 template<typename T>
-static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& varBlkInfo,
-											   [[maybe_unused]] const void* elements,
+static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& varBlkInfo, [[maybe_unused]] const void* elements,
 											   [[maybe_unused]] U32 elementsCount, [[maybe_unused]] void* buffBegin,
 											   [[maybe_unused]] U32 elementsCount, [[maybe_unused]] void* buffBegin,
 											   [[maybe_unused]] const void* buffEnd)
 											   [[maybe_unused]] const void* buffEnd)
 {
 {
@@ -34,8 +33,8 @@ static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& va
 }
 }
 
 
 template<typename T>
 template<typename T>
-static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkInfo, const void* elements,
-										 U32 elementsCount, void* buffBegin, const void* buffEnd)
+static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
+										 const void* buffEnd)
 {
 {
 	writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 	writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 
 
@@ -53,8 +52,8 @@ static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkIn
 }
 }
 
 
 template<typename T, typename Vec>
 template<typename T, typename Vec>
-static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkInfo, const void* elements,
-										 U32 elementsCount, void* buffBegin, const void* buffEnd)
+static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
+										 const void* buffEnd)
 {
 {
 	writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 	writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 	ANKI_ASSERT(varBlkInfo.m_matrixStride > 0);
 	ANKI_ASSERT(varBlkInfo.m_matrixStride > 0);
@@ -102,8 +101,7 @@ template<typename T, Bool isMatrix = IsShaderVarDataTypeAMatrix<T>::kValue>
 class WriteShaderBlockMemory
 class WriteShaderBlockMemory
 {
 {
 public:
 public:
-	void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
-					const void* buffEnd)
+	void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
 	{
 	{
 		using RowVec = typename T::RowVec;
 		using RowVec = typename T::RowVec;
 		writeShaderBlockMemoryMatrix<T, RowVec>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		writeShaderBlockMemoryMatrix<T, RowVec>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
@@ -114,8 +112,7 @@ template<typename T>
 class WriteShaderBlockMemory<T, false>
 class WriteShaderBlockMemory<T, false>
 {
 {
 public:
 public:
-	void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
-					const void* buffEnd)
+	void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
 	{
 	{
 		writeShaderBlockMemorySimple<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		writeShaderBlockMemorySimple<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 	}
 	}
@@ -123,8 +120,8 @@ public:
 
 
 } // namespace
 } // namespace
 
 
-void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo,
-							const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
+void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount,
+							void* buffBegin, const void* buffEnd)
 {
 {
 	switch(type)
 	switch(type)
 	{
 	{

+ 8 - 9
AnKi/Gr/Utils/Functions.h

@@ -10,19 +10,18 @@
 
 
 namespace anki {
 namespace anki {
 
 
-inline Bool stencilTestDisabled(StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
-								StencilOperation stencilPassDepthPass, CompareOperation compare)
+inline Bool stencilTestDisabled(StencilOperation stencilFail, StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass,
+								CompareOperation compare)
 {
 {
 	return stencilFail == StencilOperation::kKeep && stencilPassDepthFail == StencilOperation::kKeep
 	return stencilFail == StencilOperation::kKeep && stencilPassDepthFail == StencilOperation::kKeep
 		   && stencilPassDepthPass == StencilOperation::kKeep && compare == CompareOperation::kAlways;
 		   && stencilPassDepthPass == StencilOperation::kKeep && compare == CompareOperation::kAlways;
 }
 }
 
 
-inline Bool blendingDisabled(BlendFactor srcFactorRgb, BlendFactor dstFactorRgb, BlendFactor srcFactorA,
-							 BlendFactor dstFactorA, BlendOperation opRgb, BlendOperation opA)
+inline Bool blendingDisabled(BlendFactor srcFactorRgb, BlendFactor dstFactorRgb, BlendFactor srcFactorA, BlendFactor dstFactorA, BlendOperation opRgb,
+							 BlendOperation opA)
 {
 {
-	Bool dontWantBlend = srcFactorRgb == BlendFactor::kOne && dstFactorRgb == BlendFactor::kZero
-						 && srcFactorA == BlendFactor::kOne && dstFactorA == BlendFactor::kZero
-						 && (opRgb == BlendOperation::kAdd || opRgb == BlendOperation::kSubtract)
+	Bool dontWantBlend = srcFactorRgb == BlendFactor::kOne && dstFactorRgb == BlendFactor::kZero && srcFactorA == BlendFactor::kOne
+						 && dstFactorA == BlendFactor::kZero && (opRgb == BlendOperation::kAdd || opRgb == BlendOperation::kSubtract)
 						 && (opA == BlendOperation::kAdd || opA == BlendOperation::kSubtract);
 						 && (opA == BlendOperation::kAdd || opA == BlendOperation::kSubtract);
 	return dontWantBlend;
 	return dontWantBlend;
 }
 }
@@ -42,7 +41,7 @@ ShaderVariableDataType getShaderVariableTypeFromTypename();
 #undef ANKI_SVDT_MACRO
 #undef ANKI_SVDT_MACRO
 
 
 /// Populate the memory of a variable that is inside a shader block.
 /// Populate the memory of a variable that is inside a shader block.
-void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo,
-							const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd);
+void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount,
+							void* buffBegin, const void* buffEnd);
 
 
 } // end namespace anki
 } // end namespace anki

+ 23 - 7
AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.cpp

@@ -9,8 +9,7 @@
 
 
 namespace anki {
 namespace anki {
 
 
-class SegregatedListsGpuMemoryPool::Chunk :
-	public SegregatedListsAllocatorBuilderChunkBase<SingletonMemoryPoolWrapper<GrMemoryPool>>
+class SegregatedListsGpuMemoryPool::Chunk : public SegregatedListsAllocatorBuilderChunkBase<SingletonMemoryPoolWrapper<GrMemoryPool>>
 {
 {
 public:
 public:
 	PtrSize m_offsetInGpuBuffer;
 	PtrSize m_offsetInGpuBuffer;
@@ -50,8 +49,8 @@ public:
 	/// @}
 	/// @}
 };
 };
 
 
-void SegregatedListsGpuMemoryPool::init(BufferUsageBit gpuBufferUsage, ConstWeakArray<PtrSize> classUpperSizes,
-										PtrSize initialGpuBufferSize, CString bufferName, Bool allowCoWs)
+void SegregatedListsGpuMemoryPool::init(BufferUsageBit gpuBufferUsage, ConstWeakArray<PtrSize> classUpperSizes, PtrSize initialGpuBufferSize,
+										CString bufferName, Bool allowCoWs, BufferMapAccessBit map)
 {
 {
 	ANKI_ASSERT(!isInitialized());
 	ANKI_ASSERT(!isInitialized());
 
 
@@ -76,6 +75,7 @@ void SegregatedListsGpuMemoryPool::init(BufferUsageBit gpuBufferUsage, ConstWeak
 	m_frame = 0;
 	m_frame = 0;
 	m_allocatedSize = 0;
 	m_allocatedSize = 0;
 	m_allowCoWs = allowCoWs;
 	m_allowCoWs = allowCoWs;
+	m_mapAccess = map;
 }
 }
 
 
 void SegregatedListsGpuMemoryPool::destroy()
 void SegregatedListsGpuMemoryPool::destroy()
@@ -87,6 +87,11 @@ void SegregatedListsGpuMemoryPool::destroy()
 
 
 	GrManager::getSingleton().finish();
 	GrManager::getSingleton().finish();
 
 
+	if(m_mappedGpuBufferMemory)
+	{
+		m_gpuBuffer->unmap();
+	}
+
 	for(GrDynamicArray<SegregatedListsGpuMemoryPoolToken>& arr : m_garbage)
 	for(GrDynamicArray<SegregatedListsGpuMemoryPoolToken>& arr : m_garbage)
 	{
 	{
 		for(const SegregatedListsGpuMemoryPoolToken& token : arr)
 		for(const SegregatedListsGpuMemoryPoolToken& token : arr)
@@ -115,8 +120,14 @@ Error SegregatedListsGpuMemoryPool::allocateChunk(Chunk*& newChunk, PtrSize& chu
 		BufferInitInfo buffInit(m_bufferName);
 		BufferInitInfo buffInit(m_bufferName);
 		buffInit.m_size = m_initialBufferSize;
 		buffInit.m_size = m_initialBufferSize;
 		buffInit.m_usage = m_bufferUsage | BufferUsageBit::kAllTransfer;
 		buffInit.m_usage = m_bufferUsage | BufferUsageBit::kAllTransfer;
+		buffInit.m_mapAccess = m_mapAccess;
 		m_gpuBuffer = GrManager::getSingleton().newBuffer(buffInit);
 		m_gpuBuffer = GrManager::getSingleton().newBuffer(buffInit);
 
 
+		if(!!m_mapAccess)
+		{
+			m_mappedGpuBufferMemory = m_gpuBuffer->map(0, kMaxPtrSize, m_mapAccess);
+		}
+
 		newChunk = newInstance<Chunk>(GrMemoryPool::getSingleton());
 		newChunk = newInstance<Chunk>(GrMemoryPool::getSingleton());
 		newChunk->m_offsetInGpuBuffer = 0;
 		newChunk->m_offsetInGpuBuffer = 0;
 	}
 	}
@@ -137,6 +148,7 @@ Error SegregatedListsGpuMemoryPool::allocateChunk(Chunk*& newChunk, PtrSize& chu
 		BufferInitInfo buffInit(m_bufferName);
 		BufferInitInfo buffInit(m_bufferName);
 		buffInit.m_size = m_gpuBuffer->getSize() * 2;
 		buffInit.m_size = m_gpuBuffer->getSize() * 2;
 		buffInit.m_usage = m_bufferUsage | BufferUsageBit::kAllTransfer;
 		buffInit.m_usage = m_bufferUsage | BufferUsageBit::kAllTransfer;
+		buffInit.m_mapAccess = m_mapAccess;
 		BufferPtr newBuffer = GrManager::getSingleton().newBuffer(buffInit);
 		BufferPtr newBuffer = GrManager::getSingleton().newBuffer(buffInit);
 
 
 		// Do the copy
 		// Do the copy
@@ -153,7 +165,7 @@ Error SegregatedListsGpuMemoryPool::allocateChunk(Chunk*& newChunk, PtrSize& chu
 		barriers[1].m_nextUsage = BufferUsageBit::kTransferDestination;
 		barriers[1].m_nextUsage = BufferUsageBit::kTransferDestination;
 		cmdb->setPipelineBarrier({}, barriers, {});
 		cmdb->setPipelineBarrier({}, barriers, {});
 
 
-		cmdb->copyBufferToBuffer(m_gpuBuffer, 0, newBuffer, 0, m_gpuBuffer->getSize());
+		cmdb->copyBufferToBuffer(m_gpuBuffer.get(), 0, newBuffer.get(), 0, m_gpuBuffer->getSize());
 
 
 		barriers[1].m_previousUsage = BufferUsageBit::kTransferDestination;
 		barriers[1].m_previousUsage = BufferUsageBit::kTransferDestination;
 		barriers[1].m_nextUsage = m_bufferUsage;
 		barriers[1].m_nextUsage = m_bufferUsage;
@@ -167,6 +179,11 @@ Error SegregatedListsGpuMemoryPool::allocateChunk(Chunk*& newChunk, PtrSize& chu
 
 
 		// Switch the buffers
 		// Switch the buffers
 		m_gpuBuffer = newBuffer;
 		m_gpuBuffer = newBuffer;
+
+		if(!!m_mapAccess)
+		{
+			m_mappedGpuBufferMemory = m_gpuBuffer->map(0, kMaxPtrSize, m_mapAccess);
+		}
 	}
 	}
 	else
 	else
 	{
 	{
@@ -245,8 +262,7 @@ void SegregatedListsGpuMemoryPool::endFrame()
 	m_garbage[m_frame].destroy();
 	m_garbage[m_frame].destroy();
 }
 }
 
 
-void SegregatedListsGpuMemoryPool::getStats(F32& externalFragmentation, PtrSize& userAllocatedSize,
-											PtrSize& totalSize) const
+void SegregatedListsGpuMemoryPool::getStats(F32& externalFragmentation, PtrSize& userAllocatedSize, PtrSize& totalSize) const
 {
 {
 	ANKI_ASSERT(isInitialized());
 	ANKI_ASSERT(isInitialized());
 
 

+ 18 - 8
AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h

@@ -3,6 +3,8 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
+#pragma once
+
 #include <AnKi/Util/SegregatedListsAllocatorBuilder.h>
 #include <AnKi/Util/SegregatedListsAllocatorBuilder.h>
 #include <AnKi/Gr/Buffer.h>
 #include <AnKi/Gr/Buffer.h>
 
 
@@ -38,8 +40,8 @@ private:
 	PtrSize m_chunkOffset = kMaxPtrSize;
 	PtrSize m_chunkOffset = kMaxPtrSize;
 };
 };
 
 
-/// GPU memory allocator based on segregated lists. It allocates a GPU buffer with some initial size. If there is a need
-/// to grow it allocates a bigger buffer and copies contents of the old one to the new (CoW).
+/// GPU memory allocator based on segregated lists. It allocates a GPU buffer with some initial size. If there is a need to grow it allocates a bigger
+/// buffer and copies contents of the old one to the new (CoW).
 class SegregatedListsGpuMemoryPool
 class SegregatedListsGpuMemoryPool
 {
 {
 public:
 public:
@@ -54,8 +56,8 @@ public:
 
 
 	SegregatedListsGpuMemoryPool& operator=(const SegregatedListsGpuMemoryPool&) = delete;
 	SegregatedListsGpuMemoryPool& operator=(const SegregatedListsGpuMemoryPool&) = delete;
 
 
-	void init(BufferUsageBit gpuBufferUsage, ConstWeakArray<PtrSize> classUpperSizes, PtrSize initialGpuBufferSize,
-			  CString bufferName, Bool allowCoWs);
+	void init(BufferUsageBit gpuBufferUsage, ConstWeakArray<PtrSize> classUpperSizes, PtrSize initialGpuBufferSize, CString bufferName,
+			  Bool allowCoWs, BufferMapAccessBit map = BufferMapAccessBit::kNone);
 
 
 	void destroy();
 	void destroy();
 
 
@@ -72,10 +74,16 @@ public:
 
 
 	/// Need to be checking this constantly to get the updated buffer in case of CoWs.
 	/// Need to be checking this constantly to get the updated buffer in case of CoWs.
 	/// @note It's not thread-safe.
 	/// @note It's not thread-safe.
-	const BufferPtr& getGpuBuffer() const
+	Buffer& getGpuBuffer() const
 	{
 	{
 		ANKI_ASSERT(m_gpuBuffer.isCreated() && "The buffer hasn't been created yet");
 		ANKI_ASSERT(m_gpuBuffer.isCreated() && "The buffer hasn't been created yet");
-		return m_gpuBuffer;
+		return *m_gpuBuffer;
+	}
+
+	void* getGpuBufferMappedMemory() const
+	{
+		ANKI_ASSERT(m_mappedGpuBufferMemory);
+		return m_mappedGpuBufferMemory;
 	}
 	}
 
 
 	/// @note It's thread-safe.
 	/// @note It's thread-safe.
@@ -84,8 +92,7 @@ public:
 private:
 private:
 	class BuilderInterface;
 	class BuilderInterface;
 	class Chunk;
 	class Chunk;
-	using Builder =
-		SegregatedListsAllocatorBuilder<Chunk, BuilderInterface, DummyMutex, SingletonMemoryPoolWrapper<GrMemoryPool>>;
+	using Builder = SegregatedListsAllocatorBuilder<Chunk, BuilderInterface, DummyMutex, SingletonMemoryPoolWrapper<GrMemoryPool>>;
 
 
 	BufferUsageBit m_bufferUsage = BufferUsageBit::kNone;
 	BufferUsageBit m_bufferUsage = BufferUsageBit::kNone;
 	GrDynamicArray<PtrSize> m_classes;
 	GrDynamicArray<PtrSize> m_classes;
@@ -96,6 +103,7 @@ private:
 
 
 	Builder* m_builder = nullptr;
 	Builder* m_builder = nullptr;
 	BufferPtr m_gpuBuffer;
 	BufferPtr m_gpuBuffer;
+	void* m_mappedGpuBufferMemory = nullptr;
 	PtrSize m_allocatedSize = 0;
 	PtrSize m_allocatedSize = 0;
 
 
 	GrDynamicArray<Chunk*> m_deletedChunks;
 	GrDynamicArray<Chunk*> m_deletedChunks;
@@ -104,6 +112,8 @@ private:
 	U8 m_frame = 0;
 	U8 m_frame = 0;
 	Bool m_allowCoWs = true;
 	Bool m_allowCoWs = true;
 
 
+	BufferMapAccessBit m_mapAccess = BufferMapAccessBit::kNone;
+
 	Error allocateChunk(Chunk*& newChunk, PtrSize& chunkSize);
 	Error allocateChunk(Chunk*& newChunk, PtrSize& chunkSize);
 	void deleteChunk(Chunk* chunk);
 	void deleteChunk(Chunk* chunk);
 
 

+ 3 - 4
AnKi/Gr/Utils/StackGpuMemoryPool.cpp

@@ -117,13 +117,12 @@ StackGpuMemoryPool::~StackGpuMemoryPool()
 	}
 	}
 }
 }
 
 
-void StackGpuMemoryPool::init(PtrSize initialSize, F64 nextChunkGrowScale, PtrSize nextChunkGrowBias, U32 alignment,
-							  BufferUsageBit bufferUsage, BufferMapAccessBit bufferMapping, Bool allowToGrow,
-							  CString bufferName)
+void StackGpuMemoryPool::init(PtrSize initialSize, F64 nextChunkGrowScale, PtrSize nextChunkGrowBias, U32 alignment, BufferUsageBit bufferUsage,
+							  BufferMapAccessBit bufferMapping, Bool allowToGrow, CString bufferName)
 {
 {
 	ANKI_ASSERT(m_builder == nullptr);
 	ANKI_ASSERT(m_builder == nullptr);
 	ANKI_ASSERT(initialSize > 0 && alignment > 0);
 	ANKI_ASSERT(initialSize > 0 && alignment > 0);
-	ANKI_ASSERT(nextChunkGrowScale >= 1.0 && nextChunkGrowBias > 0);
+	ANKI_ASSERT(nextChunkGrowScale >= 1.0);
 
 
 	m_builder = newInstance<Builder>(GrMemoryPool::getSingleton());
 	m_builder = newInstance<Builder>(GrMemoryPool::getSingleton());
 	BuilderInterface& inter = m_builder->getInterface();
 	BuilderInterface& inter = m_builder->getInterface();

+ 2 - 2
AnKi/Gr/Utils/StackGpuMemoryPool.h

@@ -25,8 +25,8 @@ public:
 
 
 	StackGpuMemoryPool& operator=(const StackGpuMemoryPool&) = delete; // Non-copyable
 	StackGpuMemoryPool& operator=(const StackGpuMemoryPool&) = delete; // Non-copyable
 
 
-	void init(PtrSize initialSize, F64 nextChunkGrowScale, PtrSize nextChunkGrowBias, U32 alignment,
-			  BufferUsageBit bufferUsage, BufferMapAccessBit bufferMapping, Bool allowToGrow, CString bufferName);
+	void init(PtrSize initialSize, F64 nextChunkGrowScale, PtrSize nextChunkGrowBias, U32 alignment, BufferUsageBit bufferUsage,
+			  BufferMapAccessBit bufferMapping, Bool allowToGrow, CString bufferName);
 
 
 	/// @note It's thread-safe against other allocate()
 	/// @note It's thread-safe against other allocate()
 	void allocate(PtrSize size, PtrSize& outOffset, Buffer*& buffer)
 	void allocate(PtrSize size, PtrSize& outOffset, Buffer*& buffer)

+ 7 - 2
AnKi/Gr/Vulkan/AccelerationStructure.cpp

@@ -11,8 +11,7 @@ namespace anki {
 
 
 AccelerationStructure* AccelerationStructure::newInstance(const AccelerationStructureInitInfo& init)
 AccelerationStructure* AccelerationStructure::newInstance(const AccelerationStructureInitInfo& init)
 {
 {
-	AccelerationStructureImpl* impl =
-		anki::newInstance<AccelerationStructureImpl>(GrMemoryPool::getSingleton(), init.getName());
+	AccelerationStructureImpl* impl = anki::newInstance<AccelerationStructureImpl>(GrMemoryPool::getSingleton(), init.getName());
 	const Error err = impl->init(init);
 	const Error err = impl->init(init);
 	if(err)
 	if(err)
 	{
 	{
@@ -22,4 +21,10 @@ AccelerationStructure* AccelerationStructure::newInstance(const AccelerationStru
 	return impl;
 	return impl;
 }
 }
 
 
+U64 AccelerationStructure::getGpuAddress() const
+{
+	ANKI_VK_SELF_CONST(AccelerationStructureImpl);
+	return self.getAsDeviceAddress();
+}
+
 } // end namespace anki
 } // end namespace anki

+ 60 - 45
AnKi/Gr/Vulkan/AccelerationStructureImpl.cpp

@@ -5,16 +5,17 @@
 
 
 #include <AnKi/Gr/Vulkan/AccelerationStructureImpl.h>
 #include <AnKi/Gr/Vulkan/AccelerationStructureImpl.h>
 #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
 #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
+#include <AnKi/Gr/Vulkan/FrameGarbageCollector.h>
 
 
 namespace anki {
 namespace anki {
 
 
 AccelerationStructureImpl::~AccelerationStructureImpl()
 AccelerationStructureImpl::~AccelerationStructureImpl()
 {
 {
-	m_topLevelInfo.m_blas.destroy();
-
 	if(m_handle)
 	if(m_handle)
 	{
 	{
-		vkDestroyAccelerationStructureKHR(getGrManagerImpl().getDevice(), m_handle, nullptr);
+		ASGarbage* garbage = anki::newInstance<ASGarbage>(GrMemoryPool::getSingleton());
+		garbage->m_asHandle = m_handle;
+		getGrManagerImpl().getFrameGarbageCollector().newASGarbage(garbage);
 	}
 	}
 }
 }
 
 
@@ -39,8 +40,7 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 		geom.geometry.triangles.vertexStride = inf.m_bottomLevel.m_positionStride;
 		geom.geometry.triangles.vertexStride = inf.m_bottomLevel.m_positionStride;
 		geom.geometry.triangles.maxVertex = inf.m_bottomLevel.m_positionCount - 1;
 		geom.geometry.triangles.maxVertex = inf.m_bottomLevel.m_positionCount - 1;
 		geom.geometry.triangles.indexType = convertIndexType(inf.m_bottomLevel.m_indexType);
 		geom.geometry.triangles.indexType = convertIndexType(inf.m_bottomLevel.m_indexType);
-		geom.geometry.triangles.indexData.deviceAddress =
-			inf.m_bottomLevel.m_indexBuffer->getGpuAddress() + inf.m_bottomLevel.m_indexBufferOffset;
+		geom.geometry.triangles.indexData.deviceAddress = inf.m_bottomLevel.m_indexBuffer->getGpuAddress() + inf.m_bottomLevel.m_indexBufferOffset;
 		geom.flags = 0; // VK_GEOMETRY_OPAQUE_BIT_KHR; // TODO
 		geom.flags = 0; // VK_GEOMETRY_OPAQUE_BIT_KHR; // TODO
 
 
 		// Geom build info
 		// Geom build info
@@ -56,9 +56,8 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 		VkAccelerationStructureBuildSizesInfoKHR buildSizes = {};
 		VkAccelerationStructureBuildSizesInfoKHR buildSizes = {};
 		const U32 primitiveCount = inf.m_bottomLevel.m_indexCount / 3;
 		const U32 primitiveCount = inf.m_bottomLevel.m_indexCount / 3;
 		buildSizes.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
 		buildSizes.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
-		vkGetAccelerationStructureBuildSizesKHR(vkdev, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo,
-												&primitiveCount, &buildSizes);
-		m_scratchBufferSize = U32(buildSizes.buildScratchSize);
+		vkGetAccelerationStructureBuildSizesKHR(vkdev, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &primitiveCount, &buildSizes);
+		m_scratchBufferSize = buildSizes.buildScratchSize;
 
 
 		// Create the buffer that holds the AS memory
 		// Create the buffer that holds the AS memory
 		BufferInitInfo bufferInit(inf.getName());
 		BufferInitInfo bufferInit(inf.getName());
@@ -90,38 +89,52 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 	}
 	}
 	else
 	else
 	{
 	{
-		// Create the instances buffer
-		m_topLevelInfo.m_blas.resizeStorage(inf.m_topLevel.m_instances.getSize());
-
-		BufferInitInfo buffInit("AS instances");
-		buffInit.m_size = sizeof(VkAccelerationStructureInstanceKHR) * inf.m_topLevel.m_instances.getSize();
-		buffInit.m_usage = PrivateBufferUsageBit::kAccelerationStructure;
-		buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
-		m_topLevelInfo.m_instancesBuffer = getGrManagerImpl().newBuffer(buffInit);
-
-		VkAccelerationStructureInstanceKHR* instances = static_cast<VkAccelerationStructureInstanceKHR*>(
-			m_topLevelInfo.m_instancesBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-		for(U32 i = 0; i < inf.m_topLevel.m_instances.getSize(); ++i)
+		const Bool isIndirect = inf.m_topLevel.m_indirectArgs.m_maxInstanceCount > 0;
+
+		if(!isIndirect)
 		{
 		{
-			VkAccelerationStructureInstanceKHR& outInst = instances[i];
-			const AccelerationStructureInstance& inInst = inf.m_topLevel.m_instances[i];
-			static_assert(sizeof(outInst.transform) == sizeof(inInst.m_transform), "See file");
-			memcpy(&outInst.transform, &inInst.m_transform, sizeof(inInst.m_transform));
-			outInst.instanceCustomIndex = i & 0xFFFFFF;
-			outInst.mask = inInst.m_mask;
-			outInst.instanceShaderBindingTableRecordOffset = inInst.m_hitgroupSbtRecordIndex & 0xFFFFFF;
-			outInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR
-							| VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
-			outInst.accelerationStructureReference =
-				static_cast<const AccelerationStructureImpl&>(*inInst.m_bottomLevel).m_deviceAddress;
-			ANKI_ASSERT(outInst.accelerationStructureReference != 0);
-
-			// Hold the reference
-			m_topLevelInfo.m_blas.emplaceBack(inf.m_topLevel.m_instances[i].m_bottomLevel);
+			// Create and populate the instances buffer
+			m_topLevelInfo.m_blases.resizeStorage(inf.m_topLevel.m_directArgs.m_instances.getSize());
+
+			BufferInitInfo buffInit("AS instances");
+			buffInit.m_size = sizeof(VkAccelerationStructureInstanceKHR) * inf.m_topLevel.m_directArgs.m_instances.getSize();
+			buffInit.m_usage = PrivateBufferUsageBit::kAccelerationStructure;
+			buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
+			m_topLevelInfo.m_instancesBuffer = getGrManagerImpl().newBuffer(buffInit);
+
+			VkAccelerationStructureInstanceKHR* instances =
+				static_cast<VkAccelerationStructureInstanceKHR*>(m_topLevelInfo.m_instancesBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
+			for(U32 i = 0; i < inf.m_topLevel.m_directArgs.m_instances.getSize(); ++i)
+			{
+				VkAccelerationStructureInstanceKHR& outInst = instances[i];
+				const AccelerationStructureInstanceInfo& inInst = inf.m_topLevel.m_directArgs.m_instances[i];
+				static_assert(sizeof(outInst.transform) == sizeof(inInst.m_transform), "See file");
+				memcpy(&outInst.transform, &inInst.m_transform, sizeof(inInst.m_transform));
+				outInst.instanceCustomIndex = i & 0xFFFFFF;
+				outInst.mask = inInst.m_mask;
+				outInst.instanceShaderBindingTableRecordOffset = inInst.m_hitgroupSbtRecordIndex & 0xFFFFFF;
+				outInst.flags =
+					VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR | VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
+				outInst.accelerationStructureReference = static_cast<const AccelerationStructureImpl&>(*inInst.m_bottomLevel).m_deviceAddress;
+				ANKI_ASSERT(outInst.accelerationStructureReference != 0);
+
+				// Hold the reference
+				m_topLevelInfo.m_blases.emplaceBack(inf.m_topLevel.m_directArgs.m_instances[i].m_bottomLevel);
+			}
+
+			m_topLevelInfo.m_instancesBuffer->flush(0, kMaxPtrSize);
+			m_topLevelInfo.m_instancesBuffer->unmap();
 		}
 		}
+		else
+		{
+			// Instances buffer already created
+			ANKI_ASSERT(inf.m_topLevel.m_indirectArgs.m_instancesBufferOffset
+							+ sizeof(VkAccelerationStructureInstanceKHR) * inf.m_topLevel.m_indirectArgs.m_maxInstanceCount
+						<= inf.m_topLevel.m_indirectArgs.m_instancesBuffer->getSize());
+			m_topLevelInfo.m_instancesBuffer.reset(inf.m_topLevel.m_indirectArgs.m_instancesBuffer);
 
 
-		m_topLevelInfo.m_instancesBuffer->flush(0, kMaxPtrSize);
-		m_topLevelInfo.m_instancesBuffer->unmap();
+			m_topLevelInfo.m_maxInstanceCount = inf.m_topLevel.m_indirectArgs.m_maxInstanceCount;
+		}
 
 
 		// Geom
 		// Geom
 		VkAccelerationStructureGeometryKHR& geom = m_geometry;
 		VkAccelerationStructureGeometryKHR& geom = m_geometry;
@@ -129,6 +142,10 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 		geom.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
 		geom.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
 		geom.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
 		geom.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
 		geom.geometry.instances.data.deviceAddress = m_topLevelInfo.m_instancesBuffer->getGpuAddress();
 		geom.geometry.instances.data.deviceAddress = m_topLevelInfo.m_instancesBuffer->getGpuAddress();
+		if(isIndirect)
+		{
+			geom.geometry.instances.data.deviceAddress += inf.m_topLevel.m_indirectArgs.m_instancesBufferOffset;
+		}
 		geom.geometry.instances.arrayOfPointers = false;
 		geom.geometry.instances.arrayOfPointers = false;
 		geom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // TODO
 		geom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // TODO
 
 
@@ -143,11 +160,10 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 
 
 		// Get memory info
 		// Get memory info
 		VkAccelerationStructureBuildSizesInfoKHR buildSizes = {};
 		VkAccelerationStructureBuildSizesInfoKHR buildSizes = {};
-		const U32 instanceCount = inf.m_topLevel.m_instances.getSize();
+		const U32 instanceCount = (isIndirect) ? inf.m_topLevel.m_indirectArgs.m_maxInstanceCount : inf.m_topLevel.m_directArgs.m_instances.getSize();
 		buildSizes.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
 		buildSizes.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
-		vkGetAccelerationStructureBuildSizesKHR(vkdev, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo,
-												&instanceCount, &buildSizes);
-		m_scratchBufferSize = U32(buildSizes.buildScratchSize);
+		vkGetAccelerationStructureBuildSizesKHR(vkdev, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &instanceCount, &buildSizes);
+		m_scratchBufferSize = buildSizes.buildScratchSize;
 
 
 		// Create the buffer that holds the AS memory
 		// Create the buffer that holds the AS memory
 		BufferInitInfo bufferInit(inf.getName());
 		BufferInitInfo bufferInit(inf.getName());
@@ -169,15 +185,14 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 		buildInfo.dstAccelerationStructure = m_handle;
 		buildInfo.dstAccelerationStructure = m_handle;
 
 
 		// Range info
 		// Range info
-		m_rangeInfo.primitiveCount = inf.m_topLevel.m_instances.getSize();
+		m_rangeInfo.primitiveCount = instanceCount;
 	}
 	}
 
 
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
-void AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit before,
-												   AccelerationStructureUsageBit after, VkPipelineStageFlags& srcStages,
-												   VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
+void AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after,
+												   VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
 												   VkAccessFlags& dstAccesses)
 												   VkAccessFlags& dstAccesses)
 {
 {
 	// Before
 	// Before

+ 13 - 8
AnKi/Gr/Vulkan/AccelerationStructureImpl.h

@@ -32,10 +32,16 @@ public:
 		return m_handle;
 		return m_handle;
 	}
 	}
 
 
-	U32 getBuildScratchBufferSize() const
+	U32 getMaxInstanceCount() const
 	{
 	{
-		ANKI_ASSERT(m_scratchBufferSize > 0);
-		return m_scratchBufferSize;
+		ANKI_ASSERT(m_topLevelInfo.m_maxInstanceCount);
+		return m_topLevelInfo.m_maxInstanceCount;
+	}
+
+	VkDeviceAddress getAsDeviceAddress() const
+	{
+		ANKI_ASSERT(m_deviceAddress);
+		return m_deviceAddress;
 	}
 	}
 
 
 	void generateBuildInfo(U64 scratchBufferAddress, VkAccelerationStructureBuildGeometryInfoKHR& buildInfo,
 	void generateBuildInfo(U64 scratchBufferAddress, VkAccelerationStructureBuildGeometryInfoKHR& buildInfo,
@@ -46,9 +52,8 @@ public:
 		rangeInfo = m_rangeInfo;
 		rangeInfo = m_rangeInfo;
 	}
 	}
 
 
-	static void computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after,
-								   VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
-								   VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses);
+	static void computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after, VkPipelineStageFlags& srcStages,
+								   VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses);
 
 
 private:
 private:
 	class ASBottomLevelInfo
 	class ASBottomLevelInfo
@@ -62,7 +67,8 @@ private:
 	{
 	{
 	public:
 	public:
 		BufferPtr m_instancesBuffer;
 		BufferPtr m_instancesBuffer;
-		GrDynamicArray<AccelerationStructurePtr> m_blas;
+		GrDynamicArray<AccelerationStructurePtr> m_blases;
+		U32 m_maxInstanceCount = 0; ///< Only for indirect.
 	};
 	};
 
 
 	BufferPtr m_asBuffer;
 	BufferPtr m_asBuffer;
@@ -77,7 +83,6 @@ private:
 	VkAccelerationStructureGeometryKHR m_geometry = {};
 	VkAccelerationStructureGeometryKHR m_geometry = {};
 	VkAccelerationStructureBuildGeometryInfoKHR m_buildInfo = {};
 	VkAccelerationStructureBuildGeometryInfoKHR m_buildInfo = {};
 	VkAccelerationStructureBuildRangeInfoKHR m_rangeInfo = {};
 	VkAccelerationStructureBuildRangeInfoKHR m_rangeInfo = {};
-	U32 m_scratchBufferSize = 0;
 	/// @}
 	/// @}
 };
 };
 /// @}
 /// @}

+ 22 - 26
AnKi/Gr/Vulkan/BufferImpl.cpp

@@ -46,8 +46,8 @@ BufferImpl::~BufferImpl()
 Error BufferImpl::init(const BufferInitInfo& inf)
 Error BufferImpl::init(const BufferInitInfo& inf)
 {
 {
 	ANKI_ASSERT(!isCreated());
 	ANKI_ASSERT(!isCreated());
-	const Bool exposeGpuAddress = !!(getGrManagerImpl().getExtensions() & VulkanExtensions::kKHR_buffer_device_address)
-								  && !!(inf.m_usage & ~BufferUsageBit::kAllTransfer);
+	const Bool exposeGpuAddress =
+		!!(getGrManagerImpl().getExtensions() & VulkanExtensions::kKHR_buffer_device_address) && !!(inf.m_usage & ~BufferUsageBit::kAllTransfer);
 
 
 	PtrSize size = inf.m_size;
 	PtrSize size = inf.m_size;
 	BufferMapAccessBit access = inf.m_mapAccess;
 	BufferMapAccessBit access = inf.m_mapAccess;
@@ -134,11 +134,8 @@ Error BufferImpl::init(const BufferInitInfo& inf)
 		// Read or read/write
 		// Read or read/write
 
 
 		// Cached & coherent
 		// Cached & coherent
-		memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(req.memoryTypeBits,
-																		 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
-																			 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT
-																			 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
-																		 0);
+		memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(
+			req.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0);
 
 
 		// Fallback: Just cached
 		// Fallback: Just cached
 		if(memIdx == kMaxU32)
 		if(memIdx == kMaxU32)
@@ -159,14 +156,13 @@ Error BufferImpl::init(const BufferInitInfo& inf)
 		ANKI_ASSERT(access == BufferMapAccessBit::kNone);
 		ANKI_ASSERT(access == BufferMapAccessBit::kNone);
 
 
 		// Device only
 		// Device only
-		memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(
-			req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+		memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+																		 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
 
 
 		// Fallback: Device with anything else
 		// Fallback: Device with anything else
 		if(memIdx == kMaxU32)
 		if(memIdx == kMaxU32)
 		{
 		{
-			memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(req.memoryTypeBits,
-																			 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
+			memIdx = getGrManagerImpl().getGpuMemoryManager().findMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
 		}
 		}
 	}
 	}
 
 
@@ -274,7 +270,7 @@ VkPipelineStageFlags BufferImpl::computePplineStage(BufferUsageBit usage)
 		stageMask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
 		stageMask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
 	}
 	}
 
 
-	if(!!(usage & BufferUsageBit::kAccelerationStructureBuild))
+	if(!!(usage & (BufferUsageBit::kAccelerationStructureBuild | BufferUsageBit::kAccelerationStructureBuildScratch)))
 	{
 	{
 		stageMask |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
 		stageMask |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
 	}
 	}
@@ -305,14 +301,12 @@ VkAccessFlags BufferImpl::computeAccessMask(BufferUsageBit usage)
 	constexpr BufferUsageBit kShaderRead = BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead
 	constexpr BufferUsageBit kShaderRead = BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead
 										   | BufferUsageBit::kStorageComputeRead | BufferUsageBit::kStorageTraceRaysRead
 										   | BufferUsageBit::kStorageComputeRead | BufferUsageBit::kStorageTraceRaysRead
 										   | BufferUsageBit::kTextureGeometryRead | BufferUsageBit::kTextureFragmentRead
 										   | BufferUsageBit::kTextureGeometryRead | BufferUsageBit::kTextureFragmentRead
-										   | BufferUsageBit::kTextureComputeRead
-										   | BufferUsageBit::kTextureTraceRaysRead;
+										   | BufferUsageBit::kTextureComputeRead | BufferUsageBit::kTextureTraceRaysRead;
 
 
-	constexpr BufferUsageBit kShaderWrite =
-		BufferUsageBit::kStorageGeometryWrite | BufferUsageBit::kStorageFragmentWrite
-		| BufferUsageBit::kStorageComputeWrite | BufferUsageBit::kStorageTraceRaysWrite
-		| BufferUsageBit::kTextureGeometryWrite | BufferUsageBit::kTextureFragmentWrite
-		| BufferUsageBit::kTextureComputeWrite | BufferUsageBit::kTextureTraceRaysWrite;
+	constexpr BufferUsageBit kShaderWrite = BufferUsageBit::kStorageGeometryWrite | BufferUsageBit::kStorageFragmentWrite
+											| BufferUsageBit::kStorageComputeWrite | BufferUsageBit::kStorageTraceRaysWrite
+											| BufferUsageBit::kTextureGeometryWrite | BufferUsageBit::kTextureFragmentWrite
+											| BufferUsageBit::kTextureComputeWrite | BufferUsageBit::kTextureTraceRaysWrite;
 
 
 	if(!!(usage & BufferUsageBit::kAllUniform))
 	if(!!(usage & BufferUsageBit::kAllUniform))
 	{
 	{
@@ -359,12 +353,16 @@ VkAccessFlags BufferImpl::computeAccessMask(BufferUsageBit usage)
 		mask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 		mask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 	}
 	}
 
 
+	if(!!(usage & BufferUsageBit::kAccelerationStructureBuildScratch))
+	{
+		mask |= VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
+	}
+
 	return mask;
 	return mask;
 }
 }
 
 
-void BufferImpl::computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages,
-									VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
-									VkAccessFlags& dstAccesses) const
+void BufferImpl::computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
+									VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const
 {
 {
 	ANKI_ASSERT(usageValid(before) && usageValid(after));
 	ANKI_ASSERT(usageValid(before) && usageValid(after));
 	ANKI_ASSERT(!!after);
 	ANKI_ASSERT(!!after);
@@ -388,11 +386,9 @@ VkBufferView BufferImpl::getOrCreateBufferView(Format fmt, PtrSize offset, PtrSi
 	ANKI_ASSERT(!!(m_usage & BufferUsageBit::kAllTexture));
 	ANKI_ASSERT(!!(m_usage & BufferUsageBit::kAllTexture));
 	ANKI_ASSERT(offset + range <= m_size);
 	ANKI_ASSERT(offset + range <= m_size);
 
 
-	ANKI_ASSERT(isAligned(getGrManagerImpl().getDeviceCapabilities().m_textureBufferBindOffsetAlignment, offset)
-				&& "Offset not aligned");
+	ANKI_ASSERT(isAligned(getGrManagerImpl().getDeviceCapabilities().m_textureBufferBindOffsetAlignment, offset) && "Offset not aligned");
 
 
-	ANKI_ASSERT((range % getFormatInfo(fmt).m_texelSize) == 0
-				&& "Range doesn't align with the number of texel elements");
+	ANKI_ASSERT((range % getFormatInfo(fmt).m_texelSize) == 0 && "Range doesn't align with the number of texel elements");
 
 
 	[[maybe_unused]] const PtrSize elementCount = range / getFormatInfo(fmt).m_texelSize;
 	[[maybe_unused]] const PtrSize elementCount = range / getFormatInfo(fmt).m_texelSize;
 	ANKI_ASSERT(elementCount <= getGrManagerImpl().getPhysicalDeviceProperties().limits.maxTexelBufferElements);
 	ANKI_ASSERT(elementCount <= getGrManagerImpl().getPhysicalDeviceProperties().limits.maxTexelBufferElements);

+ 2 - 3
AnKi/Gr/Vulkan/BufferImpl.h

@@ -56,9 +56,8 @@ public:
 		return m_actualSize;
 		return m_actualSize;
 	}
 	}
 
 
-	void computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages,
-							VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
-							VkAccessFlags& dstAccesses) const;
+	void computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
+							VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const;
 
 
 	ANKI_FORCE_INLINE void flush(PtrSize offset, PtrSize range) const
 	ANKI_FORCE_INLINE void flush(PtrSize offset, PtrSize range) const
 	{
 	{

+ 79 - 67
AnKi/Gr/Vulkan/CommandBuffer.cpp

@@ -38,10 +38,9 @@ void CommandBuffer::flush(ConstWeakArray<FencePtr> waitFences, FencePtr* signalF
 		}
 		}
 
 
 		MicroSemaphorePtr signalSemaphore;
 		MicroSemaphorePtr signalSemaphore;
-		getGrManagerImpl().flushCommandBuffer(
-			self.getMicroCommandBuffer(), self.renderedToDefaultFramebuffer(),
-			WeakArray<MicroSemaphorePtr>(waitSemaphores.getBegin(), waitFences.getSize()),
-			(signalFence) ? &signalSemaphore : nullptr);
+		getGrManagerImpl().flushCommandBuffer(self.getMicroCommandBuffer(), self.renderedToDefaultFramebuffer(),
+											  WeakArray<MicroSemaphorePtr>(waitSemaphores.getBegin(), waitFences.getSize()),
+											  (signalFence) ? &signalSemaphore : nullptr);
 
 
 		if(signalFence)
 		if(signalFence)
 		{
 		{
@@ -57,8 +56,7 @@ void CommandBuffer::flush(ConstWeakArray<FencePtr> waitFences, FencePtr* signalF
 	}
 	}
 }
 }
 
 
-void CommandBuffer::bindVertexBuffer(U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize stride,
-									 VertexStepRate stepRate)
+void CommandBuffer::bindVertexBuffer(U32 binding, Buffer* buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindVertexBufferInternal(binding, buff, offset, stride, stepRate);
 	self.bindVertexBufferInternal(binding, buff, offset, stride, stepRate);
@@ -70,7 +68,7 @@ void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, Format fmt
 	self.setVertexAttributeInternal(location, buffBinding, fmt, relativeOffset);
 	self.setVertexAttributeInternal(location, buffBinding, fmt, relativeOffset);
 }
 }
 
 
-void CommandBuffer::bindIndexBuffer(const BufferPtr& buff, PtrSize offset, IndexType type)
+void CommandBuffer::bindIndexBuffer(Buffer* buff, PtrSize offset, IndexType type)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindIndexBufferInternal(buff, offset, type);
 	self.bindIndexBufferInternal(buff, offset, type);
@@ -112,8 +110,8 @@ void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 	self.setPolygonOffsetInternal(factor, units);
 	self.setPolygonOffsetInternal(factor, units);
 }
 }
 
 
-void CommandBuffer::setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail,
-										 StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass)
+void CommandBuffer::setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
+										 StencilOperation stencilPassDepthPass)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.setStencilOperationsInternal(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
 	self.setStencilOperationsInternal(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
@@ -167,8 +165,7 @@ void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 	self.setColorChannelWriteMaskInternal(attachment, mask);
 	self.setColorChannelWriteMaskInternal(attachment, mask);
 }
 }
 
 
-void CommandBuffer::setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA,
-									BlendFactor dstA)
+void CommandBuffer::setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.setBlendFactorsInternal(attachment, srcRgb, dstRgb, srcA, dstA);
 	self.setBlendFactorsInternal(attachment, srcRgb, dstRgb, srcA, dstA);
@@ -180,53 +177,49 @@ void CommandBuffer::setBlendOperation(U32 attachment, BlendOperation funcRgb, Bl
 	self.setBlendOperationInternal(attachment, funcRgb, funcA);
 	self.setBlendOperationInternal(attachment, funcRgb, funcA);
 }
 }
 
 
-void CommandBuffer::bindTextureAndSampler(U32 set, U32 binding, const TextureViewPtr& texView,
-										  const SamplerPtr& sampler, U32 arrayIdx)
+void CommandBuffer::bindTextureAndSampler(U32 set, U32 binding, TextureView* texView, Sampler* sampler, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindTextureAndSamplerInternal(set, binding, texView, sampler, arrayIdx);
 	self.bindTextureAndSamplerInternal(set, binding, texView, sampler, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindTexture(U32 set, U32 binding, const TextureViewPtr& texView, U32 arrayIdx)
+void CommandBuffer::bindTexture(U32 set, U32 binding, TextureView* texView, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindTextureInternal(set, binding, texView, arrayIdx);
 	self.bindTextureInternal(set, binding, texView, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindSampler(U32 set, U32 binding, const SamplerPtr& sampler, U32 arrayIdx)
+void CommandBuffer::bindSampler(U32 set, U32 binding, Sampler* sampler, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindSamplerInternal(set, binding, sampler, arrayIdx);
 	self.bindSamplerInternal(set, binding, sampler, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-									  U32 arrayIdx)
+void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindUniformBufferInternal(set, binding, buff, offset, range, arrayIdx);
 	self.bindUniformBufferInternal(set, binding, buff, offset, range, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-									  U32 arrayIdx)
+void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindStorageBufferInternal(set, binding, buff, offset, range, arrayIdx);
 	self.bindStorageBufferInternal(set, binding, buff, offset, range, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindImage(U32 set, U32 binding, const TextureViewPtr& img, U32 arrayIdx)
+void CommandBuffer::bindImage(U32 set, U32 binding, TextureView* img, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindImageInternal(set, binding, img, arrayIdx);
 	self.bindImageInternal(set, binding, img, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindAccelerationStructure(U32 set, U32 binding, const AccelerationStructurePtr& as, U32 arrayIdx)
+void CommandBuffer::bindAccelerationStructure(U32 set, U32 binding, AccelerationStructure* as, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindAccelerationStructureInternal(set, binding, as, arrayIdx);
 	self.bindAccelerationStructureInternal(set, binding, as, arrayIdx);
 }
 }
 
 
-void CommandBuffer::bindReadOnlyTextureBuffer(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset,
-											  PtrSize range, Format fmt, U32 arrayIdx)
+void CommandBuffer::bindReadOnlyTextureBuffer(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, Format fmt, U32 arrayIdx)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindReadOnlyTextureBufferInternal(set, binding, buff, offset, range, fmt, arrayIdx);
 	self.bindReadOnlyTextureBufferInternal(set, binding, buff, offset, range, fmt, arrayIdx);
@@ -238,16 +231,14 @@ void CommandBuffer::bindAllBindless(U32 set)
 	self.bindAllBindlessInternal(set);
 	self.bindAllBindlessInternal(set);
 }
 }
 
 
-void CommandBuffer::bindShaderProgram(const ShaderProgramPtr& prog)
+void CommandBuffer::bindShaderProgram(ShaderProgram* prog)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.bindShaderProgramInternal(prog);
 	self.bindShaderProgramInternal(prog);
 }
 }
 
 
-void CommandBuffer::beginRenderPass(const FramebufferPtr& fb,
-									const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
-									TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width,
-									U32 height)
+void CommandBuffer::beginRenderPass(Framebuffer* fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
+									TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.beginRenderPassInternal(fb, colorAttachmentUsages, depthStencilAttachmentUsage, minx, miny, width, height);
 	self.beginRenderPassInternal(fb, colorAttachmentUsages, depthStencilAttachmentUsage, minx, miny, width, height);
@@ -265,30 +256,42 @@ void CommandBuffer::setVrsRate(VrsRate rate)
 	self.setVrsRateInternal(rate);
 	self.setVrsRateInternal(rate);
 }
 }
 
 
-void CommandBuffer::drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex,
-								 U32 baseVertex, U32 baseInstance)
+void CommandBuffer::drawIndexed(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.drawElementsInternal(topology, count, instanceCount, firstIndex, baseVertex, baseInstance);
+	self.drawIndexedInternal(topology, count, instanceCount, firstIndex, baseVertex, baseInstance);
 }
 }
 
 
-void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
+void CommandBuffer::draw(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.drawArraysInternal(topology, count, instanceCount, first, baseInstance);
+	self.drawInternal(topology, count, instanceCount, first, baseInstance);
 }
 }
 
 
-void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, const BufferPtr& buff)
+void CommandBuffer::drawIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* buff)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.drawArraysIndirectInternal(topology, drawCount, offset, buff);
+	self.drawIndirectInternal(topology, drawCount, offset, buff);
 }
 }
 
 
-void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset,
-										 const BufferPtr& buff)
+void CommandBuffer::drawIndexedIndirectCount(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset, U32 argBufferStride,
+											 Buffer* countBuffer, PtrSize countBufferOffset, U32 maxDrawCount)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.drawElementsIndirectInternal(topology, drawCount, offset, buff);
+	self.drawIndexedIndirectCountInternal(topology, argBuffer, argBufferOffset, argBufferStride, countBuffer, countBufferOffset, maxDrawCount);
+}
+
+void CommandBuffer::drawIndirectCount(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset, U32 argBufferStride,
+									  Buffer* countBuffer, PtrSize countBufferOffset, U32 maxDrawCount)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawIndirectCountInternal(topology, argBuffer, argBufferOffset, argBufferStride, countBuffer, countBufferOffset, maxDrawCount);
+}
+
+void CommandBuffer::drawIndexedIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* buff)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawIndexedIndirectInternal(topology, drawCount, offset, buff);
 }
 }
 
 
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
@@ -297,82 +300,79 @@ void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupC
 	self.dispatchComputeInternal(groupCountX, groupCountY, groupCountZ);
 	self.dispatchComputeInternal(groupCountX, groupCountY, groupCountZ);
 }
 }
 
 
-void CommandBuffer::traceRays(const BufferPtr& sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize,
-							  U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width, U32 height, U32 depth)
+void CommandBuffer::dispatchComputeIndirect(Buffer* argBuffer, PtrSize argBufferOffset)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.dispatchComputeIndirectInternal(argBuffer, argBufferOffset);
+}
+
+void CommandBuffer::traceRays(Buffer* sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize, U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width,
+							  U32 height, U32 depth)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.traceRaysInternal(sbtBuffer, sbtBufferOffset, sbtRecordSize, hitGroupSbtRecordCount, rayTypeCount, width,
-						   height, depth);
+	self.traceRaysInternal(sbtBuffer, sbtBufferOffset, sbtRecordSize, hitGroupSbtRecordCount, rayTypeCount, width, height, depth);
 }
 }
 
 
-void CommandBuffer::generateMipmaps2d(const TextureViewPtr& texView)
+void CommandBuffer::generateMipmaps2d(TextureView* texView)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.generateMipmaps2dInternal(texView);
 	self.generateMipmaps2dInternal(texView);
 }
 }
 
 
-void CommandBuffer::generateMipmaps3d([[maybe_unused]] const TextureViewPtr& texView)
+void CommandBuffer::generateMipmaps3d([[maybe_unused]] TextureView* texView)
 {
 {
 	ANKI_ASSERT(!"TODO");
 	ANKI_ASSERT(!"TODO");
 }
 }
 
 
-void CommandBuffer::blitTextureViews([[maybe_unused]] const TextureViewPtr& srcView,
-									 [[maybe_unused]] const TextureViewPtr& destView)
+void CommandBuffer::blitTextureViews([[maybe_unused]] TextureView* srcView, [[maybe_unused]] TextureView* destView)
 {
 {
 	ANKI_ASSERT(!"TODO");
 	ANKI_ASSERT(!"TODO");
 }
 }
 
 
-void CommandBuffer::clearTextureView(const TextureViewPtr& texView, const ClearValue& clearValue)
+void CommandBuffer::clearTextureView(TextureView* texView, const ClearValue& clearValue)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.clearTextureViewInternal(texView, clearValue);
 	self.clearTextureViewInternal(texView, clearValue);
 }
 }
 
 
-void CommandBuffer::copyBufferToTextureView(const BufferPtr& buff, PtrSize offset, PtrSize range,
-											const TextureViewPtr& texView)
+void CommandBuffer::copyBufferToTextureView(Buffer* buff, PtrSize offset, PtrSize range, TextureView* texView)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.copyBufferToTextureViewInternal(buff, offset, range, texView);
 	self.copyBufferToTextureViewInternal(buff, offset, range, texView);
 }
 }
 
 
-void CommandBuffer::fillBuffer(const BufferPtr& buff, PtrSize offset, PtrSize size, U32 value)
+void CommandBuffer::fillBuffer(Buffer* buff, PtrSize offset, PtrSize size, U32 value)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.fillBufferInternal(buff, offset, size, value);
 	self.fillBufferInternal(buff, offset, size, value);
 }
 }
 
 
-void CommandBuffer::writeOcclusionQueriesResultToBuffer(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset,
-														const BufferPtr& buff)
+void CommandBuffer::writeOcclusionQueriesResultToBuffer(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset, Buffer* buff)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.writeOcclusionQueriesResultToBufferInternal(queries, offset, buff);
 	self.writeOcclusionQueriesResultToBufferInternal(queries, offset, buff);
 }
 }
 
 
-void CommandBuffer::copyBufferToBuffer(const BufferPtr& src, const BufferPtr& dst,
-									   ConstWeakArray<CopyBufferToBufferInfo> copies)
+void CommandBuffer::copyBufferToBuffer(Buffer* src, Buffer* dst, ConstWeakArray<CopyBufferToBufferInfo> copies)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.copyBufferToBufferInternal(src, dst, copies);
 	self.copyBufferToBufferInternal(src, dst, copies);
 }
 }
 
 
-void CommandBuffer::buildAccelerationStructure(const AccelerationStructurePtr& as)
+void CommandBuffer::buildAccelerationStructure(AccelerationStructure* as, Buffer* scratchBuffer, PtrSize scratchBufferOffset)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.buildAccelerationStructureInternal(as);
+	self.buildAccelerationStructureInternal(as, scratchBuffer, scratchBufferOffset);
 }
 }
 
 
-void CommandBuffer::upscale(const GrUpscalerPtr& upscaler, const TextureViewPtr& inColor,
-							const TextureViewPtr& outUpscaledColor, const TextureViewPtr& motionVectors,
-							const TextureViewPtr& depth, const TextureViewPtr& exposure, const Bool resetAccumulation,
-							const Vec2& jitterOffset, const Vec2& motionVectorsScale)
+void CommandBuffer::upscale(GrUpscaler* upscaler, TextureView* inColor, TextureView* outUpscaledColor, TextureView* motionVectors, TextureView* depth,
+							TextureView* exposure, Bool resetAccumulation, const Vec2& jitterOffset, const Vec2& motionVectorsScale)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.upscaleInternal(upscaler, inColor, outUpscaledColor, motionVectors, depth, exposure, resetAccumulation,
-						 jitterOffset, motionVectorsScale);
+	self.upscaleInternal(upscaler, inColor, outUpscaledColor, motionVectors, depth, exposure, resetAccumulation, jitterOffset, motionVectorsScale);
 }
 }
 
 
-void CommandBuffer::setPipelineBarrier(ConstWeakArray<TextureBarrierInfo> textures,
-									   ConstWeakArray<BufferBarrierInfo> buffers,
+void CommandBuffer::setPipelineBarrier(ConstWeakArray<TextureBarrierInfo> textures, ConstWeakArray<BufferBarrierInfo> buffers,
 									   ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures)
 									   ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
@@ -385,13 +385,13 @@ void CommandBuffer::resetOcclusionQueries(ConstWeakArray<OcclusionQuery*> querie
 	self.resetOcclusionQueriesInternal(queries);
 	self.resetOcclusionQueriesInternal(queries);
 }
 }
 
 
-void CommandBuffer::beginOcclusionQuery(const OcclusionQueryPtr& query)
+void CommandBuffer::beginOcclusionQuery(OcclusionQuery* query)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.beginOcclusionQueryInternal(query);
 	self.beginOcclusionQueryInternal(query);
 }
 }
 
 
-void CommandBuffer::endOcclusionQuery(const OcclusionQueryPtr& query)
+void CommandBuffer::endOcclusionQuery(OcclusionQuery* query)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.endOcclusionQueryInternal(query);
 	self.endOcclusionQueryInternal(query);
@@ -409,7 +409,7 @@ void CommandBuffer::resetTimestampQueries(ConstWeakArray<TimestampQuery*> querie
 	self.resetTimestampQueriesInternal(queries);
 	self.resetTimestampQueriesInternal(queries);
 }
 }
 
 
-void CommandBuffer::writeTimestamp(const TimestampQueryPtr& query)
+void CommandBuffer::writeTimestamp(TimestampQuery* query)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.writeTimestampInternal(query);
 	self.writeTimestampInternal(query);
@@ -439,4 +439,16 @@ void CommandBuffer::setLineWidth(F32 width)
 	self.setLineWidthInternal(width);
 	self.setLineWidthInternal(width);
 }
 }
 
 
+void CommandBuffer::pushDebugMarker(CString name, Vec3 color)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.pushDebugMarkerInternal(name, color);
+}
+
+void CommandBuffer::popDebugMarker()
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.popDebugMarkerInternal();
+}
+
 } // end namespace anki
 } // end namespace anki

+ 8 - 8
AnKi/Gr/Vulkan/CommandBufferFactory.cpp

@@ -5,11 +5,13 @@
 
 
 #include <AnKi/Gr/Vulkan/CommandBufferFactory.h>
 #include <AnKi/Gr/Vulkan/CommandBufferFactory.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/Tracer.h>
+#include <AnKi/Core/StatsSet.h>
 
 
 namespace anki {
 namespace anki {
 
 
-static VulkanQueueType getQueueTypeFromCommandBufferFlags(CommandBufferFlag flags,
-														  const VulkanQueueFamilies& queueFamilies)
+static StatCounter g_commandBufferCountStatVar(StatCategory::kMisc, "CommandBufferCount", StatFlag::kNone);
+
+static VulkanQueueType getQueueTypeFromCommandBufferFlags(CommandBufferFlag flags, const VulkanQueueFamilies& queueFamilies)
 {
 {
 	ANKI_ASSERT(!!(flags & CommandBufferFlag::kGeneralWork) ^ !!(flags & CommandBufferFlag::kComputeWork));
 	ANKI_ASSERT(!!(flags & CommandBufferFlag::kGeneralWork) ^ !!(flags & CommandBufferFlag::kComputeWork));
 	if(!(flags & CommandBufferFlag::kGeneralWork) && queueFamilies[VulkanQueueType::kCompute] != kMaxU32)
 	if(!(flags & CommandBufferFlag::kGeneralWork) && queueFamilies[VulkanQueueType::kCompute] != kMaxU32)
@@ -38,8 +40,7 @@ MicroCommandBuffer::~MicroCommandBuffer()
 		vkFreeCommandBuffers(getVkDevice(), m_threadAlloc->m_pools[m_queue], 1, &m_handle);
 		vkFreeCommandBuffers(getVkDevice(), m_threadAlloc->m_pools[m_queue], 1, &m_handle);
 		m_handle = {};
 		m_handle = {};
 
 
-		[[maybe_unused]] const U32 count = m_threadAlloc->m_factory->m_createdCmdBufferCount.fetchSub(1);
-		ANKI_ASSERT(count > 0);
+		g_commandBufferCountStatVar.decrement(1_U64);
 	}
 	}
 }
 }
 
 
@@ -124,13 +125,14 @@ Error CommandBufferThreadAllocator::newCommandBuffer(CommandBufferFlag cmdbFlags
 		ci.commandBufferCount = 1;
 		ci.commandBufferCount = 1;
 
 
 		ANKI_TRACE_INC_COUNTER(VkCommandBufferCreate, 1);
 		ANKI_TRACE_INC_COUNTER(VkCommandBufferCreate, 1);
+		g_commandBufferCountStatVar.increment(1_U64);
 		VkCommandBuffer cmdb;
 		VkCommandBuffer cmdb;
 		ANKI_VK_CHECK(vkAllocateCommandBuffers(getVkDevice(), &ci, &cmdb));
 		ANKI_VK_CHECK(vkAllocateCommandBuffers(getVkDevice(), &ci, &cmdb));
 
 
 		MicroCommandBuffer* newCmdb = newInstance<MicroCommandBuffer>(GrMemoryPool::getSingleton(), this);
 		MicroCommandBuffer* newCmdb = newInstance<MicroCommandBuffer>(GrMemoryPool::getSingleton(), this);
 
 
-		newCmdb->m_fastPool.init(GrMemoryPool::getSingleton().getAllocationCallback(),
-								 GrMemoryPool::getSingleton().getAllocationCallbackUserData(), 256_KB, 2.0f);
+		newCmdb->m_fastPool.init(GrMemoryPool::getSingleton().getAllocationCallback(), GrMemoryPool::getSingleton().getAllocationCallbackUserData(),
+								 256_KB, 2.0f);
 
 
 		for(DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>& arr : newCmdb->m_objectRefs)
 		for(DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>& arr : newCmdb->m_objectRefs)
 		{
 		{
@@ -142,8 +144,6 @@ Error CommandBufferThreadAllocator::newCommandBuffer(CommandBufferFlag cmdbFlags
 		newCmdb->m_queue = queue;
 		newCmdb->m_queue = queue;
 
 
 		out = newCmdb;
 		out = newCmdb;
-
-		m_factory->m_createdCmdBufferCount.fetchAdd(1);
 	}
 	}
 	else
 	else
 	{
 	{

+ 6 - 25
AnKi/Gr/Vulkan/CommandBufferFactory.h

@@ -52,16 +52,15 @@ public:
 		return m_refcount.load();
 		return m_refcount.load();
 	}
 	}
 
 
-	void setFence(MicroFencePtr& fence)
+	void setFence(MicroFence* fence)
 	{
 	{
 		ANKI_ASSERT(!(m_flags & CommandBufferFlag::kSecondLevel));
 		ANKI_ASSERT(!(m_flags & CommandBufferFlag::kSecondLevel));
-		ANKI_ASSERT(!m_fence.isCreated());
-		m_fence = fence;
+		m_fence.reset(fence);
 	}
 	}
 
 
-	MicroFencePtr& getFence()
+	MicroFence* getFence() const
 	{
 	{
-		return m_fence;
+		return m_fence.tryGet();
 	}
 	}
 
 
 	/// Interface method.
 	/// Interface method.
@@ -81,15 +80,11 @@ public:
 		return m_handle;
 		return m_handle;
 	}
 	}
 
 
-	template<typename T>
-	void pushObjectRef(const GrObjectPtrT<T>& x)
-	{
-		pushToArray(m_objectRefs[T::kClassType], x.get());
-	}
-
 	template<typename T>
 	template<typename T>
 	void pushObjectRef(T* x)
 	void pushObjectRef(T* x)
 	{
 	{
+		ANKI_ASSERT(T::kClassType != GrObjectType::kTexture && T::kClassType != GrObjectType::kTextureView && T::kClassType != GrObjectType::kBuffer
+					&& "No need to push references of buffers and textures");
 		pushToArray(m_objectRefs[T::kClassType], x);
 		pushToArray(m_objectRefs[T::kClassType], x);
 	}
 	}
 
 
@@ -143,12 +138,6 @@ private:
 	}
 	}
 };
 };
 
 
-template<>
-inline void MicroCommandBuffer::pushObjectRef<GrObject>(const GrObjectPtr& x)
-{
-	pushToArray(m_objectRefs[x->getType()], x.get());
-}
-
 /// Deleter.
 /// Deleter.
 class MicroCommandBufferPtrDeleter
 class MicroCommandBufferPtrDeleter
 {
 {
@@ -224,19 +213,11 @@ public:
 	/// Request a new command buffer.
 	/// Request a new command buffer.
 	Error newCommandBuffer(ThreadId tid, CommandBufferFlag cmdbFlags, MicroCommandBufferPtr& ptr);
 	Error newCommandBuffer(ThreadId tid, CommandBufferFlag cmdbFlags, MicroCommandBufferPtr& ptr);
 
 
-	/// Stats.
-	U32 getCreatedCommandBufferCount() const
-	{
-		return m_createdCmdBufferCount.load();
-	}
-
 private:
 private:
 	VulkanQueueFamilies m_queueFamilies;
 	VulkanQueueFamilies m_queueFamilies;
 
 
 	GrDynamicArray<CommandBufferThreadAllocator*> m_threadAllocs;
 	GrDynamicArray<CommandBufferThreadAllocator*> m_threadAllocs;
 	RWMutex m_threadAllocMtx;
 	RWMutex m_threadAllocMtx;
-
-	Atomic<U32> m_createdCmdBufferCount = {0};
 };
 };
 /// @}
 /// @}
 
 

+ 46 - 82
AnKi/Gr/Vulkan/CommandBufferImpl.cpp

@@ -33,6 +33,10 @@ CommandBufferImpl::~CommandBufferImpl()
 	{
 	{
 		ANKI_VK_LOGW("Command buffer was not flushed");
 		ANKI_VK_LOGW("Command buffer was not flushed");
 	}
 	}
+
+#if ANKI_EXTRA_CHECKS
+	ANKI_ASSERT(m_debugMarkersPushed == 0);
+#endif
 }
 }
 
 
 Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
@@ -51,7 +55,7 @@ Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 		m_activeFb = init.m_framebuffer;
 		m_activeFb = init.m_framebuffer;
 		m_colorAttachmentUsages = init.m_colorAttachmentUsages;
 		m_colorAttachmentUsages = init.m_colorAttachmentUsages;
 		m_depthStencilAttachmentUsage = init.m_depthStencilAttachmentUsage;
 		m_depthStencilAttachmentUsage = init.m_depthStencilAttachmentUsage;
-		m_state.beginRenderPass(static_cast<FramebufferImpl*>(m_activeFb.get()));
+		m_state.beginRenderPass(static_cast<FramebufferImpl*>(m_activeFb));
 		m_microCmdb->pushObjectRef(m_activeFb);
 		m_microCmdb->pushObjectRef(m_activeFb);
 	}
 	}
 
 
@@ -62,6 +66,8 @@ Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 
 
 	m_state.setVrsCapable(getGrManagerImpl().getDeviceCapabilities().m_vrs);
 	m_state.setVrsCapable(getGrManagerImpl().getDeviceCapabilities().m_vrs);
 
 
+	m_debugMarkers = !!(getGrManagerImpl().getExtensions() & VulkanExtensions::kEXT_debug_utils);
+
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
@@ -118,9 +124,8 @@ void CommandBufferImpl::beginRecording()
 	}
 	}
 }
 }
 
 
-void CommandBufferImpl::beginRenderPassInternal(
-	const FramebufferPtr& fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
-	TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height)
+void CommandBufferImpl::beginRenderPassInternal(Framebuffer* fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
+												TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height)
 {
 {
 	commandCommon();
 	commandCommon();
 	ANKI_ASSERT(!insideRenderPass());
 	ANKI_ASSERT(!insideRenderPass());
@@ -206,8 +211,6 @@ void CommandBufferImpl::beginRenderPassInternal()
 	bi.renderArea.extent.width = m_renderArea[2];
 	bi.renderArea.extent.width = m_renderArea[2];
 	bi.renderArea.extent.height = m_renderArea[3];
 	bi.renderArea.extent.height = m_renderArea[3];
 
 
-	getGrManagerImpl().beginMarker(m_handle, impl.getName(), Vec3(0.0f, 1.0f, 0.0f));
-
 #if !ANKI_PLATFORM_MOBILE
 #if !ANKI_PLATFORM_MOBILE
 	// nVidia SRI cache workaround
 	// nVidia SRI cache workaround
 	if(impl.hasSri())
 	if(impl.hasSri())
@@ -247,9 +250,8 @@ void CommandBufferImpl::endRenderPassInternal()
 	subpassEndInfo.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
 	subpassEndInfo.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
 
 
 	vkCmdEndRenderPass2KHR(m_handle, &subpassEndInfo);
 	vkCmdEndRenderPass2KHR(m_handle, &subpassEndInfo);
-	getGrManagerImpl().endMarker(m_handle);
 
 
-	m_activeFb.reset(nullptr);
+	m_activeFb = nullptr;
 	m_state.endRenderPass();
 	m_state.endRenderPass();
 
 
 	// After pushing second level command buffers the state is undefined. Reset the tracker and rebind the dynamic state
 	// After pushing second level command buffers the state is undefined. Reset the tracker and rebind the dynamic state
@@ -305,7 +307,7 @@ void CommandBufferImpl::endRecording()
 #endif
 #endif
 }
 }
 
 
-void CommandBufferImpl::generateMipmaps2dInternal(const TextureViewPtr& texView)
+void CommandBufferImpl::generateMipmaps2dInternal(TextureView* texView)
 {
 {
 	commandCommon();
 	commandCommon();
 
 
@@ -332,24 +334,20 @@ void CommandBufferImpl::generateMipmaps2dInternal(const TextureViewPtr& texView)
 		if(i > 0)
 		if(i > 0)
 		{
 		{
 			VkImageSubresourceRange range;
 			VkImageSubresourceRange range;
-			tex.computeVkImageSubresourceRange(TextureSubresourceInfo(TextureSurfaceInfo(i, 0, face, layer), aspect),
-											   range);
+			tex.computeVkImageSubresourceRange(TextureSubresourceInfo(TextureSurfaceInfo(i, 0, face, layer), aspect), range);
 
 
-			setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
-							VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
-							VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
+			setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+							VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
 							range);
 							range);
 		}
 		}
 
 
 		// Transition destination
 		// Transition destination
 		{
 		{
 			VkImageSubresourceRange range;
 			VkImageSubresourceRange range;
-			tex.computeVkImageSubresourceRange(
-				TextureSubresourceInfo(TextureSurfaceInfo(i + 1, 0, face, layer), aspect), range);
+			tex.computeVkImageSubresourceRange(TextureSubresourceInfo(TextureSurfaceInfo(i + 1, 0, face, layer), aspect), range);
 
 
-			setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED,
-							VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
-							VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex.m_imageHandle, range);
+			setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_PIPELINE_STAGE_TRANSFER_BIT,
+							VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex.m_imageHandle, range);
 		}
 		}
 
 
 		// Setup the blit struct
 		// Setup the blit struct
@@ -393,17 +391,12 @@ void CommandBufferImpl::generateMipmaps2dInternal(const TextureViewPtr& texView)
 		blit.dstOffsets[0] = {0, 0, 0};
 		blit.dstOffsets[0] = {0, 0, 0};
 		blit.dstOffsets[1] = {dstWidth, dstHeight, 1};
 		blit.dstOffsets[1] = {dstWidth, dstHeight, 1};
 
 
-		vkCmdBlitImage(m_handle, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
-					   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
-					   (!!aspect) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
+		vkCmdBlitImage(m_handle, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
+					   &blit, (!!aspect) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
 	}
 	}
-
-	// Hold the reference
-	m_microCmdb->pushObjectRef(texView);
 }
 }
 
 
-void CommandBufferImpl::copyBufferToTextureViewInternal(const BufferPtr& buff, PtrSize offset,
-														[[maybe_unused]] PtrSize range, const TextureViewPtr& texView)
+void CommandBufferImpl::copyBufferToTextureViewInternal(Buffer* buff, PtrSize offset, [[maybe_unused]] PtrSize range, TextureView* texView)
 {
 {
 	commandCommon();
 	commandCommon();
 
 
@@ -415,8 +408,7 @@ void CommandBufferImpl::copyBufferToTextureViewInternal(const BufferPtr& buff, P
 	const Bool is3D = tex.getTextureType() == TextureType::k3D;
 	const Bool is3D = tex.getTextureType() == TextureType::k3D;
 	const VkImageAspectFlags aspect = convertImageAspect(view.getSubresource().m_depthStencilAspect);
 	const VkImageAspectFlags aspect = convertImageAspect(view.getSubresource().m_depthStencilAspect);
 
 
-	const TextureSurfaceInfo surf(view.getSubresource().m_firstMipmap, view.getSubresource().m_firstFace, 0,
-								  view.getSubresource().m_firstLayer);
+	const TextureSurfaceInfo surf(view.getSubresource().m_firstMipmap, view.getSubresource().m_firstFace, 0, view.getSubresource().m_firstLayer);
 	const TextureVolumeInfo vol(view.getSubresource().m_firstMipmap);
 	const TextureVolumeInfo vol(view.getSubresource().m_firstMipmap);
 
 
 	// Compute the sizes of the mip
 	// Compute the sizes of the mip
@@ -448,11 +440,7 @@ void CommandBufferImpl::copyBufferToTextureViewInternal(const BufferPtr& buff, P
 	region.bufferImageHeight = 0;
 	region.bufferImageHeight = 0;
 	region.bufferRowLength = 0;
 	region.bufferRowLength = 0;
 
 
-	vkCmdCopyBufferToImage(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), tex.m_imageHandle, layout, 1,
-						   &region);
-
-	m_microCmdb->pushObjectRef(texView);
-	m_microCmdb->pushObjectRef(buff);
+	vkCmdCopyBufferToImage(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), tex.m_imageHandle, layout, 1, &region);
 }
 }
 
 
 void CommandBufferImpl::rebindDynamicState()
 void CommandBufferImpl::rebindDynamicState()
@@ -467,8 +455,7 @@ void CommandBufferImpl::rebindDynamicState()
 	// Rebind the stencil compare mask
 	// Rebind the stencil compare mask
 	if(m_stencilCompareMasks[0] == m_stencilCompareMasks[1])
 	if(m_stencilCompareMasks[0] == m_stencilCompareMasks[1])
 	{
 	{
-		vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
-								   m_stencilCompareMasks[0]);
+		vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilCompareMasks[0]);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -479,8 +466,7 @@ void CommandBufferImpl::rebindDynamicState()
 	// Rebind the stencil write mask
 	// Rebind the stencil write mask
 	if(m_stencilWriteMasks[0] == m_stencilWriteMasks[1])
 	if(m_stencilWriteMasks[0] == m_stencilWriteMasks[1])
 	{
 	{
-		vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
-								 m_stencilWriteMasks[0]);
+		vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilWriteMasks[0]);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -491,8 +477,7 @@ void CommandBufferImpl::rebindDynamicState()
 	// Rebind the stencil reference
 	// Rebind the stencil reference
 	if(m_stencilReferenceMasks[0] == m_stencilReferenceMasks[1])
 	if(m_stencilReferenceMasks[0] == m_stencilReferenceMasks[1])
 	{
 	{
-		vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
-								 m_stencilReferenceMasks[0]);
+		vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilReferenceMasks[0]);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -501,31 +486,24 @@ void CommandBufferImpl::rebindDynamicState()
 	}
 	}
 }
 }
 
 
-void CommandBufferImpl::buildAccelerationStructureInternal(const AccelerationStructurePtr& as)
+void CommandBufferImpl::buildAccelerationStructureInternal(AccelerationStructure* as, Buffer* scratchBuffer, PtrSize scratchBufferOffset)
 {
 {
+	ANKI_ASSERT(as && scratchBuffer);
+	ANKI_ASSERT(as->getBuildScratchBufferSize() + scratchBufferOffset <= scratchBuffer->getSize());
+
 	commandCommon();
 	commandCommon();
 
 
 	// Get objects
 	// Get objects
 	const AccelerationStructureImpl& asImpl = static_cast<AccelerationStructureImpl&>(*as);
 	const AccelerationStructureImpl& asImpl = static_cast<AccelerationStructureImpl&>(*as);
 
 
-	// Create the scrach buffer
-	BufferInitInfo bufferInit;
-	bufferInit.m_usage = PrivateBufferUsageBit::kAccelerationStructureBuildScratch;
-	bufferInit.m_size = asImpl.getBuildScratchBufferSize();
-	BufferPtr scratchBuff = getGrManagerImpl().newBuffer(bufferInit);
-
 	// Create the build info
 	// Create the build info
 	VkAccelerationStructureBuildGeometryInfoKHR buildInfo;
 	VkAccelerationStructureBuildGeometryInfoKHR buildInfo;
 	VkAccelerationStructureBuildRangeInfoKHR rangeInfo;
 	VkAccelerationStructureBuildRangeInfoKHR rangeInfo;
-	asImpl.generateBuildInfo(scratchBuff->getGpuAddress(), buildInfo, rangeInfo);
+	asImpl.generateBuildInfo(scratchBuffer->getGpuAddress() + scratchBufferOffset, buildInfo, rangeInfo);
 
 
-	// Do the command
+	// Run the command
 	Array<const VkAccelerationStructureBuildRangeInfoKHR*, 1> pRangeInfos = {&rangeInfo};
 	Array<const VkAccelerationStructureBuildRangeInfoKHR*, 1> pRangeInfos = {&rangeInfo};
 	vkCmdBuildAccelerationStructuresKHR(m_handle, 1, &buildInfo, &pRangeInfos[0]);
 	vkCmdBuildAccelerationStructuresKHR(m_handle, 1, &buildInfo, &pRangeInfos[0]);
-
-	// Push refs
-	m_microCmdb->pushObjectRef(as);
-	m_microCmdb->pushObjectRef(scratchBuff);
 }
 }
 
 
 #if ANKI_DLSS
 #if ANKI_DLSS
@@ -542,15 +520,12 @@ static NVSDK_NGX_Resource_VK getNGXResourceFromAnkiTexture(const TextureViewImpl
 	const Bool isUAV = !!(tex.m_vkUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT);
 	const Bool isUAV = !!(tex.m_vkUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT);
 
 
 	// TODO Not sure if I should pass the width,height of the image or the view
 	// TODO Not sure if I should pass the width,height of the image or the view
-	return NVSDK_NGX_Create_ImageView_Resource_VK(imageView, image, subresourceRange, format, tex.getWidth(),
-												  tex.getHeight(), isUAV);
+	return NVSDK_NGX_Create_ImageView_Resource_VK(imageView, image, subresourceRange, format, tex.getWidth(), tex.getHeight(), isUAV);
 }
 }
 #endif
 #endif
 
 
-void CommandBufferImpl::upscaleInternal(const GrUpscalerPtr& upscaler, const TextureViewPtr& inColor,
-										const TextureViewPtr& outUpscaledColor, const TextureViewPtr& motionVectors,
-										const TextureViewPtr& depth, const TextureViewPtr& exposure,
-										const Bool resetAccumulation, const Vec2& jitterOffset,
+void CommandBufferImpl::upscaleInternal(GrUpscaler* upscaler, TextureView* inColor, TextureView* outUpscaledColor, TextureView* motionVectors,
+										TextureView* depth, TextureView* exposure, const Bool resetAccumulation, const Vec2& jitterOffset,
 										const Vec2& motionVectorsScale)
 										const Vec2& motionVectorsScale)
 {
 {
 #if ANKI_DLSS
 #if ANKI_DLSS
@@ -596,17 +571,13 @@ void CommandBufferImpl::upscaleInternal(const GrUpscalerPtr& upscaler, const Tex
 	vkDlssEvalParams.InMVSubrectBase = renderingOffset;
 	vkDlssEvalParams.InMVSubrectBase = renderingOffset;
 	vkDlssEvalParams.InRenderSubrectDimensions = renderingSize;
 	vkDlssEvalParams.InRenderSubrectDimensions = renderingSize;
 
 
-	getGrManagerImpl().beginMarker(m_handle, "DLSS");
 	NVSDK_NGX_Parameter* dlssParameters = &upscalerImpl.getParameters();
 	NVSDK_NGX_Parameter* dlssParameters = &upscalerImpl.getParameters();
 	NVSDK_NGX_Handle* dlssFeature = &upscalerImpl.getFeature();
 	NVSDK_NGX_Handle* dlssFeature = &upscalerImpl.getFeature();
-	const NVSDK_NGX_Result result =
-		NGX_VULKAN_EVALUATE_DLSS_EXT(m_handle, dlssFeature, dlssParameters, &vkDlssEvalParams);
-	getGrManagerImpl().endMarker(m_handle);
+	const NVSDK_NGX_Result result = NGX_VULKAN_EVALUATE_DLSS_EXT(m_handle, dlssFeature, dlssParameters, &vkDlssEvalParams);
 
 
 	if(NVSDK_NGX_FAILED(result))
 	if(NVSDK_NGX_FAILED(result))
 	{
 	{
-		ANKI_VK_LOGF("Failed to NVSDK_NGX_VULKAN_EvaluateFeature for DLSS, code = 0x%08x, info: %ls", result,
-					 GetNGXResultAsString(result));
+		ANKI_VK_LOGF("Failed to NVSDK_NGX_VULKAN_EvaluateFeature for DLSS, code = 0x%08x, info: %ls", result, GetNGXResultAsString(result));
 	}
 	}
 #else
 #else
 	ANKI_ASSERT(0 && "Not supported");
 	ANKI_ASSERT(0 && "Not supported");
@@ -622,9 +593,8 @@ void CommandBufferImpl::upscaleInternal(const GrUpscalerPtr& upscaler, const Tex
 #endif
 #endif
 }
 }
 
 
-void CommandBufferImpl::setPipelineBarrierInternal(
-	ConstWeakArray<TextureBarrierInfo> textures, ConstWeakArray<BufferBarrierInfo> buffers,
-	ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures)
+void CommandBufferImpl::setPipelineBarrierInternal(ConstWeakArray<TextureBarrierInfo> textures, ConstWeakArray<BufferBarrierInfo> buffers,
+												   ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures)
 {
 {
 	commandCommon();
 	commandCommon();
 
 
@@ -657,8 +627,7 @@ void CommandBufferImpl::setPipelineBarrierInternal(
 
 
 		if(nextUsage == TextureUsageBit::kGenerateMipmaps) [[unlikely]]
 		if(nextUsage == TextureUsageBit::kGenerateMipmaps) [[unlikely]]
 		{
 		{
-			// The transition of the non zero mip levels happens inside CommandBufferImpl::generateMipmapsX so limit the
-			// subresource
+			// The transition of the non zero mip levels happens inside CommandBufferImpl::generateMipmapsX so limit the subresource
 
 
 			ANKI_ASSERT(subresource.m_firstMipmap == 0 && subresource.m_mipmapCount == 1);
 			ANKI_ASSERT(subresource.m_firstMipmap == 0 && subresource.m_mipmapCount == 1);
 		}
 		}
@@ -674,15 +643,12 @@ void CommandBufferImpl::setPipelineBarrierInternal(
 
 
 		VkPipelineStageFlags srcStage;
 		VkPipelineStageFlags srcStage;
 		VkPipelineStageFlags dstStage;
 		VkPipelineStageFlags dstStage;
-		impl.computeBarrierInfo(prevUsage, nextUsage, inf.subresourceRange.baseMipLevel, srcStage, inf.srcAccessMask,
-								dstStage, inf.dstAccessMask);
+		impl.computeBarrierInfo(prevUsage, nextUsage, inf.subresourceRange.baseMipLevel, srcStage, inf.srcAccessMask, dstStage, inf.dstAccessMask);
 		inf.oldLayout = impl.computeLayout(prevUsage, inf.subresourceRange.baseMipLevel);
 		inf.oldLayout = impl.computeLayout(prevUsage, inf.subresourceRange.baseMipLevel);
 		inf.newLayout = impl.computeLayout(nextUsage, inf.subresourceRange.baseMipLevel);
 		inf.newLayout = impl.computeLayout(nextUsage, inf.subresourceRange.baseMipLevel);
 
 
 		srcStageMask |= srcStage;
 		srcStageMask |= srcStage;
 		dstStageMask |= dstStage;
 		dstStageMask |= dstStage;
-
-		m_microCmdb->pushObjectRef(barrier.m_texture);
 	}
 	}
 
 
 	for(const BufferBarrierInfo& barrier : buffers)
 	for(const BufferBarrierInfo& barrier : buffers)
@@ -703,15 +669,15 @@ void CommandBufferImpl::setPipelineBarrierInternal(
 		ANKI_ASSERT(barrier.m_offset < impl.getSize());
 		ANKI_ASSERT(barrier.m_offset < impl.getSize());
 		inf.offset = barrier.m_offset;
 		inf.offset = barrier.m_offset;
 
 
-		if(barrier.m_size == kMaxPtrSize)
+		if(barrier.m_range == kMaxPtrSize)
 		{
 		{
 			inf.size = VK_WHOLE_SIZE;
 			inf.size = VK_WHOLE_SIZE;
 		}
 		}
 		else
 		else
 		{
 		{
-			ANKI_ASSERT(barrier.m_size > 0);
-			ANKI_ASSERT(barrier.m_offset + barrier.m_size <= impl.getSize());
-			inf.size = barrier.m_size;
+			ANKI_ASSERT(barrier.m_range > 0);
+			ANKI_ASSERT(barrier.m_offset + barrier.m_range <= impl.getSize());
+			inf.size = barrier.m_range;
 		}
 		}
 
 
 		VkPipelineStageFlags srcStage;
 		VkPipelineStageFlags srcStage;
@@ -720,8 +686,6 @@ void CommandBufferImpl::setPipelineBarrierInternal(
 
 
 		srcStageMask |= srcStage;
 		srcStageMask |= srcStage;
 		dstStageMask |= dstStage;
 		dstStageMask |= dstStage;
-
-		m_microCmdb->pushObjectRef(barrier.m_buffer);
 	}
 	}
 
 
 	for(const AccelerationStructureBarrierInfo& barrier : accelerationStructures)
 	for(const AccelerationStructureBarrierInfo& barrier : accelerationStructures)
@@ -734,8 +698,8 @@ void CommandBufferImpl::setPipelineBarrierInternal(
 
 
 		VkPipelineStageFlags srcStage;
 		VkPipelineStageFlags srcStage;
 		VkPipelineStageFlags dstStage;
 		VkPipelineStageFlags dstStage;
-		AccelerationStructureImpl::computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStage,
-													  inf.srcAccessMask, dstStage, inf.dstAccessMask);
+		AccelerationStructureImpl::computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStage, inf.srcAccessMask, dstStage,
+													  inf.dstAccessMask);
 
 
 		srcStageMask |= srcStage;
 		srcStageMask |= srcStage;
 		dstStageMask |= dstStage;
 		dstStageMask |= dstStage;

+ 217 - 106
AnKi/Gr/Vulkan/CommandBufferImpl.h

@@ -34,10 +34,6 @@ public:
 	/// Default constructor
 	/// Default constructor
 	CommandBufferImpl(CString name)
 	CommandBufferImpl(CString name)
 		: CommandBuffer(name)
 		: CommandBuffer(name)
-		, m_renderedToDefaultFb(false)
-		, m_finalized(false)
-		, m_empty(false)
-		, m_beganRecording(false)
 	{
 	{
 	}
 	}
 
 
@@ -45,7 +41,7 @@ public:
 
 
 	Error init(const CommandBufferInitInfo& init);
 	Error init(const CommandBufferInitInfo& init);
 
 
-	void setFence(MicroFencePtr& fence)
+	void setFence(MicroFence* fence)
 	{
 	{
 		m_microCmdb->setFence(fence);
 		m_microCmdb->setFence(fence);
 	}
 	}
@@ -76,49 +72,45 @@ public:
 		return !!(m_flags & CommandBufferFlag::kSecondLevel);
 		return !!(m_flags & CommandBufferFlag::kSecondLevel);
 	}
 	}
 
 
-	void bindVertexBufferInternal(U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize stride,
-								  VertexStepRate stepRate)
+	ANKI_FORCE_INLINE void bindVertexBufferInternal(U32 binding, Buffer* buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.bindVertexBuffer(binding, stride, stepRate);
 		m_state.bindVertexBuffer(binding, stride, stepRate);
 		const VkBuffer vkbuff = static_cast<const BufferImpl&>(*buff).getHandle();
 		const VkBuffer vkbuff = static_cast<const BufferImpl&>(*buff).getHandle();
 		vkCmdBindVertexBuffers(m_handle, binding, 1, &vkbuff, &offset);
 		vkCmdBindVertexBuffers(m_handle, binding, 1, &vkbuff, &offset);
-		m_microCmdb->pushObjectRef(buff);
 	}
 	}
 
 
-	void setVertexAttributeInternal(U32 location, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
+	ANKI_FORCE_INLINE void setVertexAttributeInternal(U32 location, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
 		m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
 	}
 	}
 
 
-	void bindIndexBufferInternal(const BufferPtr& buff, PtrSize offset, IndexType type)
+	ANKI_FORCE_INLINE void bindIndexBufferInternal(Buffer* buff, PtrSize offset, IndexType type)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		vkCmdBindIndexBuffer(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), offset,
-							 convertIndexType(type));
-		m_microCmdb->pushObjectRef(buff);
+		vkCmdBindIndexBuffer(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), offset, convertIndexType(type));
 	}
 	}
 
 
-	void setPrimitiveRestartInternal(Bool enable)
+	ANKI_FORCE_INLINE void setPrimitiveRestartInternal(Bool enable)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setPrimitiveRestart(enable);
 		m_state.setPrimitiveRestart(enable);
 	}
 	}
 
 
-	void setFillModeInternal(FillMode mode)
+	ANKI_FORCE_INLINE void setFillModeInternal(FillMode mode)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setFillMode(mode);
 		m_state.setFillMode(mode);
 	}
 	}
 
 
-	void setCullModeInternal(FaceSelectionBit mode)
+	ANKI_FORCE_INLINE void setCullModeInternal(FaceSelectionBit mode)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setCullMode(mode);
 		m_state.setCullMode(mode);
 	}
 	}
 
 
-	void setViewportInternal(U32 minx, U32 miny, U32 width, U32 height)
+	ANKI_FORCE_INLINE void setViewportInternal(U32 minx, U32 miny, U32 width, U32 height)
 	{
 	{
 		ANKI_ASSERT(width > 0 && height > 0);
 		ANKI_ASSERT(width > 0 && height > 0);
 		commandCommon();
 		commandCommon();
@@ -134,7 +126,7 @@ public:
 		}
 		}
 	}
 	}
 
 
-	void setScissorInternal(U32 minx, U32 miny, U32 width, U32 height)
+	ANKI_FORCE_INLINE void setScissorInternal(U32 minx, U32 miny, U32 width, U32 height)
 	{
 	{
 		ANKI_ASSERT(width > 0 && height > 0);
 		ANKI_ASSERT(width > 0 && height > 0);
 		commandCommon();
 		commandCommon();
@@ -150,21 +142,21 @@ public:
 		}
 		}
 	}
 	}
 
 
-	void setPolygonOffsetInternal(F32 factor, F32 units)
+	ANKI_FORCE_INLINE void setPolygonOffsetInternal(F32 factor, F32 units)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setPolygonOffset(factor, units);
 		m_state.setPolygonOffset(factor, units);
 		vkCmdSetDepthBias(m_handle, factor, 0.0f, units);
 		vkCmdSetDepthBias(m_handle, factor, 0.0f, units);
 	}
 	}
 
 
-	void setStencilOperationsInternal(FaceSelectionBit face, StencilOperation stencilFail,
-									  StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass)
+	ANKI_FORCE_INLINE void setStencilOperationsInternal(FaceSelectionBit face, StencilOperation stencilFail, StencilOperation stencilPassDepthFail,
+														StencilOperation stencilPassDepthPass)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
 		m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
 	}
 	}
 
 
-	void setStencilCompareOperationInternal(FaceSelectionBit face, CompareOperation comp)
+	ANKI_FORCE_INLINE void setStencilCompareOperationInternal(FaceSelectionBit face, CompareOperation comp)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setStencilCompareOperation(face, comp);
 		m_state.setStencilCompareOperation(face, comp);
@@ -176,45 +168,43 @@ public:
 
 
 	void setStencilReferenceInternal(FaceSelectionBit face, U32 ref);
 	void setStencilReferenceInternal(FaceSelectionBit face, U32 ref);
 
 
-	void setDepthWriteInternal(Bool enable)
+	ANKI_FORCE_INLINE void setDepthWriteInternal(Bool enable)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setDepthWrite(enable);
 		m_state.setDepthWrite(enable);
 	}
 	}
 
 
-	void setDepthCompareOperationInternal(CompareOperation op)
+	ANKI_FORCE_INLINE void setDepthCompareOperationInternal(CompareOperation op)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setDepthCompareOperation(op);
 		m_state.setDepthCompareOperation(op);
 	}
 	}
 
 
-	void setAlphaToCoverageInternal(Bool enable)
+	ANKI_FORCE_INLINE void setAlphaToCoverageInternal(Bool enable)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setAlphaToCoverage(enable);
 		m_state.setAlphaToCoverage(enable);
 	}
 	}
 
 
-	void setColorChannelWriteMaskInternal(U32 attachment, ColorBit mask)
+	ANKI_FORCE_INLINE void setColorChannelWriteMaskInternal(U32 attachment, ColorBit mask)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setColorChannelWriteMask(attachment, mask);
 		m_state.setColorChannelWriteMask(attachment, mask);
 	}
 	}
 
 
-	void setBlendFactorsInternal(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA,
-								 BlendFactor dstA)
+	ANKI_FORCE_INLINE void setBlendFactorsInternal(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA);
 		m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA);
 	}
 	}
 
 
-	void setBlendOperationInternal(U32 attachment, BlendOperation funcRgb, BlendOperation funcA)
+	ANKI_FORCE_INLINE void setBlendOperationInternal(U32 attachment, BlendOperation funcRgb, BlendOperation funcA)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_state.setBlendOperation(attachment, funcRgb, funcA);
 		m_state.setBlendOperation(attachment, funcRgb, funcA);
 	}
 	}
 
 
-	void bindTextureAndSamplerInternal(U32 set, U32 binding, const TextureViewPtr& texView, const SamplerPtr& sampler,
-									   U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindTextureAndSamplerInternal(U32 set, U32 binding, TextureView* texView, Sampler* sampler, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
 		const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
@@ -222,13 +212,12 @@ public:
 		ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
 		ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
 		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage(), 0);
 		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage(), 0);
 
 
-		m_dsetState[set].bindTextureAndSampler(binding, arrayIdx, &view, sampler.get(), lay);
+		m_dsetState[set].bindTextureAndSampler(binding, arrayIdx, &view, sampler, lay);
 
 
-		m_microCmdb->pushObjectRef(texView);
 		m_microCmdb->pushObjectRef(sampler);
 		m_microCmdb->pushObjectRef(sampler);
 	}
 	}
 
 
-	void bindTextureInternal(U32 set, U32 binding, const TextureViewPtr& texView, U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindTextureInternal(U32 set, U32 binding, TextureView* texView, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
 		const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
@@ -236,82 +225,162 @@ public:
 		ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
 		ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
 		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage(), 0);
 		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage(), 0);
 
 
-		m_dsetState[set].bindTexture(binding, arrayIdx, &view, lay);
-
-		m_microCmdb->pushObjectRef(texView);
+		m_dsetState[set].bindTexture(binding, arrayIdx, texView, lay);
 	}
 	}
 
 
-	void bindSamplerInternal(U32 set, U32 binding, const SamplerPtr& sampler, U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindSamplerInternal(U32 set, U32 binding, Sampler* sampler, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindSampler(binding, arrayIdx, sampler.get());
+		m_dsetState[set].bindSampler(binding, arrayIdx, sampler);
 		m_microCmdb->pushObjectRef(sampler);
 		m_microCmdb->pushObjectRef(sampler);
 	}
 	}
 
 
-	void bindImageInternal(U32 set, U32 binding, const TextureViewPtr& img, U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindImageInternal(U32 set, U32 binding, TextureView* img, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindImage(binding, arrayIdx, img.get());
+		m_dsetState[set].bindImage(binding, arrayIdx, img);
 
 
-		const Bool isPresentable = !!(static_cast<const TextureViewImpl&>(*img).getTextureImpl().getTextureUsage()
-									  & TextureUsageBit::kPresent);
+		const Bool isPresentable = !!(static_cast<const TextureViewImpl&>(*img).getTextureImpl().getTextureUsage() & TextureUsageBit::kPresent);
 		if(isPresentable)
 		if(isPresentable)
 		{
 		{
 			m_renderedToDefaultFb = true;
 			m_renderedToDefaultFb = true;
 		}
 		}
-
-		m_microCmdb->pushObjectRef(img);
 	}
 	}
 
 
-	void bindAccelerationStructureInternal(U32 set, U32 binding, const AccelerationStructurePtr& as, U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindAccelerationStructureInternal(U32 set, U32 binding, AccelerationStructure* as, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindAccelerationStructure(binding, arrayIdx, as.get());
+		m_dsetState[set].bindAccelerationStructure(binding, arrayIdx, as);
 		m_microCmdb->pushObjectRef(as);
 		m_microCmdb->pushObjectRef(as);
 	}
 	}
 
 
-	void bindAllBindlessInternal(U32 set)
+	ANKI_FORCE_INLINE void bindAllBindlessInternal(U32 set)
 	{
 	{
 		commandCommon();
 		commandCommon();
 		m_dsetState[set].bindBindlessDescriptorSet();
 		m_dsetState[set].bindBindlessDescriptorSet();
 	}
 	}
 
 
-	void beginRenderPassInternal(const FramebufferPtr& fb,
-								 const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
-								 TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width,
-								 U32 height);
+	void beginRenderPassInternal(Framebuffer* fb, const Array<TextureUsageBit, kMaxColorRenderTargets>& colorAttachmentUsages,
+								 TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height);
 
 
 	void endRenderPassInternal();
 	void endRenderPassInternal();
 
 
-	void setVrsRateInternal(VrsRate rate);
+	ANKI_FORCE_INLINE void setVrsRateInternal(VrsRate rate)
+	{
+		ANKI_ASSERT(getGrManagerImpl().getDeviceCapabilities().m_vrs);
+		ANKI_ASSERT(rate < VrsRate::kCount);
+		commandCommon();
+
+		if(m_vrsRate != rate)
+		{
+			m_vrsRate = rate;
+			m_vrsRateDirty = true;
+		}
+	}
+
+	ANKI_FORCE_INLINE void drawInternal(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		vkCmdDraw(m_handle, count, instanceCount, first, baseInstance);
+	}
+
+	ANKI_FORCE_INLINE void drawIndexedInternal(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex,
+											   U32 baseInstance)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		vkCmdDrawIndexed(m_handle, count, instanceCount, firstIndex, baseVertex, baseInstance);
+	}
+
+	ANKI_FORCE_INLINE void drawIndirectInternal(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* buff)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
+		ANKI_ASSERT(impl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((offset % 4) == 0);
+		ANKI_ASSERT((offset + sizeof(DrawIndirectArgs) * drawCount) <= impl.getSize());
+
+		vkCmdDrawIndirect(m_handle, impl.getHandle(), offset, drawCount, sizeof(DrawIndirectArgs));
+	}
+
+	ANKI_FORCE_INLINE void drawIndexedIndirectInternal(PrimitiveTopology topology, U32 drawCount, PtrSize offset, Buffer* buff)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
+		ANKI_ASSERT(impl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((offset % 4) == 0);
+		ANKI_ASSERT((offset + sizeof(DrawIndexedIndirectArgs) * drawCount) <= impl.getSize());
+
+		vkCmdDrawIndexedIndirect(m_handle, impl.getHandle(), offset, drawCount, sizeof(DrawIndexedIndirectArgs));
+	}
 
 
-	void drawArraysInternal(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance);
+	ANKI_FORCE_INLINE void drawIndexedIndirectCountInternal(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset,
+															U32 argBufferStride, Buffer* countBuffer, PtrSize countBufferOffset, U32 maxDrawCount)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		const BufferImpl& argBufferImpl = static_cast<const BufferImpl&>(*argBuffer);
+		ANKI_ASSERT(argBufferImpl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((argBufferOffset % 4) == 0);
+		ANKI_ASSERT(argBufferStride >= sizeof(DrawIndexedIndirectArgs));
+		ANKI_ASSERT(argBufferOffset + maxDrawCount * argBufferStride <= argBuffer->getSize());
 
 
-	void drawElementsInternal(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex,
-							  U32 baseInstance);
+		const BufferImpl& countBufferImpl = static_cast<const BufferImpl&>(*countBuffer);
+		ANKI_ASSERT(countBufferImpl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((countBufferOffset % 4) == 0);
+		ANKI_ASSERT(countBufferOffset + sizeof(U32) <= countBuffer->getSize());
 
 
-	void drawArraysIndirectInternal(PrimitiveTopology topology, U32 drawCount, PtrSize offset, const BufferPtr& buff);
+		ANKI_ASSERT(maxDrawCount > 0 && maxDrawCount <= getGrManagerImpl().getDeviceCapabilities().m_maxDrawIndirectCount);
 
 
-	void drawElementsIndirectInternal(PrimitiveTopology topology, U32 drawCount, PtrSize offset, const BufferPtr& buff);
+		vkCmdDrawIndexedIndirectCountKHR(m_handle, argBufferImpl.getHandle(), argBufferOffset, countBufferImpl.getHandle(), countBufferOffset,
+										 maxDrawCount, argBufferStride);
+	}
+
+	ANKI_FORCE_INLINE void drawIndirectCountInternal(PrimitiveTopology topology, Buffer* argBuffer, PtrSize argBufferOffset, U32 argBufferStride,
+													 Buffer* countBuffer, PtrSize countBufferOffset, U32 maxDrawCount)
+	{
+		m_state.setPrimitiveTopology(topology);
+		drawcallCommon();
+		const BufferImpl& argBufferImpl = static_cast<const BufferImpl&>(*argBuffer);
+		ANKI_ASSERT(argBufferImpl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((argBufferOffset % 4) == 0);
+		ANKI_ASSERT(argBufferStride >= sizeof(DrawIndirectArgs));
+		ANKI_ASSERT(argBufferOffset + maxDrawCount * argBufferStride <= argBuffer->getSize());
+
+		const BufferImpl& countBufferImpl = static_cast<const BufferImpl&>(*countBuffer);
+		ANKI_ASSERT(countBufferImpl.usageValid(BufferUsageBit::kIndirectDraw));
+		ANKI_ASSERT((countBufferOffset % 4) == 0);
+		ANKI_ASSERT(countBufferOffset + maxDrawCount * sizeof(U32) <= countBuffer->getSize());
+
+		ANKI_ASSERT(maxDrawCount > 0 && maxDrawCount <= getGrManagerImpl().getDeviceCapabilities().m_maxDrawIndirectCount);
+
+		vkCmdDrawIndirectCountKHR(m_handle, argBufferImpl.getHandle(), argBufferOffset, countBufferImpl.getHandle(), countBufferOffset, maxDrawCount,
+								  argBufferStride);
+	}
 
 
 	void dispatchComputeInternal(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 	void dispatchComputeInternal(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 
 
-	void traceRaysInternal(const BufferPtr& sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize,
-						   U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width, U32 height, U32 depth);
+	void dispatchComputeIndirectInternal(Buffer* argBuffer, PtrSize argBufferOffset);
+
+	void traceRaysInternal(Buffer* sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize, U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width,
+						   U32 height, U32 depth);
 
 
 	void resetOcclusionQueriesInternal(ConstWeakArray<OcclusionQuery*> queries);
 	void resetOcclusionQueriesInternal(ConstWeakArray<OcclusionQuery*> queries);
 
 
-	void beginOcclusionQueryInternal(const OcclusionQueryPtr& query);
+	void beginOcclusionQueryInternal(OcclusionQuery* query);
 
 
-	void endOcclusionQueryInternal(const OcclusionQueryPtr& query);
+	void endOcclusionQueryInternal(OcclusionQuery* query);
 
 
 	void resetTimestampQueriesInternal(ConstWeakArray<TimestampQuery*> queries);
 	void resetTimestampQueriesInternal(ConstWeakArray<TimestampQuery*> queries);
 
 
-	void writeTimestampInternal(const TimestampQueryPtr& query);
+	void writeTimestampInternal(TimestampQuery* query);
 
 
-	void generateMipmaps2dInternal(const TextureViewPtr& texView);
+	void generateMipmaps2dInternal(TextureView* texView);
 
 
-	void clearTextureViewInternal(const TextureViewPtr& texView, const ClearValue& clearValue);
+	void clearTextureViewInternal(TextureView* texView, const ClearValue& clearValue);
 
 
 	void pushSecondLevelCommandBuffersInternal(ConstWeakArray<CommandBuffer*> cmdbs);
 	void pushSecondLevelCommandBuffersInternal(ConstWeakArray<CommandBuffer*> cmdbs);
 
 
@@ -323,59 +392,99 @@ public:
 
 
 	void endRecording();
 	void endRecording();
 
 
-	void setPipelineBarrierInternal(ConstWeakArray<TextureBarrierInfo> textures,
-									ConstWeakArray<BufferBarrierInfo> buffers,
+	void setPipelineBarrierInternal(ConstWeakArray<TextureBarrierInfo> textures, ConstWeakArray<BufferBarrierInfo> buffers,
 									ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures);
 									ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures);
 
 
-	void fillBufferInternal(const BufferPtr& buff, PtrSize offset, PtrSize size, U32 value);
+	void fillBufferInternal(Buffer* buff, PtrSize offset, PtrSize size, U32 value);
 
 
-	void writeOcclusionQueriesResultToBufferInternal(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset,
-													 const BufferPtr& buff);
+	void writeOcclusionQueriesResultToBufferInternal(ConstWeakArray<OcclusionQuery*> queries, PtrSize offset, Buffer* buff);
 
 
-	void bindShaderProgramInternal(const ShaderProgramPtr& prog);
+	void bindShaderProgramInternal(ShaderProgram* prog);
 
 
-	void bindUniformBufferInternal(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-								   U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindUniformBufferInternal(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindUniformBuffer(binding, arrayIdx, buff.get(), offset, range);
-		m_microCmdb->pushObjectRef(buff);
+		m_dsetState[set].bindUniformBuffer(binding, arrayIdx, buff, offset, range);
 	}
 	}
 
 
-	void bindStorageBufferInternal(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-								   U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindStorageBufferInternal(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindStorageBuffer(binding, arrayIdx, buff.get(), offset, range);
-		m_microCmdb->pushObjectRef(buff);
+		m_dsetState[set].bindStorageBuffer(binding, arrayIdx, buff, offset, range);
 	}
 	}
 
 
-	void bindReadOnlyTextureBufferInternal(U32 set, U32 binding, const BufferPtr& buff, PtrSize offset, PtrSize range,
-										   Format fmt, U32 arrayIdx)
+	ANKI_FORCE_INLINE void bindReadOnlyTextureBufferInternal(U32 set, U32 binding, Buffer* buff, PtrSize offset, PtrSize range, Format fmt,
+															 U32 arrayIdx)
 	{
 	{
 		commandCommon();
 		commandCommon();
-		m_dsetState[set].bindReadOnlyTextureBuffer(binding, arrayIdx, buff.get(), offset, range, fmt);
-		m_microCmdb->pushObjectRef(buff);
+		m_dsetState[set].bindReadOnlyTextureBuffer(binding, arrayIdx, buff, offset, range, fmt);
 	}
 	}
 
 
-	void copyBufferToTextureViewInternal(const BufferPtr& buff, PtrSize offset, PtrSize range,
-										 const TextureViewPtr& texView);
+	void copyBufferToTextureViewInternal(Buffer* buff, PtrSize offset, PtrSize range, TextureView* texView);
 
 
-	void copyBufferToBufferInternal(const BufferPtr& src, const BufferPtr& dst,
-									ConstWeakArray<CopyBufferToBufferInfo> copies);
+	void copyBufferToBufferInternal(Buffer* src, Buffer* dst, ConstWeakArray<CopyBufferToBufferInfo> copies);
 
 
-	void buildAccelerationStructureInternal(const AccelerationStructurePtr& as);
+	void buildAccelerationStructureInternal(AccelerationStructure* as, Buffer* scratchBuffer, PtrSize scratchBufferOffset);
 
 
-	void upscaleInternal(const GrUpscalerPtr& upscaler, const TextureViewPtr& inColor,
-						 const TextureViewPtr& outUpscaledColor, const TextureViewPtr& motionVectors,
-						 const TextureViewPtr& depth, const TextureViewPtr& exposure, const Bool resetAccumulation,
-						 const Vec2& jitterOffset, const Vec2& motionVectorsScale);
+	void upscaleInternal(GrUpscaler* upscaler, TextureView* inColor, TextureView* outUpscaledColor, TextureView* motionVectors, TextureView* depth,
+						 TextureView* exposure, const Bool resetAccumulation, const Vec2& jitterOffset, const Vec2& motionVectorsScale);
 
 
 	void setPushConstantsInternal(const void* data, U32 dataSize);
 	void setPushConstantsInternal(const void* data, U32 dataSize);
 
 
-	void setRasterizationOrderInternal(RasterizationOrder order);
+	ANKI_FORCE_INLINE void setRasterizationOrderInternal(RasterizationOrder order)
+	{
+		commandCommon();
 
 
-	void setLineWidthInternal(F32 width);
+		if(!!(getGrManagerImpl().getExtensions() & VulkanExtensions::kAMD_rasterization_order))
+		{
+			m_state.setRasterizationOrder(order);
+		}
+	}
+
+	ANKI_FORCE_INLINE void setLineWidthInternal(F32 width)
+	{
+		commandCommon();
+		vkCmdSetLineWidth(m_handle, width);
+
+#if ANKI_ASSERTIONS_ENABLED
+		m_lineWidthSet = true;
+#endif
+	}
+
+	ANKI_FORCE_INLINE void pushDebugMarkerInternal(CString name, Vec3 color)
+	{
+		if(m_debugMarkers) [[unlikely]]
+		{
+			commandCommon();
+
+			VkDebugUtilsLabelEXT label = {};
+			label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+			label.pLabelName = name.cstr();
+			label.color[0] = color[0];
+			label.color[1] = color[1];
+			label.color[2] = color[2];
+			label.color[3] = 1.0f;
+			vkCmdBeginDebugUtilsLabelEXT(m_handle, &label);
+		}
+
+#if ANKI_EXTRA_CHECKS
+		++m_debugMarkersPushed;
+#endif
+	}
+
+	ANKI_FORCE_INLINE void popDebugMarkerInternal()
+	{
+		if(m_debugMarkers) [[unlikely]]
+		{
+			commandCommon();
+			vkCmdEndDebugUtilsLabelEXT(m_handle);
+		}
+
+#if ANKI_EXTRA_CHECKS
+		ANKI_ASSERT(m_debugMarkersPushed > 0);
+		--m_debugMarkersPushed;
+#endif
+	}
 
 
 private:
 private:
 	StackMemoryPool* m_pool = nullptr;
 	StackMemoryPool* m_pool = nullptr;
@@ -384,16 +493,18 @@ private:
 	VkCommandBuffer m_handle = VK_NULL_HANDLE;
 	VkCommandBuffer m_handle = VK_NULL_HANDLE;
 	ThreadId m_tid = ~ThreadId(0);
 	ThreadId m_tid = ~ThreadId(0);
 	CommandBufferFlag m_flags = CommandBufferFlag::kNone;
 	CommandBufferFlag m_flags = CommandBufferFlag::kNone;
-	Bool m_renderedToDefaultFb : 1;
-	Bool m_finalized : 1;
-	Bool m_empty : 1;
-	Bool m_beganRecording : 1;
+	Bool m_renderedToDefaultFb : 1 = false;
+	Bool m_finalized : 1 = false;
+	Bool m_empty : 1 = true;
+	Bool m_beganRecording : 1 = false;
+	Bool m_debugMarkers : 1 = false;
 #if ANKI_EXTRA_CHECKS
 #if ANKI_EXTRA_CHECKS
 	U32 m_commandCount = 0;
 	U32 m_commandCount = 0;
 	U32 m_setPushConstantsSize = 0;
 	U32 m_setPushConstantsSize = 0;
+	U32 m_debugMarkersPushed = 0;
 #endif
 #endif
 
 
-	FramebufferPtr m_activeFb;
+	Framebuffer* m_activeFb = nullptr;
 	Array<U32, 4> m_renderArea = {0, 0, kMaxU32, kMaxU32};
 	Array<U32, 4> m_renderArea = {0, 0, kMaxU32, kMaxU32};
 	Array<U32, 2> m_fbSize = {0, 0};
 	Array<U32, 2> m_fbSize = {0, 0};
 	U32 m_rpCommandCount = 0; ///< Number of drawcalls or pushed cmdbs in rp.
 	U32 m_rpCommandCount = 0; ///< Number of drawcalls or pushed cmdbs in rp.
@@ -421,7 +532,7 @@ private:
 	Array<U32, 2> m_stencilCompareMasks = {0x5A5A5A5A, 0x5A5A5A5A}; ///< Use a stupid number to initialize.
 	Array<U32, 2> m_stencilCompareMasks = {0x5A5A5A5A, 0x5A5A5A5A}; ///< Use a stupid number to initialize.
 	Array<U32, 2> m_stencilWriteMasks = {0x5A5A5A5A, 0x5A5A5A5A};
 	Array<U32, 2> m_stencilWriteMasks = {0x5A5A5A5A, 0x5A5A5A5A};
 	Array<U32, 2> m_stencilReferenceMasks = {0x5A5A5A5A, 0x5A5A5A5A};
 	Array<U32, 2> m_stencilReferenceMasks = {0x5A5A5A5A, 0x5A5A5A5A};
-#if ANKI_ENABLE_ASSERTIONS
+#if ANKI_ASSERTIONS_ENABLED
 	Bool m_lineWidthSet = false;
 	Bool m_lineWidthSet = false;
 #endif
 #endif
 	Bool m_vrsRateDirty = true;
 	Bool m_vrsRateDirty = true;
@@ -446,16 +557,17 @@ private:
 			m_beganRecording = true;
 			m_beganRecording = true;
 		}
 		}
 
 
-		ANKI_ASSERT(Thread::getCurrentThreadId() == m_tid
-					&& "Commands must be recorder and flushed by the thread this command buffer was created");
+		ANKI_ASSERT(Thread::getCurrentThreadId() == m_tid && "Commands must be recorder and flushed by the thread this command buffer was created");
 		ANKI_ASSERT(m_handle);
 		ANKI_ASSERT(m_handle);
 	}
 	}
 
 
 	void drawcallCommon();
 	void drawcallCommon();
 
 
+	void dispatchCommon();
+
 	Bool insideRenderPass() const
 	Bool insideRenderPass() const
 	{
 	{
-		return m_activeFb.isCreated();
+		return m_activeFb != nullptr;
 	}
 	}
 
 
 	void beginRenderPassInternal();
 	void beginRenderPassInternal();
@@ -465,9 +577,8 @@ private:
 		return !!(m_flags & CommandBufferFlag::kSecondLevel);
 		return !!(m_flags & CommandBufferFlag::kSecondLevel);
 	}
 	}
 
 
-	void setImageBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess, VkImageLayout prevLayout,
-						 VkPipelineStageFlags dstStage, VkAccessFlags dstAccess, VkImageLayout newLayout, VkImage img,
-						 const VkImageSubresourceRange& range);
+	void setImageBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess, VkImageLayout prevLayout, VkPipelineStageFlags dstStage,
+						 VkAccessFlags dstAccess, VkImageLayout newLayout, VkImage img, const VkImageSubresourceRange& range);
 
 
 	void beginRecording();
 	void beginRecording();
 
 

Some files were not shown because too many files changed in this diff