Browse Source

Refactor CVARs

Panagiotis Christopoulos Charitos 3 months ago
parent
commit
77c6a85271
100 changed files with 934 additions and 634 deletions
  1. 34 34
      AnKi/Core/App.cpp
  2. 13 15
      AnKi/Core/App.h
  3. 7 7
      AnKi/Core/CoreTracer.cpp
  4. 2 2
      AnKi/Core/CoreTracer.h
  5. 4 1
      AnKi/Core/StatsSet.h
  6. 7 9
      AnKi/GpuMemory/GpuSceneBuffer.cpp
  7. 1 1
      AnKi/GpuMemory/GpuSceneBuffer.h
  8. 2 3
      AnKi/GpuMemory/GpuVisibleTransientMemoryPool.cpp
  9. 3 3
      AnKi/GpuMemory/RebarTransientMemoryPool.cpp
  10. 1 1
      AnKi/GpuMemory/RebarTransientMemoryPool.h
  11. 7 8
      AnKi/GpuMemory/UnifiedGeometryBuffer.cpp
  12. 1 2
      AnKi/GpuMemory/UnifiedGeometryBuffer.h
  13. 1 1
      AnKi/Gr/BackendCommon/MicroFenceFactory.h
  14. 4 4
      AnKi/Gr/BackendCommon/MicroFenceFactory.inl.h
  15. 27 29
      AnKi/Gr/Common.h
  16. 1 1
      AnKi/Gr/D3D/D3DCommandBuffer.cpp
  17. 3 3
      AnKi/Gr/D3D/D3DCommandBufferFactory.cpp
  18. 12 12
      AnKi/Gr/D3D/D3DDescriptor.cpp
  19. 13 13
      AnKi/Gr/D3D/D3DGrManager.cpp
  20. 1 1
      AnKi/Gr/D3D/D3DGrUpscaler.cpp
  21. 2 2
      AnKi/Gr/D3D/D3DSwapchainFactory.cpp
  22. 3 3
      AnKi/Gr/Vulkan/VkCommandBufferFactory.cpp
  23. 5 5
      AnKi/Gr/Vulkan/VkDescriptor.cpp
  24. 21 21
      AnKi/Gr/Vulkan/VkGpuMemoryManager.cpp
  25. 22 22
      AnKi/Gr/Vulkan/VkGrManager.cpp
  26. 1 1
      AnKi/Gr/Vulkan/VkGraphicsState.cpp
  27. 1 1
      AnKi/Gr/Vulkan/VkSemaphoreFactory.cpp
  28. 6 7
      AnKi/Physics/PhysicsWorld.cpp
  29. 5 5
      AnKi/Renderer/AccelerationStructureBuilder.cpp
  30. 8 10
      AnKi/Renderer/AccelerationStructureBuilder.h
  31. 8 8
      AnKi/Renderer/Bloom.cpp
  32. 4 4
      AnKi/Renderer/Bloom.h
  33. 7 7
      AnKi/Renderer/Dbg.cpp
  34. 2 2
      AnKi/Renderer/Dbg.h
  35. 2 2
      AnKi/Renderer/DepthDownscale.cpp
  36. 14 11
      AnKi/Renderer/FinalComposite.cpp
  37. 2 2
      AnKi/Renderer/FinalComposite.h
  38. 2 2
      AnKi/Renderer/ForwardShading.cpp
  39. 4 4
      AnKi/Renderer/GBuffer.cpp
  40. 2 3
      AnKi/Renderer/GBuffer.h
  41. 3 3
      AnKi/Renderer/HistoryLength.cpp
  42. 2 2
      AnKi/Renderer/IndirectDiffuse.cpp
  43. 1 1
      AnKi/Renderer/IndirectDiffuse.h
  44. 154 27
      AnKi/Renderer/IndirectDiffuseClipmaps.cpp
  45. 29 37
      AnKi/Renderer/IndirectDiffuseClipmaps.h
  46. 8 8
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  47. 2 4
      AnKi/Renderer/IndirectDiffuseProbes.h
  48. 1 1
      AnKi/Renderer/LensFlare.cpp
  49. 1 2
      AnKi/Renderer/LensFlare.h
  50. 3 3
      AnKi/Renderer/LightShading.cpp
  51. 21 16
      AnKi/Renderer/MotionBlur.cpp
  52. 2 2
      AnKi/Renderer/MotionBlur.h
  53. 3 3
      AnKi/Renderer/MotionVectors.cpp
  54. 8 8
      AnKi/Renderer/ProbeReflections.cpp
  55. 1 4
      AnKi/Renderer/ProbeReflections.h
  56. 6 6
      AnKi/Renderer/Reflections.cpp
  57. 9 11
      AnKi/Renderer/Reflections.h
  58. 16 17
      AnKi/Renderer/Renderer.cpp
  59. 19 25
      AnKi/Renderer/Renderer.h
  60. 1 1
      AnKi/Renderer/RendererObject.cpp
  61. 7 7
      AnKi/Renderer/RendererObject.def.h
  62. 1 1
      AnKi/Renderer/RtMaterialFetchDbg.h
  63. 4 4
      AnKi/Renderer/RtShadows.cpp
  64. 4 4
      AnKi/Renderer/RtShadows.h
  65. 20 21
      AnKi/Renderer/ShadowMapping.cpp
  66. 4 6
      AnKi/Renderer/ShadowMapping.h
  67. 6 6
      AnKi/Renderer/ShadowmapsResolve.cpp
  68. 1 1
      AnKi/Renderer/ShadowmapsResolve.h
  69. 16 16
      AnKi/Renderer/Ssao.cpp
  70. 7 7
      AnKi/Renderer/Ssao.h
  71. 3 3
      AnKi/Renderer/TemporalAA.cpp
  72. 3 3
      AnKi/Renderer/TemporalUpscaler.cpp
  73. 1 1
      AnKi/Renderer/TemporalUpscaler.h
  74. 2 2
      AnKi/Renderer/Tonemapping.cpp
  75. 5 8
      AnKi/Renderer/Utils/GpuVisibility.cpp
  76. 3 3
      AnKi/Renderer/VolumetricFog.cpp
  77. 4 4
      AnKi/Renderer/VolumetricLightingAccumulation.cpp
  78. 4 6
      AnKi/Renderer/VolumetricLightingAccumulation.h
  79. 4 4
      AnKi/Renderer/VrsSriGeneration.cpp
  80. 1 1
      AnKi/Renderer/VrsSriGeneration.h
  81. 3 3
      AnKi/Resource/AsyncLoader.cpp
  82. 1 1
      AnKi/Resource/ImageResource.cpp
  83. 1 1
      AnKi/Resource/ImageResource.h
  84. 1 1
      AnKi/Resource/MaterialResource.cpp
  85. 1 1
      AnKi/Resource/MeshResource.cpp
  86. 2 2
      AnKi/Resource/ResourceFilesystem.cpp
  87. 4 5
      AnKi/Resource/ResourceFilesystem.h
  88. 1 1
      AnKi/Resource/ResourceManager.cpp
  89. 1 2
      AnKi/Resource/ResourceManager.h
  90. 2 2
      AnKi/Scene/Components/GlobalIlluminationProbeComponent.cpp
  91. 2 2
      AnKi/Scene/Components/MaterialComponent.cpp
  92. 3 3
      AnKi/Scene/Components/ReflectionProbeComponent.cpp
  93. 1 2
      AnKi/Scene/Components/ReflectionProbeComponent.h
  94. 14 14
      AnKi/Scene/GpuSceneArrays.def.h
  95. 8 9
      AnKi/Scene/SceneGraph.cpp
  96. 12 21
      AnKi/Scene/SceneGraph.h
  97. 2 2
      AnKi/Scene/StatsUiNode.cpp
  98. 216 0
      AnKi/Script/Globals.cpp
  99. 2 0
      AnKi/Script/LuaBinder.cpp
  100. 2 1
      AnKi/Ui/Font.cpp

+ 34 - 34
AnKi/Core/App.cpp

@@ -44,14 +44,14 @@ namespace anki {
 android_app* g_androidApp = nullptr;
 #endif
 
-StatCounter g_cpuAllocatedMemStatVar(StatCategory::kCpuMem, "Total", StatFlag::kBytes);
-StatCounter g_cpuAllocationCountStatVar(StatCategory::kCpuMem, "Allocations/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame);
-StatCounter g_cpuFreesCountStatVar(StatCategory::kCpuMem, "Frees/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame);
+ANKI_SVAR(CpuAllocatedMem, StatCategory::kCpuMem, "Total", StatFlag::kBytes)
+ANKI_SVAR(CpuAllocationCount, StatCategory::kCpuMem, "Allocations/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame)
+ANKI_SVAR(CpuFreesCount, StatCategory::kCpuMem, "Frees/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame)
 
 #if ANKI_PLATFORM_MOBILE
-inline StatCounter g_maliGpuActiveStatVar(StatCategory::kGpuMisc, "Mali active cycles", StatFlag::kMainThreadUpdates);
-inline StatCounter g_maliGpuReadBandwidthStatVar(StatCategory::kGpuMisc, "Mali read bandwidth", StatFlag::kMainThreadUpdates);
-inline StatCounter g_maliGpuWriteBandwidthStatVar(StatCategory::kGpuMisc, "Mali write bandwidth", StatFlag::kMainThreadUpdates);
+ANKI_SVAR(MaliGpuActive, StatCategory::kGpuMisc, "Mali active cycles", StatFlag::kMainThreadUpdates)
+ANKI_SVAR(MaliGpuReadBandwidth, StatCategory::kGpuMisc, "Mali read bandwidth", StatFlag::kMainThreadUpdates)
+ANKI_SVAR(MaliGpuWriteBandwidth, StatCategory::kGpuMisc, "Mali write bandwidth", StatFlag::kMainThreadUpdates)
 #endif
 
 void* App::statsAllocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
@@ -87,8 +87,8 @@ void* App::statsAllocCallback(void* userData, void* ptr, PtrSize size, [[maybe_u
 		out = static_cast<void*>(allocation);
 
 		// Update stats
-		g_cpuAllocatedMemStatVar.increment(size);
-		g_cpuAllocationCountStatVar.increment(1);
+		g_svarCpuAllocatedMem.increment(size);
+		g_svarCpuAllocationCount.increment(1);
 	}
 	else
 	{
@@ -101,8 +101,8 @@ void* App::statsAllocCallback(void* userData, void* ptr, PtrSize size, [[maybe_u
 		ANKI_ASSERT(allocation->m_allocatedSize > 0);
 
 		// Update stats
-		g_cpuAllocatedMemStatVar.decrement(allocation->m_allocatedSize);
-		g_cpuFreesCountStatVar.increment(1);
+		g_svarCpuAllocatedMem.decrement(allocation->m_allocatedSize);
+		g_svarCpuFreesCount.increment(1);
 
 		// Free
 		self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
@@ -116,7 +116,7 @@ App::App(CString appName, AllocAlignedCallback allocCb, void* allocCbUserData)
 	m_originalAllocCallback = allocCb;
 	m_originalAllocUserData = allocCbUserData;
 
-	if(ANKI_STATS_ENABLED && g_displayStatsCVar > 1)
+	if(ANKI_STATS_ENABLED && g_cvarCoreDisplayStats > 1)
 	{
 		m_allocCallback = statsAllocCallback;
 		m_allocUserData = this;
@@ -182,7 +182,7 @@ void App::cleanup()
 Error App::init()
 {
 	StatsSet::getSingleton().initFromMainThread();
-	Logger::getSingleton().enableVerbosity(g_verboseLogCVar);
+	Logger::getSingleton().enableVerbosity(g_cvarCoreVerboseLog);
 
 	ANKI_CHECK(initDirs());
 
@@ -196,12 +196,12 @@ Error App::init()
 	}
 #endif
 
-	ANKI_CORE_LOGI("Number of job threads: %u", U32(g_jobThreadCountCVar));
+	ANKI_CORE_LOGI("Number of job threads: %u", U32(g_cvarCoreJobThreadCount));
 
-	if(g_benchmarkModeCVar && g_vsyncCVar)
+	if(g_cvarCoreBenchmarkMode && g_cvarGrVsync)
 	{
 		ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
-		g_vsyncCVar = false;
+		g_cvarGrVsync = false;
 	}
 
 	GlobalFrameIndex::allocateSingleton();
@@ -217,13 +217,13 @@ Error App::init()
 	// Window
 	//
 	NativeWindowInitInfo nwinit;
-	nwinit.m_width = g_windowWidthCVar;
-	nwinit.m_height = g_windowHeightCVar;
+	nwinit.m_width = g_cvarWindowWidth;
+	nwinit.m_height = g_cvarWindowHeight;
 	nwinit.m_depthBits = 0;
 	nwinit.m_stencilBits = 0;
-	nwinit.m_fullscreenDesktopRez = g_windowFullscreenCVar > 0;
-	nwinit.m_exclusiveFullscreen = g_windowFullscreenCVar == 2;
-	nwinit.m_targetFps = g_targetFpsCVar;
+	nwinit.m_fullscreenDesktopRez = g_cvarWindowFullscreen > 0;
+	nwinit.m_exclusiveFullscreen = g_cvarWindowFullscreen == 2;
+	nwinit.m_targetFps = g_cvarCoreTargetFps;
 	NativeWindow::allocateSingleton();
 	ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
 
@@ -237,7 +237,7 @@ Error App::init()
 	// ThreadPool
 	//
 	const Bool pinThreads = !ANKI_OS_ANDROID;
-	CoreThreadJobManager::allocateSingleton(U32(g_jobThreadCountCVar), pinThreads);
+	CoreThreadJobManager::allocateSingleton(U32(g_cvarCoreJobThreadCount), pinThreads);
 
 	//
 	// Graphics API
@@ -252,7 +252,7 @@ Error App::init()
 	// Mali HW counters
 	//
 #if ANKI_PLATFORM_MOBILE
-	if(ANKI_STATS_ENABLED && GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm && g_maliHwCountersCVar)
+	if(ANKI_STATS_ENABLED && GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm && g_cvarCoreMaliHwCounters)
 	{
 		MaliHwCounters::allocateSingleton();
 	}
@@ -286,8 +286,8 @@ Error App::init()
 	extraPaths += "|ankiprogbin"; // Shaders
 	extraPaths += ":" ANKI_SOURCE_DIRECTORY "|EngineAssets,!AndroidProject"; // EngineAssets
 	extraPaths += ":";
-	extraPaths += g_dataPathsCVar;
-	g_dataPathsCVar = extraPaths;
+	extraPaths += g_cvarRsrcDataPaths;
+	g_cvarRsrcDataPaths = extraPaths;
 #endif
 
 	ANKI_CHECK(ResourceManager::allocateSingleton().init(m_allocCallback, m_allocUserData));
@@ -353,7 +353,7 @@ Error App::initDirs()
 	m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
 
 	const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
-	if(g_clearCachesCVar && cacheDirExists)
+	if(g_cvarCoreClearCaches && cacheDirExists)
 	{
 		ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
 		ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
@@ -401,7 +401,7 @@ Error App::mainLoop()
 	Second crntTime = prevUpdateTime;
 
 	// Benchmark mode stuff:
-	const Bool benchmarkMode = g_benchmarkModeCVar;
+	const Bool benchmarkMode = g_cvarCoreBenchmarkMode;
 	Second aggregatedCpuTime = 0.0;
 	Second aggregatedGpuTime = 0.0;
 	constexpr U32 kBenchmarkFramesToGatherBeforeFlush = 60;
@@ -434,14 +434,14 @@ Error App::mainLoop()
 
 			// 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;
-			if(benchmarkMode || g_displayStatsCVar > 0) [[unlikely]]
+			if(benchmarkMode || g_cvarCoreDisplayStats > 0) [[unlikely]]
 			{
 				grTime = HighRezTimer::getCurrentTime();
 			}
 
 			GrManager::getSingleton().endFrame();
 
-			if(benchmarkMode || g_displayStatsCVar > 0) [[unlikely]]
+			if(benchmarkMode || g_cvarCoreDisplayStats > 0) [[unlikely]]
 			{
 				grTime = HighRezTimer::getCurrentTime() - grTime;
 			}
@@ -455,10 +455,10 @@ Error App::mainLoop()
 			// Sleep
 			const Second endTime = HighRezTimer::getCurrentTime();
 			const Second frameTime = endTime - startTime;
-			g_cpuTotalTimeStatVar.set((frameTime - grTime) * 1000.0);
+			g_svarCpuTotalTime.set((frameTime - grTime) * 1000.0);
 			if(!benchmarkMode) [[likely]]
 			{
-				const Second timerTick = 1.0_sec / Second(g_targetFpsCVar);
+				const Second timerTick = 1.0_sec / Second(g_cvarCoreTargetFps);
 				if(frameTime < timerTick)
 				{
 					ANKI_TRACE_SCOPED_EVENT(TimerTickSleep);
@@ -489,9 +489,9 @@ Error App::mainLoop()
 			{
 				MaliHwCountersOut out;
 				MaliHwCounters::getSingleton().sample(out);
-				g_maliGpuActiveStatVar.set(out.m_gpuActive);
-				g_maliGpuReadBandwidthStatVar.set(out.m_readBandwidth);
-				g_maliGpuWriteBandwidthStatVar.set(out.m_writeBandwidth);
+				g_svarMaliGpuActive.set(out.m_gpuActive);
+				g_svarMaliGpuReadBandwidth.set(out.m_readBandwidth);
+				g_svarMaliGpuWriteBandwidth.set(out.m_writeBandwidth);
 			}
 #endif
 
@@ -501,7 +501,7 @@ Error App::mainLoop()
 
 			if(benchmarkMode) [[unlikely]]
 			{
-				if(GlobalFrameIndex::getSingleton().m_value >= g_benchmarkModeFrameCountCVar)
+				if(GlobalFrameIndex::getSingleton().m_value >= g_cvarCoreBenchmarkModeFrameCount)
 				{
 					quit = true;
 				}

+ 13 - 15
AnKi/Core/App.h

@@ -15,25 +15,23 @@
 
 namespace anki {
 
-inline NumericCVar<U32> g_windowWidthCVar("Core", "Width", 1920, 16, 16 * 1024, "Width");
-inline NumericCVar<U32> g_windowHeightCVar("Core", "Height", 1080, 16, 16 * 1024, "Height");
-inline NumericCVar<U32> g_windowFullscreenCVar("Core", "WindowFullscreen", 1, 0, 2, "0: windowed, 1: borderless fullscreen, 2: exclusive fullscreen");
-inline NumericCVar<U32> g_targetFpsCVar("Core", "TargetFps", 60u, 1u, kMaxU32, "Target FPS");
-inline NumericCVar<U32> g_jobThreadCountCVar("Core", "JobThreadCount", clamp(getCpuCoresCount() / 2u, 2u, 16u), 2u, 1024u, "Number of job thread");
-inline NumericCVar<U32> g_displayStatsCVar("Core", "DisplayStats", 0, 0, 2, "Display stats, 0: None, 1: Simple, 2: Detailed");
-inline BoolCVar g_clearCachesCVar("Core", "ClearCaches", false, "Clear all caches");
-inline BoolCVar g_verboseLogCVar("Core", "VerboseLog", false, "Verbose logging");
-inline BoolCVar g_benchmarkModeCVar("Core", "BenchmarkMode", false, "Run in a benchmark mode. Fixed timestep, unlimited target FPS");
-inline NumericCVar<U32> g_benchmarkModeFrameCountCVar("Core", "BenchmarkModeFrameCount", 60 * 60 * 2, 1, kMaxU32,
-													  "How many frames the benchmark will run before it quits");
-inline BoolCVar g_meshletRenderingCVar("Core", "MeshletRendering", false, "Do meshlet culling and rendering");
+ANKI_CVAR(NumericCVar<U32>, Window, Width, 1920, 16, 16 * 1024, "Width")
+ANKI_CVAR(NumericCVar<U32>, Window, Height, 1080, 16, 16 * 1024, "Height")
+ANKI_CVAR(NumericCVar<U32>, Window, Fullscreen, 1, 0, 2, "0: windowed, 1: borderless fullscreen, 2: exclusive fullscreen")
+ANKI_CVAR(NumericCVar<U32>, Core, TargetFps, 60u, 1u, kMaxU32, "Target FPS")
+ANKI_CVAR(NumericCVar<U32>, Core, JobThreadCount, clamp(getCpuCoresCount() / 2u, 2u, 16u), 2u, 1024u, "Number of job thread")
+ANKI_CVAR(NumericCVar<U32>, Core, DisplayStats, 0, 0, 2, "Display stats, 0: None, 1: Simple, 2: Detailed")
+ANKI_CVAR(BoolCVar, Core, ClearCaches, false, "Clear all caches")
+ANKI_CVAR(BoolCVar, Core, VerboseLog, false, "Verbose logging")
+ANKI_CVAR(BoolCVar, Core, BenchmarkMode, false, "Run in a benchmark mode. Fixed timestep, unlimited target FPS")
+ANKI_CVAR(NumericCVar<U32>, Core, BenchmarkModeFrameCount, 60 * 60 * 2, 1, kMaxU32, "How many frames the benchmark will run before it quits")
+ANKI_CVAR(BoolCVar, Core, MeshletRendering, false, "Do meshlet culling and rendering")
 
 #if ANKI_PLATFORM_MOBILE
-inline BoolCVar g_maliHwCountersCVar("Core", "MaliHwCounters", false, "Enable Mali counters");
+ANKI_CVAR(BoolCVar, Core, MaliHwCounters, false, "Enable Mali counters")
 #endif
 
-inline StatCounter g_cpuTotalTimeStatVar(StatCategory::kTime, "CPU total",
-										 StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(CpuTotalTime, StatCategory::kTime, "CPU total", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates)
 
 /// The core class of the engine.
 class App

+ 7 - 7
AnKi/Core/CoreTracer.cpp

@@ -92,15 +92,15 @@ CoreTracer::~CoreTracer()
 Error CoreTracer::init(CString directory)
 {
 	Tracer::allocateSingleton();
-	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar)
+	if(Tracer::getSingleton().getEnabled() != g_cvarCoreTracingEnabled)
 	{
 		// Change the value inside the if because setEnabled prints a message
-		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar);
+		Tracer::getSingleton().setEnabled(g_cvarCoreTracingEnabled);
 	}
 #	if ANKI_OS_ANDROID
 	if(Tracer::getSingleton().getStreamlineEnabled())
 	{
-		Tracer::getSingleton().setStreamlineEnabled(g_streamlineEnabledCVar);
+		Tracer::getSingleton().setStreamlineEnabled(g_cvarCoreStreamlineEnabled);
 	}
 #	endif
 
@@ -329,15 +329,15 @@ void CoreTracer::flushFrame(U64 frame)
 		},
 		&ctx);
 
-	if(Tracer::getSingleton().getEnabled() != g_tracingEnabledCVar)
+	if(Tracer::getSingleton().getEnabled() != g_cvarCoreTracingEnabled)
 	{
-		Tracer::getSingleton().setEnabled(g_tracingEnabledCVar);
+		Tracer::getSingleton().setEnabled(g_cvarCoreTracingEnabled);
 	}
 
 #	if ANKI_OS_ANDROID
-	if(Tracer::getSingleton().getStreamlineEnabled() != g_streamlineEnabledCVar)
+	if(Tracer::getSingleton().getStreamlineEnabled() != g_cvarCoreStreamlineEnabled)
 	{
-		Tracer::getSingleton().setStreamlineEnabled(g_streamlineEnabledCVar);
+		Tracer::getSingleton().setStreamlineEnabled(g_cvarCoreStreamlineEnabled);
 	}
 #	endif
 }

+ 2 - 2
AnKi/Core/CoreTracer.h

@@ -16,9 +16,9 @@ namespace anki {
 /// @addtogroup core
 /// @{
 
-inline BoolCVar g_tracingEnabledCVar("Core", "Tracing", false, "Enable or disable tracing");
+ANKI_CVAR(BoolCVar, Core, TracingEnabled, false, "Enable or disable tracing")
 #if ANKI_OS_ANDROID
-inline BoolCVar g_streamlineEnabledCVar("Core", "StreamlineAnnotations", false, "Enable or disable Streamline annotations");
+ANKI_CVAR(BoolCVar, Core, StreamlineAnnotations, false, "Enable or disable Streamline annotations")
 #endif
 
 #if ANKI_TRACING_ENABLED

+ 4 - 1
AnKi/Core/StatsSet.h

@@ -16,6 +16,9 @@ namespace anki {
 /// @addtogroup core
 /// @{
 
+/// Define a global stat variable.
+#define ANKI_SVAR(name, category, descr, ...) inline StatCounter g_svar##name(category, descr, StatFlag::kNone | __VA_ARGS__);
+
 enum class StatFlag : U16
 {
 	kNone = 0,
@@ -57,7 +60,7 @@ class StatCounter
 public:
 	/// Construct.
 	/// @param name Name of the counter. The object will share ownership of the pointer.
-	StatCounter(StatCategory category, const Char* name, StatFlag flags);
+	StatCounter(StatCategory category, const Char* name, StatFlag flags = StatFlag::kNone);
 
 	template<std::integral T>
 	U64 increment(T value)

+ 7 - 9
AnKi/GpuMemory/GpuSceneBuffer.cpp

@@ -11,15 +11,13 @@
 
 namespace anki {
 
-inline StatCounter g_gpuSceneBufferAllocatedSizeStatVar(StatCategory::kGpuMem, "GPU scene allocated",
-														StatFlag::kBytes | StatFlag::kMainThreadUpdates);
-inline StatCounter g_gpuSceneBufferTotalStatVar(StatCategory::kGpuMem, "GPU scene total", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
-inline StatCounter g_gpuSceneBufferFragmentationStatVar(StatCategory::kGpuMem, "GPU scene fragmentation",
-														StatFlag::kFloat | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(GpuSceneBufferAllocatedSize, StatCategory::kGpuMem, "GPU scene allocated", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
+ANKI_SVAR(GpuSceneBufferTotal, StatCategory::kGpuMem, "GPU scene total", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
+ANKI_SVAR(GpuSceneBufferFragmentation, StatCategory::kGpuMem, "GPU scene fragmentation", StatFlag::kFloat | StatFlag::kMainThreadUpdates);
 
 void GpuSceneBuffer::init()
 {
-	const PtrSize poolSize = g_gpuSceneInitialSizeCVar;
+	const PtrSize poolSize = g_cvarCoreGpuSceneInitialSize;
 
 	const Array classes = {32_B, 64_B, 128_B, 256_B, poolSize};
 
@@ -38,9 +36,9 @@ void GpuSceneBuffer::updateStats() const
 	PtrSize userAllocatedSize, totalSize;
 	m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
 
-	g_gpuSceneBufferAllocatedSizeStatVar.set(userAllocatedSize);
-	g_gpuSceneBufferTotalStatVar.set(totalSize);
-	g_gpuSceneBufferFragmentationStatVar.set(externalFragmentation);
+	g_svarGpuSceneBufferAllocatedSize.set(userAllocatedSize);
+	g_svarGpuSceneBufferTotal.set(totalSize);
+	g_svarGpuSceneBufferFragmentation.set(externalFragmentation);
 }
 
 /// It packs the source and destination offsets as well as the size of the patch itself.

+ 1 - 1
AnKi/GpuMemory/GpuSceneBuffer.h

@@ -16,7 +16,7 @@ namespace anki {
 /// @addtogroup gpu_memory
 /// @{
 
-inline NumericCVar<PtrSize> g_gpuSceneInitialSizeCVar("Core", "GpuSceneInitialSize", 64_MB, 16_MB, 2_GB, "Global memory for the GPU scene");
+ANKI_CVAR(NumericCVar<PtrSize>, Core, GpuSceneInitialSize, 64_MB, 16_MB, 2_GB, "Global memory for the GPU scene")
 
 /// @memberof GpuSceneBuffer
 class GpuSceneBufferAllocation

+ 2 - 3
AnKi/GpuMemory/GpuVisibleTransientMemoryPool.cpp

@@ -8,12 +8,11 @@
 
 namespace anki {
 
-static StatCounter g_gpuVisibleTransientMemoryStatVar(StatCategory::kGpuMem, "GPU visible transient mem",
-													  StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(GpuVisibleTransientMemory, StatCategory::kGpuMem, "GPU visible transient mem", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
 
 void GpuVisibleTransientMemoryPool::endFrame()
 {
-	g_gpuVisibleTransientMemoryStatVar.set(m_pool.getAllocatedMemory());
+	g_svarGpuVisibleTransientMemory.set(m_pool.getAllocatedMemory());
 
 	if(m_frame == 0)
 	{

+ 3 - 3
AnKi/GpuMemory/RebarTransientMemoryPool.cpp

@@ -10,7 +10,7 @@
 
 namespace anki {
 
-inline StatCounter g_rebarUserMemoryStatVar(StatCategory::kGpuMem, "ReBAR used mem", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(RebarUserMemory, StatCategory::kGpuMem, "ReBAR used mem", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
 
 RebarTransientMemoryPool::~RebarTransientMemoryPool()
 {
@@ -24,7 +24,7 @@ void RebarTransientMemoryPool::init()
 {
 	BufferInitInfo buffInit("ReBar");
 	buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
-	buffInit.m_size = g_rebarGpuMemorySizeCvar;
+	buffInit.m_size = g_cvarCoreRebarGpuMemorySize;
 	buffInit.m_usage = BufferUsageBit::kAllConstant | BufferUsageBit::kAllUav | BufferUsageBit::kAllSrv | BufferUsageBit::kVertexOrIndex
 					   | BufferUsageBit::kShaderBindingTable | BufferUsageBit::kAllIndirect | BufferUsageBit::kCopySource;
 	m_buffer = GrManager::getSingleton().newBuffer(buffInit);
@@ -76,7 +76,7 @@ void RebarTransientMemoryPool::endFrame()
 	}
 
 	ANKI_TRACE_INC_COUNTER(ReBarUsedMemory, usedMemory);
-	g_rebarUserMemoryStatVar.set(usedMemory);
+	g_svarRebarUserMemory.set(usedMemory);
 }
 
 } // end namespace anki

+ 1 - 1
AnKi/GpuMemory/RebarTransientMemoryPool.h

@@ -15,7 +15,7 @@ namespace anki {
 /// @addtogroup gpu_memory
 /// @{
 
-inline NumericCVar<PtrSize> g_rebarGpuMemorySizeCvar("Core", "RebarGpuMemorySize", 24_MB, 1_MB, 1_GB, "ReBAR: always mapped GPU memory");
+ANKI_CVAR(NumericCVar<PtrSize>, Core, RebarGpuMemorySize, 24_MB, 1_MB, 1_GB, "ReBAR: always mapped GPU memory")
 
 /// Manages staging GPU memory.
 class RebarTransientMemoryPool : public MakeSingleton<RebarTransientMemoryPool>

+ 7 - 8
AnKi/GpuMemory/UnifiedGeometryBuffer.cpp

@@ -8,14 +8,13 @@
 
 namespace anki {
 
-inline StatCounter g_unifiedGeomBufferAllocatedSizeStatVar(StatCategory::kGpuMem, "UGB allocated", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
-inline StatCounter g_unifiedGeomBufferTotalStatVar(StatCategory::kGpuMem, "UGB total", StatFlag::kBytes | StatFlag::kMainThreadUpdates);
-inline StatCounter g_unifiedGeomBufferFragmentationStatVar(StatCategory::kGpuMem, "UGB fragmentation",
-														   StatFlag::kFloat | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(UnifiedGeomBufferAllocatedSize, StatCategory::kGpuMem, "UGB allocated", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
+ANKI_SVAR(UnifiedGeomBufferTotal, StatCategory::kGpuMem, "UGB total", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
+ANKI_SVAR(UnifiedGeomBufferFragmentation, StatCategory::kGpuMem, "UGB fragmentation", StatFlag::kFloat | StatFlag::kMainThreadUpdates)
 
 void UnifiedGeometryBuffer::init()
 {
-	const PtrSize poolSize = g_unifiedGometryBufferSizeCvar;
+	const PtrSize poolSize = g_cvarCoreUnifiedGeometryBufferSize;
 
 	const Array classes = {1_KB, 8_KB, 32_KB, 128_KB, 512_KB, 4_MB, 8_MB, 16_MB, poolSize};
 
@@ -39,9 +38,9 @@ void UnifiedGeometryBuffer::updateStats() const
 	PtrSize userAllocatedSize, totalSize;
 	m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
 
-	g_unifiedGeomBufferAllocatedSizeStatVar.set(userAllocatedSize);
-	g_unifiedGeomBufferTotalStatVar.set(totalSize);
-	g_unifiedGeomBufferFragmentationStatVar.set(externalFragmentation);
+	g_svarUnifiedGeomBufferAllocatedSize.set(userAllocatedSize);
+	g_svarUnifiedGeomBufferTotal.set(totalSize);
+	g_svarUnifiedGeomBufferFragmentation.set(externalFragmentation);
 }
 
 } // end namespace anki

+ 1 - 2
AnKi/GpuMemory/UnifiedGeometryBuffer.h

@@ -14,8 +14,7 @@ namespace anki {
 /// @addtogroup gpu_memory
 /// @{
 
-inline NumericCVar<PtrSize> g_unifiedGometryBufferSizeCvar("Core", "UnifiedGeometryBufferSize", 128_MB, 16_MB, 2_GB,
-														   "Global index and vertex buffer size");
+ANKI_CVAR(NumericCVar<PtrSize>, Core, UnifiedGeometryBufferSize, 128_MB, 16_MB, 2_GB, "Global index and vertex buffer size")
 
 /// @memberof UnifiedGeometryBuffer
 class UnifiedGeometryBufferAllocation

+ 1 - 1
AnKi/Gr/BackendCommon/MicroFenceFactory.h

@@ -67,7 +67,7 @@ public:
 		else
 		{
 			// Not signaled and has handle
-			seconds = min<Second>(seconds, g_gpuTimeoutCVar);
+			seconds = min<Second>(seconds, g_cvarGrGpuTimeout);
 			bSignaled = m_impl.clientWait(seconds);
 		}
 

+ 4 - 4
AnKi/Gr/BackendCommon/MicroFenceFactory.inl.h

@@ -8,7 +8,7 @@
 
 namespace anki {
 
-inline StatCounter g_fenceCountStatVar(StatCategory::kGr, "Fence count", StatFlag::kNone);
+ANKI_SVAR(FenceCount, StatCategory::kGr, "Fence count", StatFlag::kNone)
 
 template<typename TImplementation>
 MicroFenceFactory<TImplementation>::~MicroFenceFactory()
@@ -29,7 +29,7 @@ MicroFenceFactory<TImplementation>::~MicroFenceFactory()
 			fence.m_impl.destroy();
 			ANKI_ASSERT(m_aliveFenceCount > 0);
 			--m_aliveFenceCount;
-			g_fenceCountStatVar.decrement(1_U64);
+			g_svarFenceCount.decrement(1_U64);
 		}
 
 		m_fences.erase(idx);
@@ -88,7 +88,7 @@ MicroFenceFactory<TImplementation>::MyMicroFence* MicroFenceFactory<TImplementat
 					it->m_impl.destroy();
 					ANKI_ASSERT(m_aliveFenceCount > 0);
 					--m_aliveFenceCount;
-					g_fenceCountStatVar.decrement(1_U64);
+					g_svarFenceCount.decrement(1_U64);
 				}
 			}
 		}
@@ -123,7 +123,7 @@ MicroFenceFactory<TImplementation>::MyMicroFence* MicroFenceFactory<TImplementat
 
 		out->m_impl.create();
 
-		g_fenceCountStatVar.increment(1_U64);
+		g_svarFenceCount.increment(1_U64);
 		++m_aliveFenceCount;
 		if(m_aliveFenceCount > kMaxAliveFences)
 		{

+ 27 - 29
AnKi/Gr/Common.h

@@ -36,37 +36,35 @@ class PipelineQueryInitInfo;
 /// @addtogroup graphics
 /// @{
 
-inline BoolCVar g_validationCVar("Gr", "Validation", false, "Enable or not validation");
-inline BoolCVar g_gpuValidationCVar("Gr", "GpuValidation", false, "Enable or not GPU validation");
-inline BoolCVar g_vsyncCVar("Gr", "Vsync", false, "Enable or not vsync");
-inline BoolCVar g_debugMarkersCVar("Gr", "DebugMarkers", false, "Enable or not debug markers");
-inline BoolCVar g_meshShadersCVar("Gr", "MeshShaders", false, "Enable or not mesh shaders");
-inline NumericCVar<U8> g_deviceCVar("Gr", "Device", 0, 0, 16, "Choose an available device. Devices are sorted by performance");
-inline BoolCVar g_rayTracingCVar("Gr", "RayTracing", false, "Try enabling ray tracing");
-inline BoolCVar g_vrsCVar("Gr", "Vrs", false, "Enable or not VRS");
-inline BoolCVar g_workGraphcsCVar("Gr", "WorkGraphs", false, "Enable or not WorkGraphs");
-inline NumericCVar<U32> g_maxBindlessSampledTextureCountCVar("Gr", "MaxBindlessSampledTextureCountCVar", 512, 16, kMaxU16);
-inline NumericCVar<Second> g_gpuTimeoutCVar("Gr", "GpuTimeout", 120.0, 0.0, 24.0 * 60.0,
-											"Max time to wait for GPU fences or semaphores. More than that it must be a GPU timeout");
-inline NumericCVar<U8> g_asyncComputeCVar("Gr", "AsyncCompute", 0, 0, 2,
-										  "Control the async compute behaviour: 0: Try use separate queue family, 1: Use lower priority queue in the "
-										  "general's queue family, 2: Use the general queue");
+ANKI_CVAR(BoolCVar, Gr, Validation, false, "Enable or not validation")
+ANKI_CVAR(BoolCVar, Gr, GpuValidation, false, "Enable or not GPU validation")
+ANKI_CVAR(BoolCVar, Gr, Vsync, false, "Enable or not vsync")
+ANKI_CVAR(BoolCVar, Gr, DebugMarkers, false, "Enable or not debug markers");
+ANKI_CVAR(BoolCVar, Gr, MeshShaders, false, "Enable or not mesh shaders");
+ANKI_CVAR(NumericCVar<U8>, Gr, Device, 0, 0, 16, "Choose an available device. Devices are sorted by performance")
+ANKI_CVAR(BoolCVar, Gr, RayTracing, false, "Try enabling ray tracing")
+ANKI_CVAR(BoolCVar, Gr, Vrs, false, "Enable or not VRS")
+ANKI_CVAR(BoolCVar, Gr, WorkGraphcs, false, "Enable or not WorkGraphs")
+ANKI_CVAR(NumericCVar<U32>, Gr, MaxBindlessSampledTextureCount, 512, 16, kMaxU16)
+ANKI_CVAR(NumericCVar<Second>, Gr, GpuTimeout, 120.0, 0.0, 24.0 * 60.0,
+		  "Max time to wait for GPU fences or semaphores. More than that it must be a GPU timeout")
+ANKI_CVAR(NumericCVar<U8>, Gr, AsyncCompute, 0, 0, 2,
+		  "Control the async compute behaviour: 0: Try use separate queue family, 1: Use lower priority queue in the general's queue family, 2: Use "
+		  "the general queue")
 #if ANKI_GR_BACKEND_DIRECT3D
-inline NumericCVar<U16> g_maxRtvDescriptorsCVar("Gr", "MaxRvtDescriptors", 1024, 8, kMaxU16, "Max number of RTVs");
-inline NumericCVar<U16> g_maxDsvDescriptorsCVar("Gr", "MaxDsvDescriptors", 512, 8, kMaxU16, "Max number of DSVs");
-inline NumericCVar<U16> g_maxCpuCbvSrvUavDescriptorsCVar("Gr", "MaxCpuCbvSrvUavDescriptors", 16 * 1024, 8, kMaxU16,
-														 "Max number of CBV/SRV/UAV descriptors");
-inline NumericCVar<U16> g_maxCpuSamplerDescriptorsCVar("Gr", "MaxCpuSamplerDescriptors", 512, 8, kMaxU16, "Max number of sampler descriptors");
-inline NumericCVar<U16> g_maxGpuCbvSrvUavDescriptorsCVar("Gr", "MaxGpuCbvSrvUavDescriptors", 16 * 1024, 8, kMaxU16,
-														 "Max number of CBV/SRV/UAV descriptors");
-inline NumericCVar<U16> g_maxGpuSamplerDescriptorsCVar("Gr", "MaxGpuSamplerDescriptors", 2 * 1024, 8, kMaxU16, "Max number of sampler descriptors");
-
-inline BoolCVar g_dredCVar("Gr", "Dred", false, "Enable DRED");
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxRtvDescriptors, 1024, 8, kMaxU16, "Max number of RTVs")
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxDsvDescriptors, 512, 8, kMaxU16, "Max number of DSVs");
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxCpuCbvSrvUavDescriptors, 16 * 1024, 8, kMaxU16, "Max number of CBV/SRV/UAV descriptors")
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxCpuSamplerDescriptors, 512, 8, kMaxU16, "Max number of sampler descriptors")
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxGpuCbvSrvUavDescriptors, 16 * 1024, 8, kMaxU16, "Max number of CBV/SRV/UAV descriptors")
+ANKI_CVAR(NumericCVar<U16>, Gr, MaxGpuSamplerDescriptors, 2 * 1024, 8, kMaxU16, "Max number of sampler descriptors")
+
+ANKI_CVAR(BoolCVar, Gr, Dred, false, "Enable DRED")
 #else
-inline NumericCVar<PtrSize> g_diskShaderCacheMaxSizeCVar("Gr", "DiskShaderCacheMaxSize", 128_MB, 1_MB, 1_GB, "Max size of the pipeline cache file");
-inline BoolCVar g_debugPrintfCVar("Gr", "DebugPrintf", false, "Enable or not debug printf");
-inline BoolCVar g_samplerFilterMinMaxCVar("Gr", "SamplerFilterMinMax", true, "Enable or not min/max sample filtering");
-inline StringCVar g_vkLayersCVar("Gr", "VkLayers", "", "VK layers to enable. Seperated by :");
+ANKI_CVAR(NumericCVar<PtrSize>, Gr, DiskShaderCacheMaxSize, 128_MB, 1_MB, 1_GB, "Max size of the pipeline cache file")
+ANKI_CVAR(BoolCVar, Gr, DebugPrintf, false, "Enable or not debug printf")
+ANKI_CVAR(BoolCVar, Gr, SamplerFilterMinMax, true, "Enable or not min/max sample filtering")
+ANKI_CVAR(StringCVar, Gr, VkLayers, "", "VK layers to enable. Seperated by :")
 #endif
 
 #define ANKI_GR_LOGI(...) ANKI_LOG("GR", kNormal, __VA_ARGS__)

+ 1 - 1
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -1065,7 +1065,7 @@ Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 
 	m_descriptors.init(&m_fastPool);
 
-	m_debugMarkersEnabled = g_debugMarkersCVar;
+	m_debugMarkersEnabled = g_cvarGrDebugMarkers;
 
 	m_timestampQueries = {&m_fastPool};
 	m_pipelineQueries = {&m_fastPool};

+ 3 - 3
AnKi/Gr/D3D/D3DCommandBufferFactory.cpp

@@ -9,14 +9,14 @@
 
 namespace anki {
 
-static StatCounter g_commandBufferCountStatVar(StatCategory::kGr, "CommandBufferCount", StatFlag::kNone);
+ANKI_SVAR(CommandBufferCount, StatCategory::kGr, "CommandBufferCount", StatFlag::kNone)
 
 MicroCommandBuffer::~MicroCommandBuffer()
 {
 	safeRelease(m_cmdList);
 	safeRelease(m_cmdAllocator);
 
-	g_commandBufferCountStatVar.decrement(1);
+	g_svarCommandBufferCount.decrement(1);
 }
 
 Error MicroCommandBuffer::init(CommandBufferFlag flags)
@@ -30,7 +30,7 @@ Error MicroCommandBuffer::init(CommandBufferFlag flags)
 	ANKI_D3D_CHECK(getDevice().CreateCommandList(0, cmdListType, m_cmdAllocator, nullptr, IID_PPV_ARGS(&cmdList)));
 	ANKI_D3D_CHECK(cmdList->QueryInterface(IID_PPV_ARGS(&m_cmdList)));
 
-	g_commandBufferCountStatVar.increment(1);
+	g_svarCommandBufferCount.increment(1);
 
 	return Error::kNone;
 }

+ 12 - 12
AnKi/Gr/D3D/D3DDescriptor.cpp

@@ -189,13 +189,13 @@ Error DescriptorFactory::init()
 		return Error::kNone;
 	};
 
-	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_maxCpuCbvSrvUavDescriptorsCVar,
+	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_cvarGrMaxCpuCbvSrvUavDescriptors,
 									  "CPU CBV/SRV/UAV", m_cpuPersistent.m_cbvSrvUav));
-	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_maxCpuSamplerDescriptorsCVar,
+	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_cvarGrMaxCpuSamplerDescriptors,
 									  "CPU samplers", m_cpuPersistent.m_sampler));
-	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_maxRtvDescriptorsCVar, "CPU RTV",
+	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_cvarGrMaxRtvDescriptors, "CPU RTV",
 									  m_cpuPersistent.m_rtv));
-	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_maxDsvDescriptorsCVar, "CPU DSV",
+	ANKI_CHECK(createHeapAndAllocator(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_cvarGrMaxDsvDescriptors, "CPU DSV",
 									  m_cpuPersistent.m_dsv));
 
 	// Init GPU visible heaps
@@ -204,20 +204,20 @@ Error DescriptorFactory::init()
 	D3D12_GPU_DESCRIPTOR_HANDLE gpuHeapStart;
 	U32 descriptorSize;
 	ANKI_CHECK(createDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
-									g_maxGpuCbvSrvUavDescriptorsCVar + g_maxBindlessSampledTextureCountCVar, "GPU CBV/SRV/UAV", heap, cpuHeapStart,
-									gpuHeapStart, descriptorSize));
+									g_cvarGrMaxGpuCbvSrvUavDescriptors + g_cvarGrMaxBindlessSampledTextureCount, "GPU CBV/SRV/UAV", heap,
+									cpuHeapStart, gpuHeapStart, descriptorSize));
 	m_descriptorHeaps.emplaceBack(heap);
 
-	m_gpuPersistent.m_cbvSrvUav.init(cpuHeapStart, gpuHeapStart, descriptorSize, U16(g_maxBindlessSampledTextureCountCVar));
+	m_gpuPersistent.m_cbvSrvUav.init(cpuHeapStart, gpuHeapStart, descriptorSize, U16(g_cvarGrMaxBindlessSampledTextureCount));
 
-	cpuHeapStart.ptr += descriptorSize * g_maxBindlessSampledTextureCountCVar;
-	gpuHeapStart.ptr += descriptorSize * g_maxBindlessSampledTextureCountCVar;
-	m_gpuRing.m_cbvSrvUav.init(cpuHeapStart, gpuHeapStart, descriptorSize, g_maxGpuCbvSrvUavDescriptorsCVar, "CBV/SRV/UAV");
+	cpuHeapStart.ptr += descriptorSize * g_cvarGrMaxBindlessSampledTextureCount;
+	gpuHeapStart.ptr += descriptorSize * g_cvarGrMaxBindlessSampledTextureCount;
+	m_gpuRing.m_cbvSrvUav.init(cpuHeapStart, gpuHeapStart, descriptorSize, g_cvarGrMaxGpuCbvSrvUavDescriptors, "CBV/SRV/UAV");
 
-	ANKI_CHECK(createDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, g_maxGpuSamplerDescriptorsCVar,
+	ANKI_CHECK(createDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, g_cvarGrMaxGpuSamplerDescriptors,
 									"GPU samplers", heap, cpuHeapStart, gpuHeapStart, descriptorSize));
 	m_descriptorHeaps.emplaceBack(heap);
-	m_gpuRing.m_sampler.init(cpuHeapStart, gpuHeapStart, descriptorSize, g_maxGpuSamplerDescriptorsCVar, "Samplers");
+	m_gpuRing.m_sampler.init(cpuHeapStart, gpuHeapStart, descriptorSize, g_cvarGrMaxGpuSamplerDescriptors, "Samplers");
 
 	// Misc
 	for(D3D12_DESCRIPTOR_HEAP_TYPE type = D3D12_DESCRIPTOR_HEAP_TYPE(0); type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;

+ 13 - 13
AnKi/Gr/D3D/D3DGrManager.cpp

@@ -232,7 +232,7 @@ void GrManagerImpl::endFrameInternal()
 {
 	ANKI_TRACE_FUNCTION();
 
-	m_crntSwapchain->m_swapchain->Present((g_vsyncCVar) ? 1 : 0, (g_vsyncCVar) ? 0 : DXGI_PRESENT_ALLOW_TEARING);
+	m_crntSwapchain->m_swapchain->Present((g_cvarGrVsync) ? 1 : 0, (g_cvarGrVsync) ? 0 : DXGI_PRESENT_ALLOW_TEARING);
 
 	MicroFencePtr presentFence = FenceFactory::getSingleton().newInstance("Present");
 	presentFence->getImplementation().gpuSignal(GpuQueueType::kGeneral); // Only general can present
@@ -346,7 +346,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 
 	// Validation
 	UINT dxgiFactoryFlags = 0;
-	if(g_validationCVar || g_gpuValidationCVar)
+	if(g_cvarGrValidation || g_cvarGrGpuValidation)
 	{
 		ComPtr<ID3D12Debug> debugInterface;
 		ANKI_D3D_CHECK(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)));
@@ -355,7 +355,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 
 		dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
 
-		if(g_gpuValidationCVar)
+		if(g_cvarGrGpuValidation)
 		{
 			ComPtr<ID3D12Debug1> debugInterface1;
 			ANKI_D3D_CHECK(debugInterface->QueryInterface(IID_PPV_ARGS(&debugInterface1)));
@@ -363,7 +363,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 			debugInterface1->SetEnableGPUBasedValidation(true);
 		}
 
-		ANKI_D3D_LOGI("Validation is enabled (GPU validation %s)", (g_gpuValidationCVar) ? "as well" : "no");
+		ANKI_D3D_LOGI("Validation is enabled (GPU validation %s)", (g_cvarGrGpuValidation) ? "as well" : "no");
 	}
 
 	ComPtr<IDXGIFactory2> factory2;
@@ -390,7 +390,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 		++adapterIdx;
 	}
 
-	const U32 chosenPhysDevIdx = min<U32>(g_deviceCVar, adapters.getSize() - 1);
+	const U32 chosenPhysDevIdx = min<U32>(g_cvarGrDevice, adapters.getSize() - 1);
 
 	ANKI_D3D_LOGI("Physical devices:");
 	for(U32 i = 0; i < adapters.getSize(); ++i)
@@ -427,7 +427,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	ANKI_D3D_CHECK(D3D12CreateDevice(adapters[chosenPhysDevIdx].m_adapter.Get(), D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&dev)));
 	ANKI_D3D_CHECK(dev->QueryInterface(IID_PPV_ARGS(&m_device)));
 
-	if(g_validationCVar)
+	if(g_cvarGrValidation)
 	{
 		ComPtr<ID3D12InfoQueue1> infoq;
 		const HRESULT res = m_device->QueryInterface(IID_PPV_ARGS(&infoq));
@@ -456,7 +456,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 		}
 	}
 
-	if(g_dredCVar)
+	if(g_cvarGrDred)
 	{
 		ComPtr<ID3D12DeviceRemovedExtendedDataSettings> dredSettings;
 		ANKI_D3D_CHECK(D3D12GetDebugInterface(IID_PPV_ARGS(&dredSettings)));
@@ -494,11 +494,11 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 		D3D12_FEATURE_DATA_D3D12_OPTIONS21 options21;
 		ANKI_D3D_CHECK(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS21, &options21, sizeof(options21)));
 
-		if(g_workGraphcsCVar && options21.WorkGraphsTier == D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED)
+		if(g_cvarGrWorkGraphcs && options21.WorkGraphsTier == D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED)
 		{
 			ANKI_D3D_LOGW("WorkGraphs can't be enabled. They not supported");
 		}
-		else if(g_workGraphcsCVar && options21.WorkGraphsTier != D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED)
+		else if(g_cvarGrWorkGraphcs && options21.WorkGraphsTier != D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED)
 		{
 			ANKI_D3D_LOGV("WorkGraphs supported");
 			m_capabilities.m_workGraphs = true;
@@ -510,12 +510,12 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 			ANKI_D3D_LOGW("ReBAR not supported");
 		}
 
-		if(g_rayTracingCVar && options5.RaytracingTier != D3D12_RAYTRACING_TIER_1_1)
+		if(g_cvarGrRayTracing && options5.RaytracingTier != D3D12_RAYTRACING_TIER_1_1)
 		{
 			ANKI_D3D_LOGW("Raytracing can't be enabled. Not supported");
 			m_capabilities.m_rayTracingEnabled = false;
 		}
-		else if(g_rayTracingCVar && options5.RaytracingTier == D3D12_RAYTRACING_TIER_1_1)
+		else if(g_cvarGrRayTracing && options5.RaytracingTier == D3D12_RAYTRACING_TIER_1_1)
 		{
 			ANKI_D3D_LOGV("Raytracing supported");
 			m_capabilities.m_rayTracingEnabled = true;
@@ -537,10 +537,10 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 		m_capabilities.m_maxDrawIndirectCount = kMaxU32;
 		m_capabilities.m_discreteGpu = !architecture.UMA;
 		m_capabilities.m_majorApiVersion = 12;
-		m_capabilities.m_vrs = g_vrsCVar;
+		m_capabilities.m_vrs = g_cvarGrVrs;
 		m_capabilities.m_unalignedBbpTextureFormats = false;
 		m_capabilities.m_dlss = false;
-		m_capabilities.m_meshShaders = g_meshShadersCVar;
+		m_capabilities.m_meshShaders = g_cvarGrMeshShaders;
 		m_capabilities.m_pipelineQuery = true;
 		m_capabilities.m_barycentrics = true;
 		m_capabilities.m_shaderGroupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES;

+ 1 - 1
AnKi/Gr/D3D/D3DGrUpscaler.cpp

@@ -23,7 +23,7 @@ GrUpscalerImpl::~GrUpscalerImpl()
 {
 }
 
-Error GrUpscalerImpl::initInternal(const GrUpscalerInitInfo& initInfo)
+Error GrUpscalerImpl::initInternal([[maybe_unused]] const GrUpscalerInitInfo& initInfo)
 {
 	ANKI_ASSERT(!"TODO");
 	return Error::kNone;

+ 2 - 2
AnKi/Gr/D3D/D3DSwapchainFactory.cpp

@@ -45,7 +45,7 @@ Error MicroSwapchain::initInternal()
 		static_cast<HWND>(SDL_GetPointerProperty(SDL_GetWindowProperties(window.m_sdlWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL));
 
 	ComPtr<IDXGIFactory2> factory2;
-	ANKI_D3D_CHECK(CreateDXGIFactory2((g_validationCVar) ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&factory2)));
+	ANKI_D3D_CHECK(CreateDXGIFactory2((g_cvarGrValidation) ? DXGI_CREATE_FACTORY_DEBUG : 0, IID_PPV_ARGS(&factory2)));
 
 	// Describe and create the swap chain.
 	DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
@@ -56,7 +56,7 @@ Error MicroSwapchain::initInternal()
 	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
 	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
 	swapChainDesc.SampleDesc.Count = 1;
-	swapChainDesc.Flags |= (!g_vsyncCVar) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
+	swapChainDesc.Flags |= (!g_cvarGrVsync) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
 
 	ComPtr<IDXGISwapChain1> swapChain;
 	// Swap chain needs the queue so that it can force a flush on it.

+ 3 - 3
AnKi/Gr/Vulkan/VkCommandBufferFactory.cpp

@@ -10,7 +10,7 @@
 
 namespace anki {
 
-static StatCounter g_commandBufferCountStatVar(StatCategory::kGr, "CommandBufferCount", StatFlag::kNone);
+ANKI_SVAR(CommandBufferCount, StatCategory::kGr, "CommandBufferCount", StatFlag::kNone)
 
 MicroCommandBuffer::~MicroCommandBuffer()
 {
@@ -24,7 +24,7 @@ MicroCommandBuffer::~MicroCommandBuffer()
 		vkFreeCommandBuffers(getVkDevice(), m_threadAlloc->m_pools[queueFamilyIdx], 1, &m_handle);
 		m_handle = {};
 
-		g_commandBufferCountStatVar.decrement(1_U64);
+		g_svarCommandBufferCount.decrement(1_U64);
 	}
 }
 
@@ -110,7 +110,7 @@ Error CommandBufferThreadAllocator::newCommandBuffer(CommandBufferFlag cmdbFlags
 		ci.commandBufferCount = 1;
 
 		ANKI_TRACE_INC_COUNTER(VkCommandBufferCreate, 1);
-		g_commandBufferCountStatVar.increment(1_U64);
+		g_svarCommandBufferCount.increment(1_U64);
 		VkCommandBuffer cmdb;
 		ANKI_VK_CHECK(vkAllocateCommandBuffers(getVkDevice(), &ci, &cmdb));
 

+ 5 - 5
AnKi/Gr/Vulkan/VkDescriptor.cpp

@@ -10,8 +10,8 @@
 
 namespace anki {
 
-static StatCounter g_descriptorSetsAllocatedStatVar(StatCategory::kGr, "DescriptorSets allocated this frame", StatFlag::kZeroEveryFrame);
-static StatCounter g_descriptorSetsWrittenStatVar(StatCategory::kGr, "DescriptorSets written this frame", StatFlag::kZeroEveryFrame);
+ANKI_SVAR(DescriptorSetsAllocated, StatCategory::kGr, "DescriptorSets allocated this frame", StatFlag::kZeroEveryFrame)
+ANKI_SVAR(DescriptorSetsWritten, StatCategory::kGr, "DescriptorSets written this frame", StatFlag::kZeroEveryFrame)
 
 /// Contains some constants. It's a class to avoid bugs initializing arrays (m_descriptorCount).
 class DSAllocatorConstants
@@ -85,7 +85,7 @@ void DescriptorAllocator::createNewBlock()
 	block.m_pool = handle;
 	block.m_maxDsets = inf.maxSets;
 
-	g_descriptorSetsAllocatedStatVar.increment(1);
+	g_svarDescriptorSetsAllocated.increment(1);
 }
 
 void DescriptorAllocator::allocate(VkDescriptorSetLayout layout, VkDescriptorSet& set)
@@ -195,7 +195,7 @@ BindlessDescriptorSet::~BindlessDescriptorSet()
 
 Error BindlessDescriptorSet::init()
 {
-	const U32 bindlessTextureCount = g_maxBindlessSampledTextureCountCVar;
+	const U32 bindlessTextureCount = g_cvarGrMaxBindlessSampledTextureCount;
 
 	// Create the layout
 	{
@@ -586,7 +586,7 @@ void DescriptorState::flush(VkCommandBuffer cmdb, DescriptorAllocator& dalloc)
 			if(writeInfoCount > 0)
 			{
 				vkUpdateDescriptorSets(getVkDevice(), writeInfoCount, set.m_writeInfos.getBegin(), 0, nullptr);
-				g_descriptorSetsWrittenStatVar.increment(1);
+				g_svarDescriptorSetsWritten.increment(1);
 			}
 		}
 		else

+ 21 - 21
AnKi/Gr/Vulkan/VkGpuMemoryManager.cpp

@@ -9,12 +9,12 @@
 
 namespace anki {
 
-static StatCounter g_deviceMemoryAllocatedStatVar(StatCategory::kGpuMem, "Device mem", StatFlag::kBytes);
-static StatCounter g_deviceMemoryInUseStatVar(StatCategory::kGpuMem, "Device mem in use", StatFlag::kBytes);
-static StatCounter g_deviceMemoryAllocationCountStatVar(StatCategory::kGpuMem, "Device mem allocations", StatFlag::kNone);
-static StatCounter g_hostMemoryAllocatedStatVar(StatCategory::kGpuMem, "Host mem", StatFlag::kBytes);
-static StatCounter g_hostMemoryInUseStatVar(StatCategory::kGpuMem, "Host mem in use", StatFlag::kBytes);
-static StatCounter g_hostMemoryAllocationCountStatVar(StatCategory::kGpuMem, "Host mem allocations", StatFlag::kNone);
+ANKI_SVAR(DeviceMemoryAllocated, StatCategory::kGpuMem, "Device mem", StatFlag::kBytes)
+ANKI_SVAR(DeviceMemoryInUse, StatCategory::kGpuMem, "Device mem in use", StatFlag::kBytes)
+ANKI_SVAR(DeviceMemoryAllocationCount, StatCategory::kGpuMem, "Device mem allocations", StatFlag::kNone)
+ANKI_SVAR(HostMemoryAllocated, StatCategory::kGpuMem, "Host mem", StatFlag::kBytes)
+ANKI_SVAR(HostMemoryInUse, StatCategory::kGpuMem, "Host mem in use", StatFlag::kBytes)
+ANKI_SVAR(HostMemoryAllocationCount, StatCategory::kGpuMem, "Host mem allocations", StatFlag::kNone)
 
 static constexpr Array<GpuMemoryManagerClassInfo, 7> kClasses{
 	{{4_KB, 256_KB}, {128_KB, 8_MB}, {1_MB, 64_MB}, {16_MB, 128_MB}, {64_MB, 128_MB}, {128_MB, 128_MB}, {256_MB, 256_MB}}};
@@ -269,12 +269,12 @@ U32 GpuMemoryManager::findMemoryType(U32 resourceMemTypeBits, VkMemoryPropertyFl
 
 void GpuMemoryManager::updateStats() const
 {
-	g_deviceMemoryAllocatedStatVar.set(0);
-	g_deviceMemoryAllocationCountStatVar.set(0);
-	g_deviceMemoryInUseStatVar.set(0);
-	g_hostMemoryAllocatedStatVar.set(0);
-	g_hostMemoryAllocationCountStatVar.set(0);
-	g_hostMemoryInUseStatVar.set(0);
+	g_svarDeviceMemoryAllocated.set(0);
+	g_svarDeviceMemoryAllocationCount.set(0);
+	g_svarDeviceMemoryInUse.set(0);
+	g_svarHostMemoryAllocated.set(0);
+	g_svarHostMemoryAllocationCount.set(0);
+	g_svarHostMemoryInUse.set(0);
 
 	for(U32 memTypeIdx = 0; memTypeIdx < m_callocs.getSize(); ++memTypeIdx)
 	{
@@ -284,23 +284,23 @@ void GpuMemoryManager::updateStats() const
 
 		if(iface.m_isDeviceMemory)
 		{
-			g_deviceMemoryAllocatedStatVar.increment(cstats.m_allocatedSize);
-			g_deviceMemoryInUseStatVar.increment(cstats.m_inUseSize);
-			g_deviceMemoryAllocationCountStatVar.increment(cstats.m_chunkCount);
+			g_svarDeviceMemoryAllocated.increment(cstats.m_allocatedSize);
+			g_svarDeviceMemoryInUse.increment(cstats.m_inUseSize);
+			g_svarDeviceMemoryAllocationCount.increment(cstats.m_chunkCount);
 		}
 		else
 		{
-			g_hostMemoryAllocatedStatVar.increment(cstats.m_allocatedSize);
-			g_hostMemoryInUseStatVar.increment(cstats.m_inUseSize);
-			g_hostMemoryAllocationCountStatVar.increment(cstats.m_chunkCount);
+			g_svarHostMemoryAllocated.increment(cstats.m_allocatedSize);
+			g_svarHostMemoryInUse.increment(cstats.m_inUseSize);
+			g_svarHostMemoryAllocationCount.increment(cstats.m_chunkCount);
 		}
 	}
 
 	// Add dedicated stats
 	const PtrSize dedicatedAllocatedMemory = m_dedicatedAllocatedMemory.load();
-	g_deviceMemoryAllocatedStatVar.increment(dedicatedAllocatedMemory);
-	g_deviceMemoryInUseStatVar.increment(dedicatedAllocatedMemory);
-	g_deviceMemoryAllocationCountStatVar.increment(m_dedicatedAllocationCount.load());
+	g_svarDeviceMemoryAllocated.increment(dedicatedAllocatedMemory);
+	g_svarDeviceMemoryInUse.increment(dedicatedAllocatedMemory);
+	g_svarDeviceMemoryAllocationCount.increment(m_dedicatedAllocationCount.load());
 }
 
 void GpuMemoryManager::getImageMemoryRequirements(VkImage image, VkMemoryDedicatedRequirementsKHR& dedicatedRequirements,

+ 22 - 22
AnKi/Gr/Vulkan/VkGrManager.cpp

@@ -256,7 +256,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	PrimitivesPassedClippingFactory::allocateSingleton();
 	SamplerFactory::allocateSingleton();
 
-	SwapchainFactory::allocateSingleton(U32(g_vsyncCVar));
+	SwapchainFactory::allocateSingleton(U32(g_cvarGrVsync));
 	m_crntSwapchain = SwapchainFactory::getSingleton().newInstance();
 
 	// See if unaligned formats are supported
@@ -334,8 +334,8 @@ Error GrManagerImpl::initInstance()
 				ANKI_VK_LOGV("\t%s", layer.layerName);
 				CString layerName = layer.layerName;
 
-				Bool enableLayer = (g_validationCVar || g_debugPrintfCVar) && layerName == "VK_LAYER_KHRONOS_validation";
-				enableLayer = enableLayer || (!CString(g_vkLayersCVar).isEmpty() && CString(g_vkLayersCVar).find(layerName) != CString::kNpos);
+				Bool enableLayer = (g_cvarGrValidation || g_cvarGrDebugPrintf) && layerName == "VK_LAYER_KHRONOS_validation";
+				enableLayer = enableLayer || (!CString(g_cvarGrVkLayers).isEmpty() && CString(g_cvarGrVkLayers).find(layerName) != CString::kNpos);
 
 				if(enableLayer)
 				{
@@ -361,17 +361,17 @@ Error GrManagerImpl::initInstance()
 	// Validation features
 	GrDynamicArray<VkValidationFeatureEnableEXT> enabledValidationFeatures;
 	GrDynamicArray<VkValidationFeatureDisableEXT> disabledValidationFeatures;
-	if(g_debugPrintfCVar)
+	if(g_cvarGrDebugPrintf)
 	{
 		enabledValidationFeatures.emplaceBack(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT);
 	}
 
-	if(g_debugPrintfCVar && !g_validationCVar)
+	if(g_cvarGrDebugPrintf && !g_cvarGrValidation)
 	{
 		disabledValidationFeatures.emplaceBack(VK_VALIDATION_FEATURE_DISABLE_ALL_EXT);
 	}
 
-	if(g_validationCVar && g_gpuValidationCVar)
+	if(g_cvarGrValidation && g_cvarGrGpuValidation)
 	{
 		enabledValidationFeatures.emplaceBack(VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT);
 	}
@@ -455,7 +455,7 @@ Error GrManagerImpl::initInstance()
 				m_extensions |= VulkanExtensions::kKHR_surface;
 				instExtensions[instExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
 			}
-			else if(extensionName == VK_EXT_DEBUG_UTILS_EXTENSION_NAME && (g_debugMarkersCVar || g_validationCVar || g_debugPrintfCVar))
+			else if(extensionName == VK_EXT_DEBUG_UTILS_EXTENSION_NAME && (g_cvarGrDebugMarkers || g_cvarGrValidation || g_cvarGrDebugPrintf))
 			{
 				m_extensions |= VulkanExtensions::kEXT_debug_utils;
 				instExtensions[instExtensionCount++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
@@ -572,7 +572,7 @@ Error GrManagerImpl::initInstance()
 			}
 		});
 
-		const U32 chosenPhysDevIdx = min<U32>(g_deviceCVar, devs.getSize() - 1);
+		const U32 chosenPhysDevIdx = min<U32>(g_cvarGrDevice, devs.getSize() - 1);
 
 		ANKI_VK_LOGI("Physical devices:");
 		for(U32 devIdx = 0; devIdx < count; ++devIdx)
@@ -697,8 +697,8 @@ Error GrManagerImpl::initDevice()
 		return Error::kFunctionFailed;
 	}
 
-	const Bool pureAsyncCompute = m_queueFamilyIndices[GpuQueueType::kCompute] != kMaxU32 && g_asyncComputeCVar == 0;
-	const Bool lowPriorityQueueAsyncCompute = !pureAsyncCompute && generalQueueFamilySupportsMultipleQueues && g_asyncComputeCVar <= 1;
+	const Bool pureAsyncCompute = m_queueFamilyIndices[GpuQueueType::kCompute] != kMaxU32 && g_cvarGrAsyncCompute == 0;
+	const Bool lowPriorityQueueAsyncCompute = !pureAsyncCompute && generalQueueFamilySupportsMultipleQueues && g_cvarGrAsyncCompute <= 1;
 
 	Array<F32, U32(GpuQueueType::kCount)> priorities = {1.0f, 0.5f};
 	Array<VkDeviceQueueCreateInfo, U32(GpuQueueType::kCount)> q = {};
@@ -780,38 +780,38 @@ Error GrManagerImpl::initDevice()
 				m_extensions |= VulkanExtensions::kKHR_swapchain;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				m_extensions |= VulkanExtensions::kKHR_ray_tracing;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 				m_capabilities.m_rayTracingEnabled = true;
 			}
-			else if(extensionName == VK_KHR_RAY_QUERY_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_RAY_QUERY_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME && g_displayStatsCVar > 1)
+			else if(extensionName == VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME && g_cvarCoreDisplayStats > 1)
 			{
 				m_extensions |= VulkanExtensions::kKHR_pipeline_executable_properties;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME && g_debugPrintfCVar)
+			else if(extensionName == VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME && g_cvarGrDebugPrintf)
 			{
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME && g_vrsCVar)
+			else if(extensionName == VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME && g_cvarGrVrs)
 			{
 				m_extensions |= VulkanExtensions::kKHR_fragment_shading_rate;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
@@ -841,7 +841,7 @@ Error GrManagerImpl::initDevice()
 				m_extensions |= VulkanExtensions::kNVX_image_view_handle;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_EXT_MESH_SHADER_EXTENSION_NAME && g_meshShadersCVar)
+			else if(extensionName == VK_EXT_MESH_SHADER_EXTENSION_NAME && g_cvarGrMeshShaders)
 			{
 				m_extensions |= VulkanExtensions::kEXT_mesh_shader;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
@@ -851,7 +851,7 @@ Error GrManagerImpl::initDevice()
 				m_extensions |= VulkanExtensions::kKHR_fragment_shader_barycentric;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
-			else if(extensionName == VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME && g_rayTracingCVar)
+			else if(extensionName == VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME && g_cvarGrRayTracing)
 			{
 				m_extensions |= VulkanExtensions::kKHR_ray_tracing_position_fetch;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
@@ -873,7 +873,7 @@ Error GrManagerImpl::initDevice()
 	{
 		devFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
 		vkGetPhysicalDeviceFeatures2(m_physicalDevice, &devFeatures);
-		devFeatures.features.robustBufferAccess = (g_validationCVar && devFeatures.features.robustBufferAccess) ? true : false;
+		devFeatures.features.robustBufferAccess = (g_cvarGrValidation && devFeatures.features.robustBufferAccess) ? true : false;
 		ANKI_VK_LOGI("Robust buffer access is %s", (devFeatures.features.robustBufferAccess) ? "enabled" : "disabled");
 
 		if(devFeatures.features.pipelineStatisticsQuery)
@@ -920,7 +920,7 @@ Error GrManagerImpl::initDevice()
 		ANKI_ASSERT_SUPPORTED(features12, drawIndirectCount)
 
 		ANKI_ASSERT_SUPPORTED(features12, bufferDeviceAddress)
-		features12.bufferDeviceAddressCaptureReplay = !!features12.bufferDeviceAddressCaptureReplay && g_debugMarkersCVar;
+		features12.bufferDeviceAddressCaptureReplay = !!features12.bufferDeviceAddressCaptureReplay && g_cvarGrDebugMarkers;
 		features12.bufferDeviceAddressMultiDevice = false;
 
 		ANKI_ASSERT_SUPPORTED(features12, shaderFloat16)

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

@@ -402,7 +402,7 @@ void GraphicsPipelineFactory::flushState(GraphicsStateTracker& state, VkCommandB
 Error PipelineCache::init(CString cacheDir)
 {
 	ANKI_ASSERT(cacheDir);
-	m_dumpSize = g_diskShaderCacheMaxSizeCVar;
+	m_dumpSize = g_cvarGrDiskShaderCacheMaxSize;
 	m_dumpFilename.sprintf("%s/VkPipelineCache", cacheDir.cstr());
 
 	// Try read the pipeline cache file.

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

@@ -49,7 +49,7 @@ Bool MicroSemaphore::clientWait(Second seconds)
 {
 	ANKI_ASSERT(m_isTimeline);
 
-	seconds = min<Second>(seconds, g_gpuTimeoutCVar);
+	seconds = min<Second>(seconds, g_cvarGrGpuTimeout);
 
 	VkSemaphoreWaitInfo waitInfo = {};
 	waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;

+ 6 - 7
AnKi/Physics/PhysicsWorld.cpp

@@ -14,10 +14,9 @@
 
 namespace anki {
 
-static StatCounter g_physicsBodiesCreatedStatVar(StatCategory::kMisc, "Phys bodies created", StatFlag::kZeroEveryFrame);
-static StatCounter g_physicsJointsCreatedStatVar(StatCategory::kMisc, "Phys joints created", StatFlag::kZeroEveryFrame);
-static StatCounter g_physicsUpdateTimeStatVar(StatCategory::kTime, "Phys update",
-											  StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(PhysicsBodiesCreated, StatCategory::kMisc, "Phys bodies created", StatFlag::kZeroEveryFrame)
+ANKI_SVAR(PhysicsJointsCreated, StatCategory::kMisc, "Phys joints created", StatFlag::kZeroEveryFrame)
+ANKI_SVAR(PhysicsUpdateTime, StatCategory::kTime, "Phys update", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates)
 
 class BroadphaseLayer
 {
@@ -480,7 +479,7 @@ void PhysicsWorld::update(Second dt)
 	}
 
 #if ANKI_STATS_ENABLED
-	g_physicsUpdateTimeStatVar.set((HighRezTimer::getCurrentTime() - startTime) * 1000.0);
+	g_svarPhysicsUpdateTime.set((HighRezTimer::getCurrentTime() - startTime) * 1000.0);
 #endif
 }
 
@@ -571,7 +570,7 @@ PhysicsCollisionShapePtr PhysicsWorld::newScaleCollisionObject(const Vec3& scale
 
 PhysicsBodyPtr PhysicsWorld::newPhysicsBody(const PhysicsBodyInitInfo& init)
 {
-	g_physicsBodiesCreatedStatVar.increment(1);
+	g_svarPhysicsBodiesCreated.increment(1);
 
 	PhysicsBody* newBody;
 	{
@@ -593,7 +592,7 @@ PhysicsJointPtr PhysicsWorld::newJoint(PhysicsBody* body1, PhysicsBody* body2, T
 {
 	ANKI_ASSERT(body1 && body2);
 
-	g_physicsJointsCreatedStatVar.increment(1);
+	g_svarPhysicsJointsCreated.increment(1);
 
 	typename decltype(m_joints.m_array)::Iterator it;
 	{

+ 5 - 5
AnKi/Renderer/AccelerationStructureBuilder.cpp

@@ -19,14 +19,14 @@ void AccelerationStructureBuilder::populateRenderGraph(RenderingContext& ctx)
 	// Do visibility
 	GpuVisibilityAccelerationStructuresOutput visOut;
 	{
-		const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+		const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 		GpuVisibilityAccelerationStructuresInput in;
 		in.m_passesName = "Main TLAS visiblity";
 		in.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 		in.m_lodDistances = lodDistances;
 		in.m_pointOfTest = in.m_lodReferencePoint;
-		in.m_testRadius = g_rayTracingExtendedFrustumDistanceCVar;
+		in.m_testRadius = g_cvarRenderRtExtendedFrustumDistance;
 		in.m_viewProjectionMatrix = ctx.m_matrices.m_viewProjection;
 		in.m_rgraph = &ctx.m_renderGraphDescr;
 
@@ -69,11 +69,11 @@ void AccelerationStructureBuilder::populateRenderGraph(RenderingContext& ctx)
 	// Light visibility
 	{
 		GpuVisibilityLocalLightsInput in;
-		in.m_cellCounts = UVec3(g_lightGridCellCountXZCVar, g_lightGridCellCountYCVar, g_lightGridCellCountXZCVar);
-		in.m_cellSize = Vec3(g_lightGridSizeXZCVar, g_lightGridSizeYCVar, g_lightGridSizeXZCVar) / Vec3(in.m_cellCounts);
+		in.m_cellCounts = UVec3(g_cvarRenderRtLightGridCellCountXZ, g_cvarRenderRtLightGridCellCountY, g_cvarRenderRtLightGridCellCountXZ);
+		in.m_cellSize = Vec3(g_cvarRenderRtLightGridSizeXZ, g_cvarRenderRtLightGridSizeY, g_cvarRenderRtLightGridSizeXZ) / Vec3(in.m_cellCounts);
 		in.m_cameraPosition = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 		in.m_lookDirection = -ctx.m_matrices.m_cameraTransform.getRotationPart().getZAxis();
-		in.m_lightIndexListSize = g_lightIndexListSizeCVar;
+		in.m_lightIndexListSize = g_cvarRenderRtLightIndexListSize;
 		in.m_rgraph = &ctx.m_renderGraphDescr;
 
 		getGpuVisibilityLocalLights().populateRenderGraph(in, m_runCtx.m_lightVisInfo);

+ 8 - 10
AnKi/Renderer/AccelerationStructureBuilder.h

@@ -12,16 +12,14 @@ namespace anki {
 
 /// @addtogroup renderer
 /// @{
-inline NumericCVar<F32>
-	g_rayTracingExtendedFrustumDistanceCVar("R", "RayTracingExtendedFrustumDistance", 200.0f, 10.0f, 10000.0f,
-											"Every object that its distance from the camera is bellow that value will take part in ray tracing");
-
-inline NumericCVar<U32> g_lightGridCellCountXZCVar("R", "LightGridCellCountXZ", 64, 1, 1024, "The number of cells in the X and Z axis");
-inline NumericCVar<U32> g_lightGridCellCountYCVar("R", "LightGridCellCountY", 4, 1, 1024, "The number of cells in the Y axis");
-inline NumericCVar<F32> g_lightGridSizeXZCVar("R", "LightGridSizeXZ", 128.0f, 10.0f, 10000.0f,
-											  "The size of the grid volume in the X and Z dimensions");
-inline NumericCVar<F32> g_lightGridSizeYCVar("R", "LightGridSizeY", 64.0f, 10.0f, 10000.0f, "The size of the grid in the Y dimension");
-inline NumericCVar<U32> g_lightIndexListSizeCVar("R", "LightIndexListSize", 64 * 1024, 128, 256 * 1024, "The light index list size");
+ANKI_CVAR2(NumericCVar<F32>, Render, Rt, ExtendedFrustumDistance, 200.0f, 10.0f, 10000.0f,
+		   "Every object that its distance from the camera is bellow that value will take part in ray tracing")
+
+ANKI_CVAR2(NumericCVar<U32>, Render, Rt, LightGridCellCountXZ, 64, 1, 1024, "The number of cells in the X and Z axis")
+ANKI_CVAR2(NumericCVar<U32>, Render, Rt, LightGridCellCountY, 4, 1, 1024, "The number of cells in the Y axis")
+ANKI_CVAR2(NumericCVar<F32>, Render, Rt, LightGridSizeXZ, 128.0f, 10.0f, 10000.0f, "The size of the grid volume in the X and Z dimensions")
+ANKI_CVAR2(NumericCVar<F32>, Render, Rt, LightGridSizeY, 64.0f, 10.0f, 10000.0f, "The size of the grid in the Y dimension")
+ANKI_CVAR2(NumericCVar<U32>, Render, Rt, LightIndexListSize, 64 * 1024, 128, 256 * 1024, "The light index list size")
 
 /// @memberof AccelerationStructureBuilder
 class AccelerationStructureVisibilityInfo

+ 8 - 8
AnKi/Renderer/Bloom.cpp

@@ -16,9 +16,9 @@ Error Bloom::init()
 	// Pyramid
 	{
 		const UVec2 pyramidSize = getRenderer().getInternalResolution() / 2;
-		const U8 pyramidMipCount = computeMaxMipmapCount2d(pyramidSize.x(), pyramidSize.y(), g_bloomPyramidLowLimit);
+		const U8 pyramidMipCount = computeMaxMipmapCount2d(pyramidSize.x(), pyramidSize.y(), g_cvarRenderBloomPyramidLowLimit);
 
-		const Bool preferCompute = g_preferComputeCVar;
+		const Bool preferCompute = g_cvarRenderPreferCompute;
 
 		// Create the miped texture
 		TextureInitInfo texinit =
@@ -48,7 +48,7 @@ Error Bloom::init()
 
 	// Upscale
 	{
-		const UVec2 size = getRenderer().getPostProcessResolution() / g_bloomUpscaleDivisor;
+		const UVec2 size = getRenderer().getPostProcessResolution() / g_cvarRenderBloomUpscaleDivisor;
 
 		// Create RT descr
 		m_finalRtDesc = getRenderer().create2DRenderTargetDescription(size.x(), size.y(), getRenderer().getHdrFormat(), "Bloom final");
@@ -73,7 +73,7 @@ void Bloom::importRenderTargets(RenderingContext& ctx)
 void Bloom::populateRenderGraph(RenderingContext& ctx)
 {
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
-	const Bool preferCompute = g_preferComputeCVar;
+	const Bool preferCompute = g_cvarRenderPreferCompute;
 
 	// Pyramid generation
 	{
@@ -136,7 +136,7 @@ void Bloom::populateRenderGraph(RenderingContext& ctx)
 					rgraphCtx.bindSrv(0, 0, getRenderer().getLightShading().getRt());
 				}
 
-				if(g_preferComputeCVar)
+				if(g_cvarRenderPreferCompute)
 				{
 					const Vec4 fbSize(F32(vpWidth), F32(vpHeight), 0.0f, 0.0f);
 					cmdb.setFastConstants(&fbSize, sizeof(fbSize));
@@ -198,10 +198,10 @@ void Bloom::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, m_runCtx.m_pyramidRt, inputTexSubresource);
 			rgraphCtx.bindUav(0, 0, getRenderer().getTonemapping().getExposureAndAvgLuminanceRt());
 
-			const Vec4 consts(g_bloomThresholdCVar, g_bloomScaleCVar, 0.0f, 0.0f);
+			const Vec4 consts(g_cvarRenderBloomThreshold, g_cvarRenderBloomScale, 0.0f, 0.0f);
 			cmdb.setFastConstants(&consts, sizeof(consts));
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(1, 0, exposureRt);
 
@@ -256,7 +256,7 @@ void Bloom::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, exposureRt);
 			cmdb.bindSrv(1, 0, TextureView(&m_lensDirtImg->getTexture(), TextureSubresourceDesc::all()));
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, upscaledRt);
 

+ 4 - 4
AnKi/Renderer/Bloom.h

@@ -12,10 +12,10 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<F32> g_bloomThresholdCVar("R", "BloomThreshold", 2.5f, 0.0f, 256.0f, "Bloom threshold");
-inline NumericCVar<F32> g_bloomScaleCVar("R", "BloomScale", 2.5f, 0.0f, 256.0f, "Bloom scale");
-inline NumericCVar<U32> g_bloomPyramidLowLimit("R", "BloomPyramidLowLimit", 32, 8, 1024, "Downscale the boom pyramid up to that size");
-inline NumericCVar<U32> g_bloomUpscaleDivisor("R", "BloomUpscaleDivisor", 4, 1, 1024, "Defines the resolution of the final bloom result");
+ANKI_CVAR2(NumericCVar<F32>, Render, Bloom, Threshold, 2.5f, 0.0f, 256.0f, "Bloom threshold")
+ANKI_CVAR2(NumericCVar<F32>, Render, Bloom, Scale, 2.5f, 0.0f, 256.0f, "Bloom scale")
+ANKI_CVAR2(NumericCVar<U32>, Render, Bloom, PyramidLowLimit, 32, 8, 1024, "Downscale the boom pyramid up to that size")
+ANKI_CVAR2(NumericCVar<U32>, Render, Bloom, UpscaleDivisor, 4, 1, 1024, "Defines the resolution of the final bloom result")
 
 /// Contains multiple post-process passes that operate on the HDR output.
 class Bloom : public RendererObject

+ 7 - 7
AnKi/Renderer/Dbg.cpp

@@ -143,7 +143,7 @@ void Dbg::drawNonRenderable(GpuSceneNonRenderableObjectType type, U32 objCount,
 void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(Dbg);
-	ANKI_ASSERT(g_dbgSceneCVar || g_dbgPhysicsCVar);
+	ANKI_ASSERT(g_cvarRenderDbgScene || g_cvarRenderDbgPhysics);
 
 	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
@@ -159,7 +159,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	rgraphCtx.bindSrv(0, 0, getGBuffer().getDepthRt());
 
 	// GBuffer renderables
-	if(g_dbgSceneCVar)
+	if(g_cvarRenderDbgScene)
 	{
 		const U32 allAabbCount = GpuSceneArrays::RenderableBoundingVolumeGBuffer::getSingleton().getElementCount();
 
@@ -196,7 +196,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	}
 
 	// Forward shading renderables
-	if(g_dbgSceneCVar)
+	if(g_cvarRenderDbgScene)
 	{
 		const U32 allAabbCount = GpuSceneArrays::RenderableBoundingVolumeForward::getSingleton().getElementCount();
 
@@ -214,7 +214,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	}
 
 	// Draw non-renderables
-	if(g_dbgSceneCVar)
+	if(g_cvarRenderDbgScene)
 	{
 		drawNonRenderable(GpuSceneNonRenderableObjectType::kLight, GpuSceneArrays::Light::getSingleton().getElementCount(), ctx, *m_pointLightImage,
 						  cmdb);
@@ -226,7 +226,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	}
 
 	// Physics
-	if(g_dbgPhysicsCVar)
+	if(g_cvarRenderDbgPhysics)
 	{
 		class MyPhysicsDebugDrawerInterface final : public PhysicsDebugDrawerInterface
 		{
@@ -294,7 +294,7 @@ void Dbg::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(Dbg);
 
-	if(!g_dbgSceneCVar && !g_dbgPhysicsCVar)
+	if(!g_cvarRenderDbgScene && !g_cvarRenderDbgPhysics)
 	{
 		return;
 	}
@@ -321,7 +321,7 @@ void Dbg::populateRenderGraph(RenderingContext& ctx)
 	pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kRtvDsvWrite);
 	pass.newTextureDependency(getGBuffer().getDepthRt(), TextureUsageBit::kSrvPixel | TextureUsageBit::kRtvDsvRead);
 
-	if(g_dbgSceneCVar)
+	if(g_cvarRenderDbgScene)
 	{
 		BufferView indicesBuff;
 		BufferHandle dep;

+ 2 - 2
AnKi/Renderer/Dbg.h

@@ -14,8 +14,8 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_dbgSceneCVar("R", "DbgScene", false, "Enable or not debug visualization of scene");
-inline BoolCVar g_dbgPhysicsCVar("R", "DbgPhysics", false, "Enable or not physics debug visualization");
+ANKI_CVAR2(BoolCVar, Render, Dbg, Scene, false, "Enable or not debug visualization of scene")
+ANKI_CVAR2(BoolCVar, Render, Dbg, Physics, false, "Enable or not physics debug visualization")
 
 /// Debugging stage
 class Dbg : public RendererObject

+ 2 - 2
AnKi/Renderer/DepthDownscale.cpp

@@ -39,7 +39,7 @@ Error DepthDownscale::initInternal()
 
 	m_mipCount = 2;
 
-	const Bool preferCompute = g_preferComputeCVar;
+	const Bool preferCompute = g_cvarRenderPreferCompute;
 
 	// Create RT descr
 	{
@@ -83,7 +83,7 @@ void DepthDownscale::populateRenderGraph(RenderingContext& ctx)
 
 	m_runCtx.m_rt = rgraph.newRenderTarget(m_rtDescr);
 
-	if(g_preferComputeCVar)
+	if(g_cvarRenderPreferCompute)
 	{
 		// Do it with compute
 

+ 14 - 11
AnKi/Renderer/FinalComposite.cpp

@@ -40,10 +40,12 @@ Error FinalComposite::initInternal()
 	// Progs
 	for(MutatorValue dbg = 0; dbg < 2; ++dbg)
 	{
-		ANKI_CHECK(loadShaderProgram(
-			"ShaderBinaries/FinalComposite.ankiprogbin",
-			{{"FILM_GRAIN", (g_filmGrainCVar > 0.0) ? 1 : 0}, {"BLOOM", 1}, {"DBG", dbg}, {"SHARPEN", MutatorValue(g_sharpnessCVar > 0.0)}}, m_prog,
-			m_grProgs[dbg]));
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/FinalComposite.ankiprogbin",
+									 {{"FILM_GRAIN", (g_cvarRenderFilmGrain > 0.0) ? 1 : 0},
+									  {"BLOOM", 1},
+									  {"DBG", dbg},
+									  {"SHARPEN", MutatorValue(g_cvarRenderSharpness > 0.0)}},
+									 m_prog, m_grProgs[dbg]));
 	}
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VisualizeRenderTarget.ankiprogbin", m_defaultVisualizeRenderTargetProg,
@@ -106,12 +108,13 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 
 	pass.newTextureDependency(outRt, TextureUsageBit::kRtvDsvWrite);
 
-	if(g_dbgSceneCVar || g_dbgPhysicsCVar)
+	if(g_cvarRenderDbgScene || g_cvarRenderDbgPhysics)
 	{
 		pass.newTextureDependency(getRenderer().getDbg().getRt(), TextureUsageBit::kSrvPixel);
 	}
 
-	pass.newTextureDependency((g_motionBlurSampleCountCVar != 0) ? getRenderer().getMotionBlur().getRt() : getRenderer().getTonemapping().getRt(),
+	pass.newTextureDependency((g_cvarRenderMotionBlurSampleCount != 0) ? getRenderer().getMotionBlur().getRt()
+																	   : getRenderer().getTonemapping().getRt(),
 							  TextureUsageBit::kSrvPixel);
 	pass.newTextureDependency(getRenderer().getBloom().getBloomRt(), TextureUsageBit::kSrvPixel);
 
@@ -133,7 +136,7 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		ANKI_TRACE_SCOPED_EVENT(FinalComposite);
 
 		CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-		const Bool dbgEnabled = g_dbgSceneCVar || g_dbgPhysicsCVar;
+		const Bool dbgEnabled = g_cvarRenderDbgScene || g_cvarRenderDbgPhysics;
 
 		Array<RenderTargetHandle, kMaxDebugRenderTargets> dbgRts;
 		ShaderProgramPtr optionalDebugProgram;
@@ -158,8 +161,8 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		{
 			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
 
-			rgraphCtx.bindSrv(0, 0,
-							  (g_motionBlurSampleCountCVar != 0) ? getRenderer().getMotionBlur().getRt() : getRenderer().getTonemapping().getRt());
+			rgraphCtx.bindSrv(
+				0, 0, (g_cvarRenderMotionBlurSampleCount != 0) ? getRenderer().getMotionBlur().getRt() : getRenderer().getTonemapping().getRt());
 
 			rgraphCtx.bindSrv(1, 0, getRenderer().getBloom().getBloomRt());
 
@@ -178,12 +181,12 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 				U32 m_padding2;
 			} consts;
 
-			F32 sharpness = g_sharpnessCVar; // [0, 1]
+			F32 sharpness = g_cvarRenderSharpness; // [0, 1]
 			sharpness *= 3.0f; // [0, 3]
 			sharpness = 3.0f - sharpness; // [3, 0], RCAS translates 0 to max sharpness
 			FsrRcasCon(&consts.m_fsrConsts0[0], sharpness);
 
-			consts.m_filmGrainStrength = g_filmGrainCVar;
+			consts.m_filmGrainStrength = g_cvarRenderFilmGrain;
 			consts.m_frameCount = getRenderer().getFrameCount() & kMaxU32;
 
 			cmdb.setFastConstants(&consts, sizeof(consts));

+ 2 - 2
AnKi/Renderer/FinalComposite.h

@@ -13,8 +13,8 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<F32> g_filmGrainCVar("R", "FilmGrain", 16.0f, 0.0f, 250.0f, "Film grain strength");
-inline NumericCVar<F32> g_sharpnessCVar("R", "Sharpness", (ANKI_PLATFORM_MOBILE) ? 0.0f : 1.0f, 0.0f, 1.0f, "Sharpen the image. It's a factor");
+ANKI_CVAR(NumericCVar<F32>, Render, FilmGrain, 16.0f, 0.0f, 250.0f, "Film grain strength")
+ANKI_CVAR(NumericCVar<F32>, Render, Sharpness, (ANKI_PLATFORM_MOBILE) ? 0.0f : 1.0f, 0.0f, 1.0f, "Sharpen the image. It's a factor")
 
 /// Post-processing stage.
 class FinalComposite : public RendererObject

+ 2 - 2
AnKi/Renderer/ForwardShading.cpp

@@ -27,7 +27,7 @@ void ForwardShading::populateRenderGraph(RenderingContext& ctx)
 	m_runCtx = {};
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
 
-	const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+	const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 	FrustumGpuVisibilityInput visIn;
 	visIn.m_passesName = "FW shading";
@@ -36,7 +36,7 @@ void ForwardShading::populateRenderGraph(RenderingContext& ctx)
 	visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 	visIn.m_lodDistances = lodDistances;
 	visIn.m_rgraph = &rgraph;
-	visIn.m_gatherAabbIndices = g_dbgSceneCVar;
+	visIn.m_gatherAabbIndices = g_cvarRenderDbgScene;
 	RenderTargetHandle hzb = getGBuffer().getHzbRt();
 	visIn.m_hzbRt = &hzb;
 	visIn.m_viewportSize = getRenderer().getInternalResolution();

+ 4 - 4
AnKi/Renderer/GBuffer.cpp

@@ -98,7 +98,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 	FrustumGpuVisibilityInput visIn;
 	{
 		const CommonMatrices& matrices = ctx.m_matrices;
-		const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+		const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 		visIn.m_passesName = "GBuffer";
 		visIn.m_technique = RenderingTechnique::kGBuffer;
@@ -107,7 +107,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 		visIn.m_lodDistances = lodDistances;
 		visIn.m_rgraph = &rgraph;
 		visIn.m_hzbRt = &m_runCtx.m_hzbRt;
-		visIn.m_gatherAabbIndices = g_dbgSceneCVar;
+		visIn.m_gatherAabbIndices = g_cvarRenderDbgScene;
 		visIn.m_viewportSize = getRenderer().getInternalResolution();
 		visIn.m_twoPhaseOcclusionCulling = getRenderer().getMeshletRenderingType() != MeshletRenderingType::kNone;
 
@@ -201,7 +201,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 				};
 
 				// Visualize GI probes
-				if(g_visualizeGiProbesCVar && GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount())
+				if(g_cvarRenderVisualizeGiProbes && GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount())
 				{
 					cmdb.bindShaderProgram(m_visualizeGiProbeGrProg.get());
 					cmdb.bindSrv(0, 0, GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getBufferView());
@@ -223,7 +223,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 				}
 
 				// Visualize refl probes
-				if(g_visualizeReflectionProbesCVar && GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount())
+				if(g_cvarRenderVisualizeReflectionProbes && GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount())
 				{
 					cmdb.bindShaderProgram(m_visualizeReflProbeGrProg.get());
 					cmdb.bindSrv(0, 0, GpuSceneArrays::ReflectionProbe::getSingleton().getBufferView());

+ 2 - 3
AnKi/Renderer/GBuffer.h

@@ -13,9 +13,8 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_gbufferVrsCVar("R", "GBufferVrs", false, "Enable VRS in GBuffer");
-inline BoolCVar g_visualizeGiProbesCVar("R", "VisualizeGiProbes", false, "Visualize GI probes");
-inline BoolCVar g_visualizeReflectionProbesCVar("R", "VisualizeReflProbes", false, "Visualize reflection probes");
+ANKI_CVAR(BoolCVar, Render, VisualizeGiProbes, false, "Visualize GI probes")
+ANKI_CVAR(BoolCVar, Render, VisualizeReflectionProbes, false, "Visualize reflection probes")
 
 /// G buffer stage. It populates the G buffer
 class GBuffer : public RendererObject

+ 3 - 3
AnKi/Renderer/HistoryLength.cpp

@@ -14,7 +14,7 @@ Error HistoryLength::init()
 	for(U32 i = 0; i < 2; ++i)
 	{
 		TextureUsageBit texUsage = TextureUsageBit::kAllSrv;
-		texUsage |= (g_preferComputeCVar) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
+		texUsage |= (g_cvarRenderPreferCompute) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
 
 		const TextureInitInfo init =
 			getRenderer().create2DRenderTargetInitInfo(getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y(),
@@ -53,7 +53,7 @@ void HistoryLength::populateRenderGraph(RenderingContext& ctx)
 	RenderPassBase* pass;
 	TextureUsageBit readTexUsage;
 	TextureUsageBit writeTexUsage;
-	if(g_preferComputeCVar)
+	if(g_cvarRenderPreferCompute)
 	{
 		pass = &rgraph.newNonGraphicsRenderPass("History length");
 		readTexUsage = TextureUsageBit::kSrvCompute;
@@ -89,7 +89,7 @@ void HistoryLength::populateRenderGraph(RenderingContext& ctx)
 
 		cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
 
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			rgraphCtx.bindUav(0, 0, current);
 			dispatchPPCompute(cmdb, 8, 8, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());

+ 2 - 2
AnKi/Renderer/IndirectDiffuse.cpp

@@ -18,7 +18,7 @@ namespace anki {
 
 Error IndirectDiffuse::init()
 {
-	[[maybe_unused]] const Bool bRt = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtIndirectDiffuseCVar;
+	[[maybe_unused]] const Bool bRt = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderRtIndirectDiffuse;
 	ANKI_ASSERT(bRt);
 
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/IndirectDiffuse.ankiprogbin", m_mainProg));
@@ -53,7 +53,7 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(IndirectDiffuse);
 
-	const Bool bRt = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtIndirectDiffuseCVar;
+	const Bool bRt = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderRtIndirectDiffuse;
 
 	if(!bRt)
 	{

+ 1 - 1
AnKi/Renderer/IndirectDiffuse.h

@@ -12,7 +12,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_rtIndirectDiffuseCVar("R", "RtIndirectDiffuse", false, "Enable RT GI");
+ANKI_CVAR2(BoolCVar, Render, Rt, IndirectDiffuse, false, "Enable RT GI")
 
 class IndirectDiffuse : public RendererObject
 {

+ 154 - 27
AnKi/Renderer/IndirectDiffuseClipmaps.cpp

@@ -18,6 +18,133 @@
 
 namespace anki {
 
+class ProbeRange
+{
+public:
+	IVec3 m_begin;
+	IVec3 m_end;
+};
+
+/// Given the clipmap's position of this and the previous frame it splits the clipmap into regions that contain new probes (thus they need a full
+/// update) or regions of probes that need a less frequent update.
+static void findClipmapInUpdateRanges(Vec3 newClipmapMin, Vec3 oldClipmapMin, UVec3 probeCountsi, Array<ProbeRange, 3>& fullUpdateProbeRanges,
+									  U32& fullUpdateProbeRangeCount, ProbeRange& partialUpdateProbeRange)
+{
+	fullUpdateProbeRangeCount = 0;
+
+	const IVec3 probeCounts(probeCountsi);
+
+	const IVec3 delta = IVec3(newClipmapMin - oldClipmapMin) / probeCounts;
+	const IVec3 absDelta = delta.abs();
+
+	if(absDelta.x() >= probeCounts.x() || absDelta.y() >= probeCounts.y() || absDelta.z() >= probeCounts.z())
+	{
+		// No overlap between the old and new clipmap positions, full update
+
+		fullUpdateProbeRanges[fullUpdateProbeRangeCount++] = {IVec3(0), probeCounts};
+	}
+	else
+	{
+		IVec3 partialUpdateProbeRangeBegin(0);
+		IVec3 partialUpdateProbeRangeEnd = probeCounts;
+
+		IVec3 fullUpdateProbeRangeBegin(0);
+		IVec3 fullUpdateProbeRangeEnd(0);
+		if(delta.x() > 0)
+		{
+			// New AABB on the right of old
+			fullUpdateProbeRangeBegin =
+				IVec3(partialUpdateProbeRangeEnd.x() - delta.x(), partialUpdateProbeRangeBegin.y(), partialUpdateProbeRangeBegin.z());
+			fullUpdateProbeRangeEnd = partialUpdateProbeRangeEnd;
+
+			partialUpdateProbeRangeEnd.x() -= delta.x();
+		}
+		else if(delta.x() < 0)
+		{
+			// New AABB on the left of old
+			fullUpdateProbeRangeBegin = partialUpdateProbeRangeBegin;
+			fullUpdateProbeRangeEnd = IVec3(-delta.x(), partialUpdateProbeRangeEnd.y(), partialUpdateProbeRangeEnd.z());
+
+			partialUpdateProbeRangeBegin.x() += -delta.x();
+		}
+
+		if(delta.x() != 0)
+		{
+			fullUpdateProbeRanges[fullUpdateProbeRangeCount++] = {fullUpdateProbeRangeBegin, fullUpdateProbeRangeEnd};
+		}
+
+		fullUpdateProbeRangeBegin = fullUpdateProbeRangeEnd = IVec3(0);
+		if(delta.y() > 0)
+		{
+			// New AABB on the top of old
+			fullUpdateProbeRangeBegin =
+				IVec3(partialUpdateProbeRangeBegin.x(), partialUpdateProbeRangeEnd.y() - delta.y(), partialUpdateProbeRangeBegin.z());
+			fullUpdateProbeRangeEnd = partialUpdateProbeRangeEnd;
+
+			partialUpdateProbeRangeEnd.y() -= delta.y();
+		}
+		else if(delta.y() < 0)
+		{
+			// New AABB at the bottom of old
+			fullUpdateProbeRangeBegin = partialUpdateProbeRangeBegin;
+			fullUpdateProbeRangeEnd = IVec3(partialUpdateProbeRangeEnd.x(), -delta.y(), partialUpdateProbeRangeEnd.z());
+
+			partialUpdateProbeRangeEnd.y() += -delta.y();
+		}
+
+		if(delta.y() != 0)
+		{
+			fullUpdateProbeRanges[fullUpdateProbeRangeCount++] = {fullUpdateProbeRangeBegin, fullUpdateProbeRangeEnd};
+		}
+
+		fullUpdateProbeRangeBegin = fullUpdateProbeRangeEnd = IVec3(0);
+		if(delta.z() > 0)
+		{
+			// New AABB on the front of old
+			fullUpdateProbeRangeBegin =
+				IVec3(partialUpdateProbeRangeBegin.x(), partialUpdateProbeRangeBegin.y(), partialUpdateProbeRangeEnd.z() - delta.z());
+			fullUpdateProbeRangeEnd = partialUpdateProbeRangeEnd;
+
+			partialUpdateProbeRangeEnd.z() -= delta.z();
+		}
+		else if(delta.z() < 0)
+		{
+			// New AABB on the back of old
+			fullUpdateProbeRangeBegin = partialUpdateProbeRangeBegin;
+			fullUpdateProbeRangeEnd = IVec3(partialUpdateProbeRangeEnd.x(), partialUpdateProbeRangeEnd.y(), -delta.z());
+
+			partialUpdateProbeRangeEnd.z() += -delta.z();
+		}
+
+		if(delta.z() != 0)
+		{
+			fullUpdateProbeRanges[fullUpdateProbeRangeCount++] = {fullUpdateProbeRangeBegin, fullUpdateProbeRangeEnd};
+		}
+
+		partialUpdateProbeRange = {partialUpdateProbeRangeBegin, partialUpdateProbeRangeEnd};
+
+		// Validation
+		[[maybe_unused]] IVec3 totalProbeCount(0);
+		for(U32 i = 0; i < fullUpdateProbeRangeCount; ++i)
+		{
+			const IVec3 end = fullUpdateProbeRanges[i].m_end;
+			const IVec3 begin = fullUpdateProbeRanges[i].m_begin;
+			const IVec3 diff = end - begin;
+			ANKI_ASSERT(diff.x() * diff.y() * diff.z() > 0);
+			totalProbeCount += diff;
+		}
+
+		{
+			const IVec3 end = partialUpdateProbeRange.m_end;
+			const IVec3 begin = partialUpdateProbeRange.m_begin;
+			const IVec3 diff = end - begin;
+			ANKI_ASSERT(diff.x() * diff.y() * diff.z() > 0);
+			totalProbeCount += diff;
+		}
+		ANKI_ASSERT(totalProbeCount == probeCounts);
+	}
+}
+
 static void computeClipmapBounds(Vec3 cameraPos, Vec3 lookDir, U32 clipmapIdx, IndirectDiffuseClipmapConstants& consts)
 {
 	const Vec3 offset = lookDir * kIndirectDiffuseClipmapForwardBias * F32(clipmapIdx + 1);
@@ -35,11 +162,11 @@ Error IndirectDiffuseClipmaps::init()
 {
 	ANKI_CHECK(RtMaterialFetchRendererObject::init());
 
-	const Bool firstBounceUsesRt = g_indirectDiffuseClipmapFirstBounceRayDistance > 0.0f;
+	const Bool firstBounceUsesRt = g_cvarRenderIdcFirstBounceRayDistance > 0.0f;
 
-	m_lowRezRtDesc = getRenderer().create2DRenderTargetDescription(
-		getRenderer().getInternalResolution().x() / 2, getRenderer().getInternalResolution().y() / (!g_indirectDiffuseClipmapApplyHighQuality + 1),
-		getRenderer().getHdrFormat(), "IndirectDiffuseClipmap: Apply rez");
+	m_lowRezRtDesc = getRenderer().create2DRenderTargetDescription(getRenderer().getInternalResolution().x() / 2,
+																   getRenderer().getInternalResolution().y() / (!g_cvarRenderIdcApplyHighQuality + 1),
+																   getRenderer().getHdrFormat(), "IndirectDiffuseClipmap: Apply rez");
 	m_lowRezRtDesc.bake();
 
 	m_fullRtDesc = getRenderer().create2DRenderTargetDescription(getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y(),
@@ -58,12 +185,12 @@ Error IndirectDiffuseClipmaps::init()
 		}
 	}
 
-	m_consts.m_probeCounts = UVec3(g_indirectDiffuseClipmapProbesXZCVar, g_indirectDiffuseClipmapProbesYCVar, g_indirectDiffuseClipmapProbesXZCVar);
+	m_consts.m_probeCounts = UVec3(g_cvarRenderIdcProbesXZ, g_cvarRenderIdcProbesY, g_cvarRenderIdcProbesXZ);
 	m_consts.m_totalProbeCount = m_consts.m_probeCounts.x() * m_consts.m_probeCounts.y() * m_consts.m_probeCounts.z();
 
-	m_consts.m_sizes[0] = Vec3(g_indirectDiffuseClipmap0XZSizeCVar, g_indirectDiffuseClipmap0YSizeCVar, g_indirectDiffuseClipmap0XZSizeCVar).xyz0();
-	m_consts.m_sizes[1] = Vec3(g_indirectDiffuseClipmap1XZSizeCVar, g_indirectDiffuseClipmap1YSizeCVar, g_indirectDiffuseClipmap1XZSizeCVar).xyz0();
-	m_consts.m_sizes[2] = Vec3(g_indirectDiffuseClipmap2XZSizeCVar, g_indirectDiffuseClipmap2YSizeCVar, g_indirectDiffuseClipmap2XZSizeCVar).xyz0();
+	m_consts.m_sizes[0] = Vec3(g_cvarRenderIdcClipmap0XZSize, g_cvarRenderIdcClipmap0YSize, g_cvarRenderIdcClipmap0XZSize).xyz0();
+	m_consts.m_sizes[1] = Vec3(g_cvarRenderIdcClipmap1XZSize, g_cvarRenderIdcClipmap1YSize, g_cvarRenderIdcClipmap1XZSize).xyz0();
+	m_consts.m_sizes[2] = Vec3(g_cvarRenderIdcClipmap2XZSize, g_cvarRenderIdcClipmap2YSize, g_cvarRenderIdcClipmap2XZSize).xyz0();
 
 	for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
 	{
@@ -78,7 +205,7 @@ Error IndirectDiffuseClipmaps::init()
 	}
 
 	// Create the RT result texture
-	const U32 raysPerProbePerFrame = square<U32>(g_indirectDiffuseClipmapRadianceOctMapSize);
+	const U32 raysPerProbePerFrame = square<U32>(g_cvarRenderIdcRadianceOctMapSize);
 	m_rtResultRtDesc = getRenderer().create2DRenderTargetDescription(m_consts.m_totalProbeCount, raysPerProbePerFrame * kIndirectDiffuseClipmapCount,
 																	 Format::kR16G16B16A16_Sfloat, "IndirectDiffuseClipmap: RT result");
 	m_rtResultRtDesc.bake();
@@ -86,8 +213,8 @@ Error IndirectDiffuseClipmaps::init()
 	for(U32 clipmap = 0; clipmap < kIndirectDiffuseClipmapCount; ++clipmap)
 	{
 		TextureInitInfo volumeInit = getRenderer().create2DRenderTargetInitInfo(
-			m_consts.m_probeCounts.x() * (g_indirectDiffuseClipmapRadianceOctMapSize + 2),
-			m_consts.m_probeCounts.z() * (g_indirectDiffuseClipmapRadianceOctMapSize + 2), Format::kB10G11R11_Ufloat_Pack32,
+			m_consts.m_probeCounts.x() * (g_cvarRenderIdcRadianceOctMapSize + 2),
+			m_consts.m_probeCounts.z() * (g_cvarRenderIdcRadianceOctMapSize + 2), Format::kB10G11R11_Ufloat_Pack32,
 			TextureUsageBit::kAllShaderResource, generateTempPassName("IndirectDiffuseClipmap: Radiance #%u", clipmap));
 		volumeInit.m_depth = m_consts.m_probeCounts.y();
 		volumeInit.m_type = TextureType::k3D;
@@ -98,8 +225,8 @@ Error IndirectDiffuseClipmaps::init()
 	for(U32 clipmap = 0; clipmap < kIndirectDiffuseClipmapCount; ++clipmap)
 	{
 		TextureInitInfo volumeInit = getRenderer().create2DRenderTargetInitInfo(
-			m_consts.m_probeCounts.x() * (g_indirectDiffuseClipmapIrradianceOctMapSize + 2),
-			m_consts.m_probeCounts.z() * (g_indirectDiffuseClipmapIrradianceOctMapSize + 2), Format::kB10G11R11_Ufloat_Pack32,
+			m_consts.m_probeCounts.x() * (g_cvarRenderIdcIrradianceOctMapSize + 2),
+			m_consts.m_probeCounts.z() * (g_cvarRenderIdcIrradianceOctMapSize + 2), Format::kB10G11R11_Ufloat_Pack32,
 			TextureUsageBit::kAllShaderResource, generateTempPassName("IndirectDiffuseClipmap: Irradiance #%u", clipmap));
 		volumeInit.m_depth = m_consts.m_probeCounts.y();
 		volumeInit.m_type = TextureType::k3D;
@@ -110,9 +237,9 @@ Error IndirectDiffuseClipmaps::init()
 	for(U32 clipmap = 0; clipmap < kIndirectDiffuseClipmapCount; ++clipmap)
 	{
 		TextureInitInfo volumeInit = getRenderer().create2DRenderTargetInitInfo(
-			m_consts.m_probeCounts.x() * (g_indirectDiffuseClipmapRadianceOctMapSize + 2),
-			m_consts.m_probeCounts.z() * (g_indirectDiffuseClipmapRadianceOctMapSize + 2), Format::kR16G16_Sfloat,
-			TextureUsageBit::kAllShaderResource, generateTempPassName("IndirectDiffuseClipmap: Dist moments #%u", clipmap));
+			m_consts.m_probeCounts.x() * (g_cvarRenderIdcRadianceOctMapSize + 2),
+			m_consts.m_probeCounts.z() * (g_cvarRenderIdcRadianceOctMapSize + 2), Format::kR16G16_Sfloat, TextureUsageBit::kAllShaderResource,
+			generateTempPassName("IndirectDiffuseClipmap: Dist moments #%u", clipmap));
 		volumeInit.m_depth = m_consts.m_probeCounts.y();
 		volumeInit.m_type = TextureType::k3D;
 
@@ -131,10 +258,10 @@ Error IndirectDiffuseClipmaps::init()
 	}
 
 	const Array<SubMutation, 5> mutation = {{{"GPU_WAVE_SIZE", MutatorValue(GrManager::getSingleton().getDeviceCapabilities().m_maxWaveSize)},
-											 {"RADIANCE_OCTAHEDRON_MAP_SIZE", MutatorValue(g_indirectDiffuseClipmapRadianceOctMapSize)},
-											 {"IRRADIANCE_OCTAHEDRON_MAP_SIZE", MutatorValue(g_indirectDiffuseClipmapIrradianceOctMapSize)},
+											 {"RADIANCE_OCTAHEDRON_MAP_SIZE", MutatorValue(g_cvarRenderIdcRadianceOctMapSize)},
+											 {"IRRADIANCE_OCTAHEDRON_MAP_SIZE", MutatorValue(g_cvarRenderIdcIrradianceOctMapSize)},
 											 {"RT_MATERIAL_FETCH_CLIPMAP", 0},
-											 {"SPATIAL_RECONSTRUCT_TYPE", !g_indirectDiffuseClipmapApplyHighQuality}}};
+											 {"SPATIAL_RECONSTRUCT_TYPE", !g_cvarRenderIdcApplyHighQuality}}};
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/IndirectDiffuseClipmaps.ankiprogbin", mutation, m_prog, m_applyGiGrProg, "Apply"));
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/IndirectDiffuseClipmaps.ankiprogbin", mutation, m_prog, m_visProbesGrProg, "VisualizeProbes"));
@@ -203,7 +330,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(IndirectDiffuse);
 
-	const Bool firstBounceUsesRt = g_indirectDiffuseClipmapFirstBounceRayDistance > 0.0f;
+	const Bool firstBounceUsesRt = g_cvarRenderIdcFirstBounceRayDistance > 0.0f;
 
 	for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
 	{
@@ -304,11 +431,11 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 
 			rgraphCtx.bindUav(0, 2, rtResultHandle);
 
-			const U32 raysPerProbePerFrame = square<U32>(g_indirectDiffuseClipmapRadianceOctMapSize);
+			const U32 raysPerProbePerFrame = square<U32>(g_cvarRenderIdcRadianceOctMapSize);
 
 			for(U32 clipmap = 0; clipmap < kIndirectDiffuseClipmapCount; ++clipmap)
 			{
-				const UVec4 consts(clipmap, g_indirectDiffuseClipmapRadianceOctMapSize, 0, 0);
+				const UVec4 consts(clipmap, g_cvarRenderIdcRadianceOctMapSize, 0, 0);
 				cmdb.setFastConstants(&consts, sizeof(consts));
 
 				cmdb.dispatchRays(sbtBuffer, m_sbtRecordSize, GpuSceneArrays::RenderableBoundingVolumeRt::getSingleton().getElementCount(), 1,
@@ -347,7 +474,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 				const UVec4 consts(clipmap);
 				cmdb.setFastConstants(&consts, sizeof(consts));
 
-				const U32 raysPerProbePerFrame = square<U32>(g_indirectDiffuseClipmapRadianceOctMapSize);
+				const U32 raysPerProbePerFrame = square<U32>(g_cvarRenderIdcRadianceOctMapSize);
 				const U32 threadCount = 64;
 				cmdb.dispatchCompute((raysPerProbePerFrame * m_consts.m_totalProbeCount + threadCount - 1) / threadCount, 1, 1);
 			}
@@ -430,12 +557,12 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 			bindRgenSpace2Resources(ctx, rgraphCtx);
 			rgraphCtx.bindUav(0, 2, lowRezRt);
 
-			const Vec4 consts(g_indirectDiffuseClipmapFirstBounceRayDistance);
+			const Vec4 consts(g_cvarRenderIdcFirstBounceRayDistance);
 			cmdb.setFastConstants(&consts, sizeof(consts));
 
 			cmdb.dispatchRays(sbtBuffer, m_sbtRecordSize, GpuSceneArrays::RenderableBoundingVolumeRt::getSingleton().getElementCount(), 1,
 							  getRenderer().getInternalResolution().x() / 2,
-							  getRenderer().getInternalResolution().y() / (!g_indirectDiffuseClipmapApplyHighQuality + 1), 1);
+							  getRenderer().getInternalResolution().y() / (!g_cvarRenderIdcApplyHighQuality + 1), 1);
 		});
 	}
 	else
@@ -469,7 +596,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
 
 			dispatchPPCompute(cmdb, 8, 8, getRenderer().getInternalResolution().x() / 2,
-							  getRenderer().getInternalResolution().y() / (!g_indirectDiffuseClipmapApplyHighQuality + 1));
+							  getRenderer().getInternalResolution().y() / (!g_cvarRenderIdcApplyHighQuality + 1));
 		});
 	}
 
@@ -491,7 +618,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindUav(0, 0, fullRtTmp);
 
 			dispatchPPCompute(cmdb, 8, 8, getRenderer().getInternalResolution().x() / 2,
-							  getRenderer().getInternalResolution().y() / (!g_indirectDiffuseClipmapApplyHighQuality + 1));
+							  getRenderer().getInternalResolution().y() / (!g_cvarRenderIdcApplyHighQuality + 1));
 		});
 	}
 

+ 29 - 37
AnKi/Renderer/IndirectDiffuseClipmaps.h

@@ -14,7 +14,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_rtIndirectDiffuseClipmapsCVar("R", "RtIndirectDiffuseClipmaps", false);
+ANKI_CVAR(BoolCVar, Render, Idc, false, "Enable ray traced indirect diffuse clipmaps")
 
 constexpr U32 kDefaultClipmapProbeCountXZ = 32;
 constexpr U32 kDefaultClipmapProbeCountY = 12;
@@ -22,45 +22,37 @@ constexpr F32 kDefaultClipmap0ProbeSize = 1.5f;
 constexpr F32 kDefaultClipmap1ProbeSize = 3.0f;
 constexpr F32 kDefaultClipmap2ProbeSize = 6.0f;
 
-inline NumericCVar<U32> g_indirectDiffuseClipmapProbesXZCVar("R", "IndirectDiffuseClipmapProbesXZ", kDefaultClipmapProbeCountXZ, 10, 100,
-															 "The cell count of each dimension of 1st clipmap");
-inline NumericCVar<U32> g_indirectDiffuseClipmapProbesYCVar("R", "IndirectDiffuseClipmapProbesY", kDefaultClipmapProbeCountY, 4, 100,
-															"The cell count of each dimension of 1st clipmap");
-
-inline NumericCVar<F32> g_indirectDiffuseClipmap0XZSizeCVar("R", "IndirectDiffuseClipmap0XZSize",
-															F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap0ProbeSize, 10.0, 1000.0,
-															"The clipmap size in meters");
-inline NumericCVar<F32> g_indirectDiffuseClipmap0YSizeCVar("R", "IndirectDiffuseClipmap0YSize",
-														   F32(kDefaultClipmapProbeCountY) * kDefaultClipmap0ProbeSize, 10.0, 1000.0,
-														   "The clipmap size in meters");
-
-inline NumericCVar<F32> g_indirectDiffuseClipmap1XZSizeCVar("R", "IndirectDiffuseClipmap1XZSize",
-															F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap1ProbeSize, 10.0, 1000.0,
-															"The clipmap size in meters");
-inline NumericCVar<F32> g_indirectDiffuseClipmap1YSizeCVar("R", "IndirectDiffuseClipmap1YSize",
-														   F32(kDefaultClipmapProbeCountY) * kDefaultClipmap1ProbeSize, 10.0, 1000.0,
-														   "The clipmap size in meters");
-
-inline NumericCVar<F32> g_indirectDiffuseClipmap2XZSizeCVar("R", "IndirectDiffuseClipmap2XZSize",
-															F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap2ProbeSize, 10.0, 1000.0,
-															"The clipmap size in meters");
-inline NumericCVar<F32> g_indirectDiffuseClipmap2YSizeCVar("R", "IndirectDiffuseClipmap2YSize",
-														   F32(kDefaultClipmapProbeCountY) * kDefaultClipmap2ProbeSize, 10.0, 1000.0,
-														   "The clipmap size in meters");
-
-inline NumericCVar<U32> g_indirectDiffuseClipmapRadianceOctMapSize(
-	"R", "IndirectDiffuseClipmapRadianceOctMapSize", 10,
+ANKI_CVAR2(NumericCVar<U32>, Render, Idc, ProbesXZ, kDefaultClipmapProbeCountXZ, 10, 100, "The cell count of each dimension of 1st clipmap")
+ANKI_CVAR2(NumericCVar<U32>, Render, Idc, ProbesY, kDefaultClipmapProbeCountY, 4, 100, "The cell count of each dimension of 1st clipmap")
+
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap0XZSize, F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap0ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap0YSize, F32(kDefaultClipmapProbeCountY) * kDefaultClipmap0ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap1XZSize, F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap1ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap1YSize, F32(kDefaultClipmapProbeCountY) * kDefaultClipmap1ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap2XZSize, F32(kDefaultClipmapProbeCountXZ) * kDefaultClipmap2ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, Clipmap2YSize, F32(kDefaultClipmapProbeCountY) * kDefaultClipmap2ProbeSize, 10.0, 1000.0,
+		   "The clipmap size in meters")
+
+ANKI_CVAR2(
+	NumericCVar<U32>, Render, Idc, RadianceOctMapSize, 10,
 	[](U32 val) {
 		return val >= 4 && val <= 30 && val % 2 == 0;
 	},
-	"Size of the octahedral for the light cache");
-inline NumericCVar<U32> g_indirectDiffuseClipmapIrradianceOctMapSize("R", "IndirectDiffuseClipmapIrradianceOctMapSize", 5, 4, 20,
-																	 "Size of the octahedral for the irradiance");
-
-inline NumericCVar<F32> g_indirectDiffuseClipmapFirstBounceRayDistance("R", "IndirectDiffuseClipmapFirstBounceRayDistance", 0.0f, 0.0f, 10000.0f,
-																	   "For the 1st bounce shoot rays instead of sampling the clipmaps");
-inline BoolCVar g_indirectDiffuseClipmapApplyHighQuality("R", "IndirectDiffuseClipmapApplyHighQuality", false,
-														 "If true use 1/2 resolution else use 1/4");
+	"Size of the octahedral for the light cache")
+ANKI_CVAR2(NumericCVar<U32>, Render, Idc, IrradianceOctMapSize, 5, 4, 20, "Size of the octahedral for the irradiance")
+
+ANKI_CVAR2(NumericCVar<F32>, Render, Idc, FirstBounceRayDistance, 0.0f, 0.0f, 10000.0f,
+		   "For the 1st bounce shoot rays instead of sampling the clipmaps")
+ANKI_CVAR2(BoolCVar, Render, Idc, ApplyHighQuality, false, "If true use 1/2 resolution else use 1/4")
+ANKI_CVAR2(NumericCVar<U8>, Render, Idc, TexelRayCountNewProbe, 4, 1, 16,
+		   "The number of rays for a single texel of the oct map that will be cast for probes that are seen for the 1st time")
 
 /// @memberof IndirectDiffuseClipmaps
 class IndirectDiffuseClipmapsRenderTargetHandles

+ 8 - 8
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -20,8 +20,8 @@
 
 namespace anki {
 
-static StatCounter g_giProbeRenderCountStatVar(StatCategory::kRenderer, "GI probes rendered", StatFlag::kMainThreadUpdates);
-static StatCounter g_giProbeCellsRenderCountStatVar(StatCategory::kRenderer, "GI probes cells rendered", StatFlag::kMainThreadUpdates);
+ANKI_SVAR(GiProbeRenderCount, StatCategory::kRenderer, "GI probes rendered", StatFlag::kMainThreadUpdates)
+ANKI_SVAR(GiProbeCellsRenderCount, StatCategory::kRenderer, "GI probes cells rendered", StatFlag::kMainThreadUpdates)
 
 static Vec3 computeCellCenter(U32 cellIdx, const GlobalIlluminationProbeComponent& probe)
 {
@@ -50,7 +50,7 @@ Error IndirectDiffuseProbes::init()
 
 Error IndirectDiffuseProbes::initInternal()
 {
-	m_tileSize = g_indirectDiffuseProbeTileResolutionCVar;
+	m_tileSize = g_cvarRenderIdpTileResolution;
 
 	ANKI_CHECK(initGBuffer());
 	ANKI_CHECK(initLightShading());
@@ -90,7 +90,7 @@ Error IndirectDiffuseProbes::initGBuffer()
 
 Error IndirectDiffuseProbes::initShadowMapping()
 {
-	const U32 resolution = g_indirectDiffuseProbeShadowMapResolutionCVar;
+	const U32 resolution = g_cvarRenderIdpShadowMapResolution;
 	ANKI_ASSERT(resolution > 8);
 
 	// RT descr
@@ -161,7 +161,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 	const Bool probeTouchedFirstTime = probeToRefresh->getNextCellForRefresh() == 0;
 	if(probeTouchedFirstTime)
 	{
-		g_giProbeRenderCountStatVar.increment(1);
+		g_svarGiProbeRenderCount.increment(1);
 	}
 
 	RenderGraphBuilder& rgraph = rctx.m_renderGraphDescr;
@@ -199,7 +199,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 					Transform(cellCenter.xyz0(), Frustum::getOmnidirectionalFrustumRotations()[f], Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
 				frustum.update();
 
-				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+				Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 				FrustumGpuVisibilityInput visIn;
 				visIn.m_passesName = generateTempPassName("GI: GBuffer cell:%u face:%u", cellIdx, f);
@@ -277,7 +277,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 				cascadeViewProjMat = cascadeProjMat * Mat4(cascadeViewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
 
-				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+				Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 				FrustumGpuVisibilityInput visIn;
 				visIn.m_passesName = generateTempPassName("GI: Shadows cell:%u face:%u", cellIdx, f);
@@ -477,7 +477,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 		}
 
 		probeToRefresh->incrementRefreshedCells(1);
-		g_giProbeCellsRenderCountStatVar.increment(1);
+		g_svarGiProbeCellsRenderCount.increment(1);
 	}
 }
 

+ 2 - 4
AnKi/Renderer/IndirectDiffuseProbes.h

@@ -14,10 +14,8 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_indirectDiffuseProbeTileResolutionCVar("R", "IndirectDiffuseProbeTileResolution", (ANKI_PLATFORM_MOBILE) ? 16 : 32, 8, 32,
-																 "GI tile resolution");
-inline NumericCVar<U32> g_indirectDiffuseProbeShadowMapResolutionCVar("R", "IndirectDiffuseProbeShadowMapResolution", 128, 4, 2048,
-																	  "GI shadowmap resolution");
+ANKI_CVAR2(NumericCVar<U32>, Render, Idp, TileResolution, (ANKI_PLATFORM_MOBILE) ? 16 : 32, 8, 32, "GI tile resolution")
+ANKI_CVAR2(NumericCVar<U32>, Render, Idp, ShadowMapResolution, 128, 4, 2048, "GI shadowmap resolution")
 
 /// Ambient global illumination passes.
 ///

+ 1 - 1
AnKi/Renderer/LensFlare.cpp

@@ -27,7 +27,7 @@ Error LensFlare::init()
 
 Error LensFlare::initInternal()
 {
-	m_maxSpritesPerFlare = g_lensFlareMaxSpritesPerFlareCVar;
+	m_maxSpritesPerFlare = g_cvarRenderLensFlareMaxSpritesPerFlare;
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/LensFlareSprite.ankiprogbin", m_realProg, m_realGrProg));
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/LensFlareUpdateIndirectInfo.ankiprogbin", m_updateIndirectBuffProg, m_updateIndirectBuffGrProg));

+ 1 - 2
AnKi/Renderer/LensFlare.h

@@ -14,8 +14,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U8> g_lensFlareMaxSpritesPerFlareCVar("R", "LensFlareMaxSpritesPerFlare", 8, 4, 255, "Max sprites per lens flare");
-inline NumericCVar<U8> g_lensFlareMaxFlaresCVar("R", "LensFlareMaxFlares", 16, 8, 255, "Max flare count");
+ANKI_CVAR2(NumericCVar<U8>, Render, LensFlare, MaxSpritesPerFlare, 8, 4, 255, "Max sprites per lens flare")
 
 /// Lens flare rendering pass. Part of forward shading.
 class LensFlare : public RendererObject

+ 3 - 3
AnKi/Renderer/LightShading.cpp

@@ -70,7 +70,7 @@ void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgrap
 
 	cmdb.setViewport(0, 0, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());
 
-	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar;
+	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_cvarGrVrs;
 	if(enableVrs)
 	{
 		// Just set some low value, the attachment will take over
@@ -221,7 +221,7 @@ void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgrap
 	}
 
 	// Debug stuff
-	if(g_visualizeGiProbesCVar && getRenderer().isIndirectDiffuseClipmapsEnabled())
+	if(g_cvarRenderVisualizeGiProbes && getRenderer().isIndirectDiffuseClipmapsEnabled())
 	{
 		getIndirectDiffuseClipmaps().drawDebugProbes(ctx, rgraphCtx);
 	}
@@ -252,7 +252,7 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 	ANKI_TRACE_SCOPED_EVENT(LightShading);
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
 
-	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar;
+	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_cvarGrVrs;
 
 	// Create RT
 	m_runCtx.m_rt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);

+ 21 - 16
AnKi/Renderer/MotionBlur.cpp

@@ -14,17 +14,20 @@ namespace anki {
 
 Error MotionBlur::init()
 {
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
-								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
-								 m_prog, m_maxVelocityGrProg, "MaxTileVelocity"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
-								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
-								 m_prog, m_maxNeightbourVelocityGrProg, "MaxNeighbourTileVelocity"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MotionBlur.ankiprogbin",
-								 {{"TILE_SIZE", MutatorValue(g_motionBlurTileSizeCVar)}, {"SAMPLE_COUNT", MutatorValue(g_motionBlurSampleCountCVar)}},
-								 m_prog, m_reconstructGrProg, "Reconstruct"));
-
-	const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+	ANKI_CHECK(loadShaderProgram(
+		"ShaderBinaries/MotionBlur.ankiprogbin",
+		{{"TILE_SIZE", MutatorValue(g_cvarRenderMotionBlurTileSize)}, {"SAMPLE_COUNT", MutatorValue(g_cvarRenderMotionBlurSampleCount)}}, m_prog,
+		m_maxVelocityGrProg, "MaxTileVelocity"));
+	ANKI_CHECK(loadShaderProgram(
+		"ShaderBinaries/MotionBlur.ankiprogbin",
+		{{"TILE_SIZE", MutatorValue(g_cvarRenderMotionBlurTileSize)}, {"SAMPLE_COUNT", MutatorValue(g_cvarRenderMotionBlurSampleCount)}}, m_prog,
+		m_maxNeightbourVelocityGrProg, "MaxNeighbourTileVelocity"));
+	ANKI_CHECK(loadShaderProgram(
+		"ShaderBinaries/MotionBlur.ankiprogbin",
+		{{"TILE_SIZE", MutatorValue(g_cvarRenderMotionBlurTileSize)}, {"SAMPLE_COUNT", MutatorValue(g_cvarRenderMotionBlurSampleCount)}}, m_prog,
+		m_reconstructGrProg, "Reconstruct"));
+
+	const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_cvarRenderMotionBlurTileSize - 1) / g_cvarRenderMotionBlurTileSize;
 	m_maxVelocityRtDesc =
 		getRenderer().create2DRenderTargetDescription(tiledTexSize.x(), tiledTexSize.y(), Format::kR16G16_Sfloat, "MaxTileVelocity");
 	m_maxVelocityRtDesc.bake();
@@ -45,7 +48,7 @@ Error MotionBlur::init()
 void MotionBlur::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(MotionBlur);
-	if(g_motionBlurSampleCountCVar == 0)
+	if(g_cvarRenderMotionBlurSampleCount == 0)
 	{
 		m_runCtx.m_rt = {};
 		return;
@@ -74,7 +77,8 @@ void MotionBlur::populateRenderGraph(RenderingContext& ctx)
 			const Vec4 consts(Vec2(getRenderer().getPostProcessResolution()), 0.0f, 0.0f);
 			cmdb.setFastConstants(&consts, sizeof(consts));
 
-			const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+			const UVec2 tiledTexSize =
+				(getRenderer().getPostProcessResolution() + g_cvarRenderMotionBlurTileSize - 1) / g_cvarRenderMotionBlurTileSize;
 			cmdb.dispatchCompute(tiledTexSize.x(), tiledTexSize.y(), 1);
 		});
 	}
@@ -96,7 +100,8 @@ void MotionBlur::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, maxVelRt);
 			rgraphCtx.bindUav(0, 0, maxNeighbourVelRt);
 
-			const UVec2 tiledTexSize = (getRenderer().getPostProcessResolution() + g_motionBlurTileSizeCVar - 1) / g_motionBlurTileSizeCVar;
+			const UVec2 tiledTexSize =
+				(getRenderer().getPostProcessResolution() + g_cvarRenderMotionBlurTileSize - 1) / g_cvarRenderMotionBlurTileSize;
 			cmdb.dispatchCompute(tiledTexSize.x(), tiledTexSize.y(), 1);
 		});
 	}
@@ -107,7 +112,7 @@ void MotionBlur::populateRenderGraph(RenderingContext& ctx)
 
 		TextureUsageBit readUsage, writeUsage;
 		RenderPassBase* ppass;
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Motion blur reconstruct");
 			ppass = &pass;
@@ -155,7 +160,7 @@ void MotionBlur::populateRenderGraph(RenderingContext& ctx)
 			consts.m_far = ctx.m_matrices.m_far;
 			cmdb.setFastConstants(&consts, sizeof(consts));
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, m_runCtx.m_rt);
 				dispatchPPCompute(cmdb, 8, 8, getRenderer().getPostProcessResolution().x(), getRenderer().getPostProcessResolution().y());

+ 2 - 2
AnKi/Renderer/MotionBlur.h

@@ -12,8 +12,8 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_motionBlurTileSizeCVar("R", "MotionBlurTileSize", 32, 8, 64, "Motion blur tile size");
-inline NumericCVar<U32> g_motionBlurSampleCountCVar("R", "MotionBlurSampleCount", 16, 0, 64, "Motion blur sample count");
+ANKI_CVAR2(NumericCVar<U32>, Render, MotionBlur, TileSize, 32, 8, 64, "Motion blur tile size")
+ANKI_CVAR2(NumericCVar<U32>, Render, MotionBlur, SampleCount, 16, 0, 64, "Motion blur sample count")
 
 /// Motion blur.
 class MotionBlur : public RendererObject

+ 3 - 3
AnKi/Renderer/MotionVectors.cpp

@@ -33,7 +33,7 @@ void MotionVectors::populateRenderGraph(RenderingContext& ctx)
 	RenderPassBase* ppass;
 	TextureUsageBit readUsage;
 	TextureUsageBit writeUsage;
-	if(g_preferComputeCVar)
+	if(g_cvarRenderPreferCompute)
 	{
 		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("MotionVectors");
 
@@ -74,12 +74,12 @@ void MotionVectors::populateRenderGraph(RenderingContext& ctx)
 		pc->m_currentInvViewProjMat = ctx.m_matrices.m_invertedViewProjection;
 		pc->m_prevViewProjMat = ctx.m_prevMatrices.m_viewProjection;
 
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			rgraphCtx.bindUav(0, 0, m_runCtx.m_motionVectorsRtHandle);
 		}
 
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			dispatchPPCompute(cmdb, 8, 8, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());
 		}

+ 8 - 8
AnKi/Renderer/ProbeReflections.cpp

@@ -26,13 +26,13 @@
 
 namespace anki {
 
-static StatCounter g_probeReflectionCountStatVar(StatCategory::kRenderer, "Reflection probes rendered", StatFlag::kMainThreadUpdates);
+ANKI_SVAR(ProbeReflectionCount, StatCategory::kRenderer, "Reflection probes rendered", StatFlag::kMainThreadUpdates)
 
 Error ProbeReflections::init()
 {
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/IblDfg.png", m_integrationLut));
 
-	m_gbuffer.m_tileSize = g_reflectionProbeResolutionCVar;
+	m_gbuffer.m_tileSize = g_cvarRenderProbeReflectionsResolution;
 
 	{
 		RenderTargetDesc texinit = getRenderer().create2DRenderTargetDescription(m_gbuffer.m_tileSize, m_gbuffer.m_tileSize,
@@ -56,11 +56,11 @@ Error ProbeReflections::init()
 		m_gbuffer.m_depthRtDescr.bake();
 	}
 
-	m_lightShading.m_tileSize = g_reflectionProbeResolutionCVar;
+	m_lightShading.m_tileSize = g_cvarRenderProbeReflectionsResolution;
 	m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
 
 	{
-		const U32 resolution = g_probeReflectionShadowMapResolutionCVar;
+		const U32 resolution = g_cvarRenderProbeReflectionsShadowMapResolution;
 		ANKI_ASSERT(resolution > 8);
 
 		// RT descr
@@ -78,7 +78,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
 
-	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtReflectionsCVar;
+	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderReflectionsRt;
 	if(bRtReflections)
 	{
 		return;
@@ -105,7 +105,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		return;
 	}
 
-	g_probeReflectionCountStatVar.increment(1);
+	g_svarProbeReflectionCount.increment(1);
 	probeToRefresh->setEnvironmentTextureAsRefreshed();
 
 	RenderGraphBuilder& rgraph = rctx.m_renderGraphDescr;
@@ -136,7 +136,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				Transform(probeToRefresh->getWorldPosition().xyz0(), Frustum::getOmnidirectionalFrustumRotations()[f], Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
 			frustum.update();
 
-			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+			Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 			FrustumGpuVisibilityInput visIn;
 			visIn.m_passesName = generateTempPassName("Cube refl: GBuffer face:%u", f);
@@ -212,7 +212,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 
 			cascadeViewProjMat = cascadeProjMat * Mat4(cascadeViewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
 
-			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+			Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 
 			FrustumGpuVisibilityInput visIn;
 			visIn.m_passesName = generateTempPassName("Cube refl: Shadows face:%u", f);

+ 1 - 4
AnKi/Renderer/ProbeReflections.h

@@ -14,10 +14,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_probeReflectionIrradianceResolutionCVar("R", "ProbeReflectionIrradianceResolution", 16, 4, 2048,
-																  "Reflection probe irradiance resolution");
-inline NumericCVar<U32> g_probeReflectionShadowMapResolutionCVar("R", "ProbeReflectionShadowMapResolution", 64, 4, 2048,
-																 "Reflection probe shadow resolution");
+ANKI_CVAR2(NumericCVar<U32>, Render, ProbeReflections, ShadowMapResolution, 64, 4, 2048, "Reflection probe shadow resolution")
 
 /// Probe reflections.
 class ProbeReflections : public RendererObject

+ 6 - 6
AnKi/Renderer/Reflections.cpp

@@ -28,7 +28,7 @@ Error Reflections::init()
 {
 	ANKI_CHECK(RtMaterialFetchRendererObject::init());
 
-	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtReflectionsCVar;
+	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderReflectionsRt;
 	const Bool bSsrSamplesGBuffer = bRtReflections;
 
 	std::initializer_list<SubMutation> mutation = {{"SSR_SAMPLE_GBUFFER", bSsrSamplesGBuffer},
@@ -136,7 +136,7 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 {
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
 
-	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtReflectionsCVar;
+	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderReflectionsRt;
 
 	// Create or import render targets
 	RenderTargetHandle mainRt;
@@ -165,9 +165,9 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 	const BufferHandle indirectArgsHandle = rgraph.importBuffer(BufferView(m_indirectArgsBuffer.get()), BufferUsageBit::kNone);
 
 	ReflectionConstants consts;
-	consts.m_ssrStepIncrement = g_ssrStepIncrementCVar;
-	consts.m_ssrMaxIterations = g_ssrMaxIterationsCVar;
-	consts.m_roughnessCutoffToGiEdges = Vec2(g_roughnessCutoffToGiEdge0, g_roughnessCutoffToGiEdge1);
+	consts.m_ssrStepIncrement = g_cvarRenderReflectionsSsrStepIncrement;
+	consts.m_ssrMaxIterations = g_cvarRenderReflectionsSsrMaxIterations;
+	consts.m_roughnessCutoffToGiEdges = Vec2(g_cvarRenderReflectionsRoughnessCutoffToGiEdge0, g_cvarRenderReflectionsRoughnessCutoffToGiEdge1);
 
 	// Classification
 	{
@@ -313,7 +313,7 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 				U32 m_giProbeCount;
 				F32 m_padding1;
 				F32 m_padding2;
-			} consts = {g_rtReflectionsMaxRayDistanceCVar, GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount(), 0, 0};
+			} consts = {g_cvarRenderReflectionsRtMaxRayDistance, GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount(), 0, 0};
 
 			cmdb.setFastConstants(&consts, sizeof(consts));
 

+ 9 - 11
AnKi/Renderer/Reflections.h

@@ -12,17 +12,15 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_rtReflectionsCVar("R", "RtReflections", true, "Enable RT reflections");
-inline NumericCVar<F32> g_rtReflectionsMaxRayDistanceCVar("R", "RtReflectionsMaxRayDistance", 100.0f, 1.0f, 10000.0f,
-														  "Max RT reflections ray distance");
-inline NumericCVar<U32> g_ssrStepIncrementCVar("R", "SsrStepIncrement", 32, 1, 256, "The number of steps for each loop");
-inline NumericCVar<U32> g_ssrMaxIterationsCVar("R", "SsrMaxIterations", ANKI_PLATFORM_MOBILE ? 16 : 64, 1, 256,
-											   "Max SSR raymarching loop iterations");
-
-inline NumericCVar<F32> g_roughnessCutoffToGiEdge0("R", "RoughnessCutoffToGiEdge0", 0.7f, 0.0f, 1.0f,
-												   "Before this roughness the reflections will never sample the GI probes");
-inline NumericCVar<F32> g_roughnessCutoffToGiEdge1("R", "RoughnessCutoffToGiEdge1", 0.9f, 0.0f, 1.0f,
-												   "After this roughness the reflections will sample the GI probes");
+ANKI_CVAR2(BoolCVar, Render, Reflections, Rt, true, "Enable RT reflections")
+ANKI_CVAR2(NumericCVar<F32>, Render, Reflections, RtMaxRayDistance, 100.0f, 1.0f, 10000.0f, "Max RT reflections ray distance")
+ANKI_CVAR2(NumericCVar<U32>, Render, Reflections, SsrStepIncrement, 32, 1, 256, "The number of steps for each loop")
+ANKI_CVAR2(NumericCVar<U32>, Render, Reflections, SsrMaxIterations, ANKI_PLATFORM_MOBILE ? 16 : 64, 1, 256, "Max SSR raymarching loop iterations")
+
+ANKI_CVAR2(NumericCVar<F32>, Render, Reflections, RoughnessCutoffToGiEdge0, 0.7f, 0.0f, 1.0f,
+		   "Before this roughness the reflections will never sample the GI probes")
+ANKI_CVAR2(NumericCVar<F32>, Render, Reflections, RoughnessCutoffToGiEdge1, 0.9f, 0.0f, 1.0f,
+		   "After this roughness the reflections will sample the GI probes")
 
 class Reflections : public RtMaterialFetchRendererObject
 {

+ 16 - 17
AnKi/Renderer/Renderer.cpp

@@ -59,9 +59,8 @@
 
 namespace anki {
 
-static StatCounter g_primitivesDrawnStatVar(StatCategory::kRenderer, "Primitives drawn", StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame);
-static StatCounter g_rendererCpuTimeStatVar(StatCategory::kTime, "Renderer",
-											StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(PrimitivesDrawn, StatCategory::kRenderer, "Primitives drawn", StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame)
+ANKI_SVAR(RendererCpuTime, StatCategory::kTime, "Renderer", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates)
 
 /// Generate a Halton jitter in [-0.5, 0.5]
 static Vec2 generateJitter(U32 frame)
@@ -129,11 +128,11 @@ Error Renderer::initInternal(const RendererInitInfo& inf)
 	m_rgraph = GrManager::getSingleton().newRenderGraph();
 
 	// Set from the config
-	m_postProcessResolution = UVec2(Vec2(m_swapchainResolution) * g_renderScalingCVar);
+	m_postProcessResolution = UVec2(Vec2(m_swapchainResolution) * g_cvarRenderRenderScaling);
 	alignRoundDown(2, m_postProcessResolution.x());
 	alignRoundDown(2, m_postProcessResolution.y());
 
-	m_internalResolution = UVec2(Vec2(m_postProcessResolution) * g_internalRenderScalingCVar);
+	m_internalResolution = UVec2(Vec2(m_postProcessResolution) * g_cvarRenderInternalRenderScaling);
 	alignRoundDown(2, m_internalResolution.x());
 	alignRoundDown(2, m_internalResolution.y());
 
@@ -142,9 +141,9 @@ Error Renderer::initInternal(const RendererInitInfo& inf)
 
 	m_tileCounts.x() = (m_internalResolution.x() + kClusteredShadingTileSize - 1) / kClusteredShadingTileSize;
 	m_tileCounts.y() = (m_internalResolution.y() + kClusteredShadingTileSize - 1) / kClusteredShadingTileSize;
-	m_zSplitCount = g_zSplitCountCVar;
+	m_zSplitCount = g_cvarRenderZSplitCount;
 
-	if(g_meshletRenderingCVar && !GrManager::getSingleton().getDeviceCapabilities().m_meshShaders)
+	if(g_cvarCoreMeshletRendering && !GrManager::getSingleton().getDeviceCapabilities().m_meshShaders)
 	{
 		m_meshletRenderingType = MeshletRenderingType::kSoftware;
 	}
@@ -244,14 +243,14 @@ Error Renderer::initInternal(const RendererInitInfo& inf)
 		sinit.m_addressing = SamplingAddressing::kRepeat;
 		m_samplers.m_trilinearRepeat = GrManager::getSingleton().newSampler(sinit);
 
-		if(g_textureAnisotropyCVar <= 1u)
+		if(g_cvarRenderTextureAnisotropy <= 1u)
 		{
 			m_samplers.m_trilinearRepeatAniso = m_samplers.m_trilinearRepeat;
 		}
 		else
 		{
 			sinit.setName("TrilinearRepeatAniso");
-			sinit.m_anisotropyLevel = g_textureAnisotropyCVar;
+			sinit.m_anisotropyLevel = g_cvarRenderTextureAnisotropy;
 			m_samplers.m_trilinearRepeatAniso = GrManager::getSingleton().newSampler(sinit);
 		}
 
@@ -384,7 +383,7 @@ void Renderer::writeGlobalRendererConstants(RenderingContext& ctx, GlobalRendere
 	consts.m_zSplitCountOverFrustumLength = F32(m_zSplitCount) / (ctx.m_matrices.m_far - ctx.m_matrices.m_near);
 	consts.m_zSplitMagic.x() = (ctx.m_matrices.m_near - ctx.m_matrices.m_far) / (ctx.m_matrices.m_near * F32(m_zSplitCount));
 	consts.m_zSplitMagic.y() = ctx.m_matrices.m_far / (ctx.m_matrices.m_near * F32(m_zSplitCount));
-	consts.m_lightVolumeLastZSplit = min(g_volumetricLightingAccumulationFinalZSplitCVar - 1, m_zSplitCount);
+	consts.m_lightVolumeLastZSplit = min(g_cvarRenderVolumetricLightingAccumulationFinalZSplit - 1, m_zSplitCount);
 
 	consts.m_reflectionProbesMipCount = F32(m_probeReflections->getReflectionTextureMipmapCount());
 
@@ -396,15 +395,15 @@ void Renderer::writeGlobalRendererConstants(RenderingContext& ctx, GlobalRendere
 	if(dirLight)
 	{
 		DirectionalLight& out = consts.m_directionalLight;
-		const U32 shadowCascadeCount = (dirLight->getShadowEnabled()) ? g_shadowCascadeCountCVar : 0;
+		const U32 shadowCascadeCount = (dirLight->getShadowEnabled()) ? g_cvarRenderShadowCascadeCount : 0;
 
 		out.m_diffuseColor = dirLight->getDiffuseColor().xyz();
 		out.m_power = dirLight->getLightPower();
 		out.m_shadowCascadeCount = shadowCascadeCount;
 		out.m_active = 1;
 		out.m_direction = dirLight->getDirection();
-		out.m_shadowCascadeDistances =
-			Vec4(g_shadowCascade0DistanceCVar, g_shadowCascade1DistanceCVar, g_shadowCascade2DistanceCVar, g_shadowCascade3DistanceCVar);
+		out.m_shadowCascadeDistances = Vec4(g_cvarRenderShadowCascade0Distance, g_cvarRenderShadowCascade1Distance,
+											g_cvarRenderShadowCascade2Distance, g_cvarRenderShadowCascade3Distance);
 
 		for(U cascade = 0; cascade < shadowCascadeCount; ++cascade)
 		{
@@ -691,7 +690,7 @@ void Renderer::setCurrentDebugRenderTarget(CString rtName)
 Format Renderer::getHdrFormat() const
 {
 	Format out;
-	if(!g_highQualityHdrCVar)
+	if(!g_cvarRenderHighQualityHdr)
 	{
 		out = Format::kB10G11R11_Ufloat_Pack32;
 	}
@@ -759,7 +758,7 @@ void Renderer::updatePipelineStats()
 
 	arr.destroy();
 
-	g_primitivesDrawnStatVar.set(sum);
+	g_svarPrimitivesDrawn.set(sum);
 }
 #endif
 
@@ -885,11 +884,11 @@ Error Renderer::render()
 	// Stats
 	if(ANKI_STATS_ENABLED || ANKI_TRACING_ENABLED)
 	{
-		g_rendererCpuTimeStatVar.set((HighRezTimer::getCurrentTime() - startTime) * 1000.0);
+		g_svarRendererCpuTime.set((HighRezTimer::getCurrentTime() - startTime) * 1000.0);
 
 		RenderGraphStatistics rgraphStats;
 		m_rgraph->getStatistics(rgraphStats);
-		g_rendererGpuTimeStatVar.set(rgraphStats.m_gpuTime * 1000.0);
+		g_svarRendererGpuTime.set(rgraphStats.m_gpuTime * 1000.0);
 
 		if(rgraphStats.m_gpuTime > 0.0)
 		{

+ 19 - 25
AnKi/Renderer/Renderer.h

@@ -15,31 +15,25 @@ namespace anki {
 
 /// @addtogroup renderer
 /// @{
-
-inline NumericCVar<F32> g_internalRenderScalingCVar("R", "InternalRenderScaling", 1.0f, 0.5f, 1.0f,
-													"A factor over the requested swapchain resolution. Applies to all passes up to TAA");
-inline NumericCVar<F32> g_renderScalingCVar("R", "RenderScaling", 1.0f, 0.5f, 8.0f,
-											"A factor over the requested swapchain resolution. Applies to post-processing and UI");
-inline NumericCVar<U32> g_zSplitCountCVar("R", "ZSplitCount", 64, 8, kMaxZsplitCount, "Clusterer number of Z splits");
-inline NumericCVar<U8> g_textureAnisotropyCVar("R", "TextureAnisotropy", (ANKI_PLATFORM_MOBILE) ? 1 : 16, 1, 16,
-											   "Texture anisotropy for the main passes");
-inline BoolCVar g_preferComputeCVar("R", "PreferCompute", !ANKI_PLATFORM_MOBILE, "Prefer compute shaders");
-inline BoolCVar g_highQualityHdrCVar("R", "HighQualityHdr", !ANKI_PLATFORM_MOBILE,
-									 "If true use R16G16B16 for HDR images. Alternatively use B10G11R11");
-inline BoolCVar g_vrsLimitTo2x2CVar("R", "VrsLimitTo2x2", false, "If true the max rate will be 2x2");
-inline NumericCVar<U8> g_shadowCascadeCountCVar("R", "ShadowCascadeCount", (ANKI_PLATFORM_MOBILE) ? 3 : kMaxShadowCascades, 1, kMaxShadowCascades,
-												"Max number of shadow cascades for directional lights");
-inline NumericCVar<F32> g_shadowCascade0DistanceCVar("R", "ShadowCascade0Distance", 18.0, 1.0, kMaxF32, "The distance of the 1st cascade");
-inline NumericCVar<F32> g_shadowCascade1DistanceCVar("R", "ShadowCascade1Distance", (ANKI_PLATFORM_MOBILE) ? 80.0f : 40.0, 1.0, kMaxF32,
-													 "The distance of the 2nd cascade");
-inline NumericCVar<F32> g_shadowCascade2DistanceCVar("R", "ShadowCascade2Distance", (ANKI_PLATFORM_MOBILE) ? 150.0f : 80.0, 1.0, kMaxF32,
-													 "The distance of the 3rd cascade");
-inline NumericCVar<F32> g_shadowCascade3DistanceCVar("R", "ShadowCascade3Distance", 200.0, 1.0, kMaxF32, "The distance of the 4th cascade");
-inline NumericCVar<F32> g_lod0MaxDistanceCVar("R", "Lod0MaxDistance", 20.0f, 1.0f, kMaxF32, "Distance that will be used to calculate the LOD 0");
-inline NumericCVar<F32> g_lod1MaxDistanceCVar("R", "Lod1MaxDistance", 40.0f, 2.0f, kMaxF32, "Distance that will be used to calculate the LOD 1");
-
-inline StatCounter g_rendererGpuTimeStatVar(StatCategory::kTime, "GPU frame",
-											StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+ANKI_CVAR(NumericCVar<F32>, Render, InternalRenderScaling, 1.0f, 0.5f, 1.0f,
+		  "A factor over the requested swapchain resolution. Applies to all passes up to TAA")
+ANKI_CVAR(NumericCVar<F32>, Render, RenderScaling, 1.0f, 0.5f, 8.0f,
+		  "A factor over the requested swapchain resolution. Applies to post-processing and UI")
+ANKI_CVAR(NumericCVar<U32>, Render, ZSplitCount, 64, 8, kMaxZsplitCount, "Clusterer number of Z splits")
+ANKI_CVAR(NumericCVar<U8>, Render, TextureAnisotropy, (ANKI_PLATFORM_MOBILE) ? 1 : 16, 1, 16, "Texture anisotropy for the main passes")
+ANKI_CVAR(BoolCVar, Render, PreferCompute, !ANKI_PLATFORM_MOBILE, "Prefer compute shaders")
+ANKI_CVAR(BoolCVar, Render, HighQualityHdr, !ANKI_PLATFORM_MOBILE, "If true use R16G16B16 for HDR images. Alternatively use B10G11R11")
+ANKI_CVAR(BoolCVar, Render, VrsLimitTo2x2, false, "If true the max rate will be 2x2")
+ANKI_CVAR(NumericCVar<U8>, Render, ShadowCascadeCount, (ANKI_PLATFORM_MOBILE) ? 3 : kMaxShadowCascades, 1, kMaxShadowCascades,
+		  "Max number of shadow cascades for directional lights")
+ANKI_CVAR(NumericCVar<F32>, Render, ShadowCascade0Distance, 18.0, 1.0, kMaxF32, "The distance of the 1st cascade")
+ANKI_CVAR(NumericCVar<F32>, Render, ShadowCascade1Distance, (ANKI_PLATFORM_MOBILE) ? 80.0f : 40.0, 1.0, kMaxF32, "The distance of the 2nd cascade")
+ANKI_CVAR(NumericCVar<F32>, Render, ShadowCascade2Distance, (ANKI_PLATFORM_MOBILE) ? 150.0f : 80.0, 1.0, kMaxF32, "The distance of the 3rd cascade")
+ANKI_CVAR(NumericCVar<F32>, Render, ShadowCascade3Distance, 200.0, 1.0, kMaxF32, "The distance of the 4th cascade")
+ANKI_CVAR(NumericCVar<F32>, Render, Lod0MaxDistance, 20.0f, 1.0f, kMaxF32, "Distance that will be used to calculate the LOD 0")
+ANKI_CVAR(NumericCVar<F32>, Render, Lod1MaxDistance, 40.0f, 2.0f, kMaxF32, "Distance that will be used to calculate the LOD 1")
+
+ANKI_SVAR(RendererGpuTime, StatCategory::kTime, "GPU frame", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates)
 
 /// Renderer statistics.
 class RendererPrecreatedSamplers

+ 1 - 1
AnKi/Renderer/RendererObject.cpp

@@ -62,7 +62,7 @@ Error RendererObject::loadShaderProgram(CString filename, ConstWeakArray<SubMuta
 
 		if(techniqueShaderTypes == (ShaderTypeBit::kCompute | ShaderTypeBit::kPixel | ShaderTypeBit::kVertex))
 		{
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				shaderTypes = ShaderTypeBit::kCompute;
 			}

+ 7 - 7
AnKi/Renderer/RendererObject.def.h

@@ -21,16 +21,16 @@ ANKI_RENDERER_OBJECT_DEF(TemporalAA, temporalAA, 1)
 ANKI_RENDERER_OBJECT_DEF(UiStage, uiStage, 1)
 ANKI_RENDERER_OBJECT_DEF(HistoryLength, historyLength, 1)
 ANKI_RENDERER_OBJECT_DEF(IndirectDiffuseProbes, indirectDiffuseProbes,
-						 !(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtIndirectDiffuseClipmapsCVar))
+						 !(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_cvarRenderIdc))
 ANKI_RENDERER_OBJECT_DEF(IndirectDiffuseClipmaps, indirectDiffuseClipmaps,
-						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_rtIndirectDiffuseClipmapsCVar)
+						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_cvarRenderIdc)
 ANKI_RENDERER_OBJECT_DEF(VolumetricLightingAccumulation, volumetricLightingAccumulation, 1)
-ANKI_RENDERER_OBJECT_DEF(RtShadows, rtShadows, GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_rayTracedShadowsCVar)
+ANKI_RENDERER_OBJECT_DEF(RtShadows, rtShadows, GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_cvarRenderRtShadows)
 ANKI_RENDERER_OBJECT_DEF(ShadowmapsResolve, shadowmapsResolve, 1)
 ANKI_RENDERER_OBJECT_DEF(AccelerationStructureBuilder, accelerationStructureBuilder,
 						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled
-							 && (g_rayTracedShadowsCVar || g_rtMaterialFetchDbgCVar || g_rtReflectionsCVar || g_rtIndirectDiffuseCVar
-								 || g_rtIndirectDiffuseClipmapsCVar))
+							 && (g_cvarRenderRtShadows || g_cvarRenderDbgRtMaterialFetch || g_cvarRenderReflectionsRt || g_cvarRenderRtIndirectDiffuse
+								 || g_cvarRenderIdc))
 ANKI_RENDERER_OBJECT_DEF(LightShading, lightShading, 1)
 ANKI_RENDERER_OBJECT_DEF(MotionVectors, motionVectors, 1)
 ANKI_RENDERER_OBJECT_DEF(TemporalUpscaler, temporalUpscaler, 1)
@@ -41,10 +41,10 @@ ANKI_RENDERER_OBJECT_DEF(Ssao, ssao, 1)
 ANKI_RENDERER_OBJECT_DEF(GeneratedSky, generatedSky, 1)
 ANKI_RENDERER_OBJECT_DEF(MotionBlur, motionBlur, 1)
 ANKI_RENDERER_OBJECT_DEF(RtMaterialFetchDbg, rtMaterialFetchDbg,
-						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_rtMaterialFetchDbgCVar)
+						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_cvarRenderDbgRtMaterialFetch)
 ANKI_RENDERER_OBJECT_DEF(Reflections, reflections, 1)
 ANKI_RENDERER_OBJECT_DEF(IndirectDiffuse, indirectDiffuse,
-						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_rtIndirectDiffuseCVar)
+						 GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled&& g_cvarRenderRtIndirectDiffuse)
 
 // Util objects
 ANKI_RENDERER_OBJECT_DEF(RenderableDrawer, drawer, 1)

+ 1 - 1
AnKi/Renderer/RtMaterialFetchDbg.h

@@ -12,7 +12,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_rtMaterialFetchDbgCVar("R", "RtMaterialFetchDbg", false, "Enable material debugging pass");
+ANKI_CVAR2(BoolCVar, Render, Dbg, RtMaterialFetch, false, "Enable material debugging pass")
 
 /// Similar to ShadowmapsResolve but it's using ray tracing.
 class RtMaterialFetchDbg : public RtMaterialFetchRendererObject

+ 4 - 4
AnKi/Renderer/RtShadows.cpp

@@ -23,8 +23,8 @@ namespace anki {
 
 Error RtShadows::init()
 {
-	m_useSvgf = g_rtShadowsSvgfCVar;
-	m_atrousPassCount = g_rtShadowsSvgfAtrousPassCountCVar;
+	m_useSvgf = g_cvarRenderRtShadowsSvgf;
+	m_atrousPassCount = g_cvarRenderRtShadowsSvgfAtrousPassCount;
 
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_blueNoiseImage));
 
@@ -35,7 +35,7 @@ Error RtShadows::init()
 	// Ray gen and miss
 	{
 		ShaderProgramResourceVariantInitInfo variantInitInfo(m_rayGenAndMissProg);
-		variantInitInfo.addMutation("RAYS_PER_PIXEL", g_rtShadowsRaysPerPixelCVar);
+		variantInitInfo.addMutation("RAYS_PER_PIXEL", g_cvarRenderRtShadowsRaysPerPixel);
 		variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kRayGen, "RtShadows");
 		const ShaderProgramResourceVariant* variant;
 		m_rayGenAndMissProg->getOrCreateVariant(variantInitInfo, variant);
@@ -43,7 +43,7 @@ Error RtShadows::init()
 		m_rayGenShaderGroupIdx = variant->getShaderGroupHandleIndex();
 
 		ShaderProgramResourceVariantInitInfo variantInitInfo2(m_rayGenAndMissProg);
-		variantInitInfo2.addMutation("RAYS_PER_PIXEL", g_rtShadowsRaysPerPixelCVar);
+		variantInitInfo2.addMutation("RAYS_PER_PIXEL", g_cvarRenderRtShadowsRaysPerPixel);
 		variantInitInfo2.requestTechniqueAndTypes(ShaderTypeBit::kMiss, "RtShadows");
 		m_rayGenAndMissProg->getOrCreateVariant(variantInitInfo2, variant);
 		m_missShaderGroupIdx = variant->getShaderGroupHandleIndex();

+ 4 - 4
AnKi/Renderer/RtShadows.h

@@ -15,10 +15,10 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_rtShadowsSvgfCVar("R", "RtShadowsSvgf", false, "Enable or not RT shadows SVGF");
-inline NumericCVar<U8> g_rtShadowsSvgfAtrousPassCountCVar("R", "RtShadowsSvgfAtrousPassCount", 3, 1, 20, "Number of atrous passes of SVGF");
-inline NumericCVar<U32> g_rtShadowsRaysPerPixelCVar("R", "RtShadowsRaysPerPixel", 1, 1, 8, "Number of shadow rays per pixel");
-inline BoolCVar g_rayTracedShadowsCVar("R", "RayTracedShadows", false, "Enable or not ray traced shadows. Ignored if RT is not supported");
+ANKI_CVAR(BoolCVar, Render, RtShadows, false, "Enable or not ray traced shadows. Ignored if RT is not supported")
+ANKI_CVAR2(BoolCVar, Render, RtShadows, Svgf, false, "Enable or not RT shadows SVGF")
+ANKI_CVAR2(NumericCVar<U8>, Render, RtShadows, SvgfAtrousPassCount, 3, 1, 20, "Number of atrous passes of SVGF")
+ANKI_CVAR2(NumericCVar<U32>, Render, RtShadows, RaysPerPixel, 1, 1, 8, "Number of shadow rays per pixel")
 
 /// Similar to ShadowmapsResolve but it's using ray tracing.
 class RtShadows : public RendererObject

+ 20 - 21
AnKi/Renderer/ShadowMapping.cpp

@@ -20,9 +20,8 @@
 
 namespace anki {
 
-static StatCounter g_tilesAllocatedStatVar(StatCategory::kRenderer, "Shadow tiles (re)allocated", StatFlag::kMainThreadUpdates);
-static StatCounter g_shadowLightsProcessedStatVar(StatCategory::kRenderer, "Lights processed by shadows",
-												  StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame);
+ANKI_SVAR(TilesAllocated, StatCategory::kRenderer, "Shadow tiles (re)allocated", StatFlag::kMainThreadUpdates)
+ANKI_SVAR(ShadowLightsProcessed, StatCategory::kRenderer, "Lights processed by shadows", StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame)
 
 class LightHash
 {
@@ -65,8 +64,8 @@ Error ShadowMapping::init()
 {
 	// Init RT
 	{
-		m_tileResolution = g_shadowMappingTileResolutionCVar;
-		m_tileCountBothAxis = g_shadowMappingTileCountPerRowOrColumnCVar;
+		m_tileResolution = g_cvarRenderSmTileResolution;
+		m_tileCountBothAxis = g_cvarRenderSmTileCountPerRowOrColumn;
 
 		const TextureUsageBit usage =
 			TextureUsageBit::kSrvPixel | TextureUsageBit::kSrvCompute | TextureUsageBit::kSrvDispatchRays | TextureUsageBit::kAllRtvDsv;
@@ -221,7 +220,7 @@ TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 compon
 		if(!!(result & TileAllocatorResult2::kAllocationFailed))
 		{
 			ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. Increase the %s or decrease the scene's shadow casters",
-						g_shadowMappingTileCountPerRowOrColumnCVar.getFullName().cstr());
+						g_cvarRenderSmTileCountPerRowOrColumn.getName().cstr());
 
 			// Invalidate cache entries for what we already allocated
 			for(U32 j = 0; j < i; ++j)
@@ -234,7 +233,7 @@ TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 compon
 
 		if(!(result & TileAllocatorResult2::kTileCached))
 		{
-			g_tilesAllocatedStatVar.increment(1);
+			g_svarTilesAllocated.increment(1);
 		}
 
 		goodResult &= result;
@@ -259,7 +258,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 	// Allocate tiles for the dir light first but don't build any passes
 	const LightComponent* dirLight = SceneGraph::getSingleton().getDirectionalLight();
-	if(dirLight && (!dirLight->getShadowEnabled() || !g_shadowCascadeCountCVar))
+	if(dirLight && (!dirLight->getShadowEnabled() || !g_cvarRenderShadowCascadeCount))
 	{
 		dirLight = nullptr; // Skip dir light
 	}
@@ -267,7 +266,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 	Array<UVec4, kMaxShadowCascades> dirLightAtlasViewports;
 	if(dirLight)
 	{
-		const U32 cascadeCount = g_shadowCascadeCountCVar;
+		const U32 cascadeCount = g_cvarRenderShadowCascadeCount;
 
 		Array<U32, kMaxShadowCascades> hierarchies;
 		for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
@@ -282,7 +281,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 	// Process the point lights first
 	WeakArray<LightComponent*> lights = getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_shadowLights;
-	g_shadowLightsProcessedStatVar.increment(lights.getSize() + (dirLight != 0));
+	g_svarShadowLightsProcessed.increment(lights.getSize() + (dirLight != 0));
 	for(LightComponent* lightc : lights)
 	{
 		if(lightc->getLightComponentType() != LightComponentType::kPoint || !lightc->getShadowEnabled())
@@ -292,7 +291,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 		// Prepare data to allocate tiles and allocate
 		U32 hierarchy;
-		chooseDetail(cameraOrigin, *lightc, {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar}, hierarchy);
+		chooseDetail(cameraOrigin, *lightc, {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance}, hierarchy);
 		Array<U32, 6> hierarchies;
 		hierarchies.fill(hierarchy);
 
@@ -305,7 +304,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 			// Remove a few texels to avoid bilinear filtering bleeding
 			F32 texelsBorder;
-			if(g_shadowMappingPcfCVar || g_shadowMappingPcssCVar)
+			if(g_cvarRenderSmPcf || g_cvarRenderSmPcss)
 			{
 				texelsBorder = 2.0f; // 2 texels
 			}
@@ -333,7 +332,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			}
 
 			// Vis testing
-			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+			const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 			DistanceGpuVisibilityInput visIn;
 			visIn.m_passesName = generateTempPassName("Shadows point light light UUID:%u", lightc->getUuid());
 			visIn.m_technique = RenderingTechnique::kDepth;
@@ -392,7 +391,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 		// Allocate tile
 		U32 hierarchy;
-		chooseDetail(cameraOrigin, *lightc, {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar}, hierarchy);
+		chooseDetail(cameraOrigin, *lightc, {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance}, hierarchy);
 		UVec4 atlasViewport;
 		const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport);
 
@@ -408,7 +407,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			}
 
 			// Vis testing
-			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+			const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 			FrustumGpuVisibilityInput visIn;
 			visIn.m_passesName = generateTempPassName("Shadows spot light UUID:%u", lightc->getUuid());
 			visIn.m_technique = RenderingTechnique::kDepth;
@@ -445,15 +444,15 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 	// Process the directional light last
 	if(dirLight)
 	{
-		const U32 cascadeCount = g_shadowCascadeCountCVar;
+		const U32 cascadeCount = g_cvarRenderShadowCascadeCount;
 
 		// Compute the view projection matrices
 		Array<F32, kMaxShadowCascades> cascadeDistances;
 		static_assert(kMaxShadowCascades == 4);
-		cascadeDistances[0] = g_shadowCascade0DistanceCVar;
-		cascadeDistances[1] = g_shadowCascade1DistanceCVar;
-		cascadeDistances[2] = g_shadowCascade2DistanceCVar;
-		cascadeDistances[3] = g_shadowCascade3DistanceCVar;
+		cascadeDistances[0] = g_cvarRenderShadowCascade0Distance;
+		cascadeDistances[1] = g_cvarRenderShadowCascade1Distance;
+		cascadeDistances[2] = g_cvarRenderShadowCascade2Distance;
+		cascadeDistances[3] = g_cvarRenderShadowCascade3Distance;
 
 		Array<Mat4, kMaxShadowCascades> cascadeViewProjMats;
 		Array<Mat3x4, kMaxShadowCascades> cascadeViewMats;
@@ -488,7 +487,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 		for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
 		{
 			// Vis testing
-			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar, g_lod1MaxDistanceCVar};
+			const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
 			FrustumGpuVisibilityInput visIn;
 			visIn.m_passesName = generateTempPassName("Shadows: Dir light cascade cascade:%u", cascade);
 			visIn.m_technique = RenderingTechnique::kDepth;

+ 4 - 6
AnKi/Renderer/ShadowMapping.h

@@ -18,12 +18,10 @@ class GpuVisibilityOutput;
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_shadowMappingTileResolutionCVar("R", "ShadowMappingTileResolution", (ANKI_PLATFORM_MOBILE) ? 128 : 256, 16, 2048,
-														  "Shadowmapping tile resolution");
-inline NumericCVar<U32> g_shadowMappingTileCountPerRowOrColumnCVar("R", "ShadowMappingTileCountPerRowOrColumn", 32, 1, 256,
-																   "Shadowmapping atlas will have this number squared number of tiles");
-inline BoolCVar g_shadowMappingPcfCVar("R", "ShadowMappingPcf", (ANKI_PLATFORM_MOBILE) ? false : true, "Shadow PCF");
-inline BoolCVar g_shadowMappingPcssCVar("R", "ShadowMappingPcss", (ANKI_PLATFORM_MOBILE) ? false : true, "Shadow PCSS");
+ANKI_CVAR2(NumericCVar<U32>, Render, Sm, TileResolution, (ANKI_PLATFORM_MOBILE) ? 128 : 256, 16, 2048, "Shadowmapping tile resolution")
+ANKI_CVAR2(NumericCVar<U32>, Render, Sm, TileCountPerRowOrColumn, 32, 1, 256, "Shadowmapping atlas will have this number squared number of tiles")
+ANKI_CVAR2(BoolCVar, Render, Sm, Pcf, (ANKI_PLATFORM_MOBILE) ? false : true, "Shadow PCF")
+ANKI_CVAR2(BoolCVar, Render, Sm, Pcss, (ANKI_PLATFORM_MOBILE) ? false : true, "Shadow PCSS")
 
 /// Shadowmapping pass
 class ShadowMapping : public RendererObject

+ 6 - 6
AnKi/Renderer/ShadowmapsResolve.cpp

@@ -17,7 +17,7 @@ namespace anki {
 
 Error ShadowmapsResolve::init()
 {
-	m_quarterRez = g_smResolveQuarterRezCVar;
+	m_quarterRez = g_cvarRenderShadowmapResolveQuarterRez;
 	const U32 width = getRenderer().getInternalResolution().x() / (m_quarterRez + 1);
 	const U32 height = getRenderer().getInternalResolution().y() / (m_quarterRez + 1);
 
@@ -44,7 +44,7 @@ void ShadowmapsResolve::populateRenderGraph(RenderingContext& ctx)
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
 	m_runCtx.m_rt = rgraph.newRenderTarget(m_rtDescr);
 
-	if(g_preferComputeCVar)
+	if(g_cvarRenderPreferCompute)
 	{
 		NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("ResolveShadows");
 
@@ -92,11 +92,11 @@ void ShadowmapsResolve::run(RenderPassWorkContext& rgraphCtx, RenderingContext&
 	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 	U32 quality;
-	if(g_shadowMappingPcssCVar)
+	if(g_cvarRenderSmPcss)
 	{
 		quality = 2;
 	}
-	else if(g_shadowMappingPcfCVar)
+	else if(g_cvarRenderSmPcf)
 	{
 		quality = 1;
 	}
@@ -131,13 +131,13 @@ void ShadowmapsResolve::run(RenderPassWorkContext& rgraphCtx, RenderingContext&
 		rgraphCtx.bindSrv(6, 0, getRtShadows().getRt());
 	}
 
-	if(g_preferComputeCVar || g_shadowMappingPcfCVar || g_shadowMappingPcssCVar)
+	if(g_cvarRenderPreferCompute || g_cvarRenderSmPcf || g_cvarRenderSmPcss)
 	{
 		const Vec4 consts(F32(m_rtDescr.m_width), F32(m_rtDescr.m_height), 0.0f, 0.0f);
 		cmdb.setFastConstants(&consts, sizeof(consts));
 	}
 
-	if(g_preferComputeCVar)
+	if(g_cvarRenderPreferCompute)
 	{
 		rgraphCtx.bindUav(0, 0, m_runCtx.m_rt);
 		dispatchPPCompute(cmdb, 8, 8, m_rtDescr.m_width, m_rtDescr.m_height);

+ 1 - 1
AnKi/Renderer/ShadowmapsResolve.h

@@ -14,7 +14,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_smResolveQuarterRezCVar("R", "SmResolveQuarterRez", ANKI_PLATFORM_MOBILE, "Shadowmapping resolve quality");
+ANKI_CVAR(BoolCVar, Render, ShadowmapResolveQuarterRez, ANKI_PLATFORM_MOBILE, "Shadowmapping resolve quality")
 
 /// Resolves shadowmaps into a single texture.
 class ShadowmapsResolve : public RendererObject

+ 16 - 16
AnKi/Renderer/Ssao.cpp

@@ -15,8 +15,8 @@ namespace anki {
 
 Error Ssao::init()
 {
-	const UVec2 rez = (g_ssaoQuarterRezCVar) ? getRenderer().getInternalResolution() / 2 : getRenderer().getInternalResolution();
-	const Bool preferCompute = g_preferComputeCVar;
+	const UVec2 rez = (g_cvarRenderSsaoQuarterRez) ? getRenderer().getInternalResolution() / 2 : getRenderer().getInternalResolution();
+	const Bool preferCompute = g_cvarRenderPreferCompute;
 
 	{
 		TextureUsageBit usage = TextureUsageBit::kAllSrv;
@@ -33,8 +33,8 @@ Error Ssao::init()
 		getRenderer().create2DRenderTargetDescription(rez.x(), rez.y(), Format::kR8G8B8A8_Snorm, "Bent normals + SSAO temp");
 	m_bentNormalsAndSsaoRtDescr.bake();
 
-	const Array<SubMutation, 2> mutation = {
-		{{"SPATIAL_DENOISE_SAMPLE_COUNT", g_ssaoSpatialDenoiseSampleCountCVar}, {"DENOISING_QUARTER_RESOLUTION", g_ssaoQuarterRezCVar}}};
+	const Array<SubMutation, 2> mutation = {{{"SPATIAL_DENOISE_SAMPLE_COUNT", MutatorValue(g_cvarRenderSsaoSpatialDenoiseSampleCout)},
+											 {"DENOISING_QUARTER_RESOLUTION", g_cvarRenderSsaoQuarterRez}}};
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", mutation, m_prog, m_grProg, "Ssao"));
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", mutation, m_prog, m_spatialDenoiseVerticalGrProg, "SsaoSpatialDenoiseVertical"));
@@ -51,7 +51,7 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(Ssao);
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
-	const Bool preferCompute = g_preferComputeCVar;
+	const Bool preferCompute = g_cvarRenderPreferCompute;
 
 	const U32 readRtIdx = getRenderer().getFrameCount() & 1;
 	const U32 writeRtIdx = !readRtIdx;
@@ -72,7 +72,7 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 	}
 
 	m_runCtx.m_finalRt = finalRt;
-	const RenderTargetHandle depthRt = (g_ssaoQuarterRezCVar) ? getDepthDownscale().getRt() : getGBuffer().getDepthRt();
+	const RenderTargetHandle depthRt = (g_cvarRenderSsaoQuarterRez) ? getDepthDownscale().getRt() : getGBuffer().getDepthRt();
 
 	const RenderTargetHandle bentNormalsAndSsaoTempRt = rgraph.newRenderTarget(m_bentNormalsAndSsaoRtDescr);
 
@@ -124,8 +124,8 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 			const UVec2 rez = getRenderer().getInternalResolution() / 2u;
 
 			SsaoConstants& consts = *allocateAndBindConstants<SsaoConstants>(cmdb, 0, 0);
-			consts.m_radius = g_ssaoRadiusCVar;
-			consts.m_sampleCount = g_ssaoSampleCountCVar;
+			consts.m_radius = g_cvarRenderSsaoRadius;
+			consts.m_sampleCount = g_cvarRenderSsaoSampleCount;
 			consts.m_viewportSizef = Vec2(rez);
 			consts.m_unprojectionParameters = ctx.m_matrices.m_unprojectionParameters;
 			consts.m_projectionMat00 = ctx.m_matrices.m_projection(0, 0);
@@ -133,11 +133,11 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 			consts.m_projectionMat22 = ctx.m_matrices.m_projection(2, 2);
 			consts.m_projectionMat23 = ctx.m_matrices.m_projection(2, 3);
 			consts.m_frameCount = getRenderer().getFrameCount() % kMaxU32;
-			consts.m_ssaoPower = g_ssaoPowerCVar;
+			consts.m_ssaoPower = g_cvarRenderSsaoPower;
 			consts.m_viewMat = ctx.m_matrices.m_view;
 			consts.m_viewToWorldMat = ctx.m_matrices.m_cameraTransform;
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, finalRt);
 
@@ -188,9 +188,9 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 
 			cmdb.bindConstantBuffer(0, 0, ctx.m_globalRenderingConstantsBuffer);
 
-			const UVec2 rez = (g_ssaoQuarterRezCVar) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
+			const UVec2 rez = (g_cvarRenderSsaoQuarterRez) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, bentNormalsAndSsaoTempRt);
 				dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());
@@ -233,9 +233,9 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, bentNormalsAndSsaoTempRt);
 			rgraphCtx.bindSrv(1, 0, depthRt);
 
-			const UVec2 rez = (g_ssaoQuarterRezCVar) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
+			const UVec2 rez = (g_cvarRenderSsaoQuarterRez) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, historyRt);
 				dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());
@@ -278,9 +278,9 @@ void Ssao::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, historyRt);
 			rgraphCtx.bindSrv(1, 0, depthRt);
 
-			const UVec2 rez = (g_ssaoQuarterRezCVar) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
+			const UVec2 rez = (g_cvarRenderSsaoQuarterRez) ? getRenderer().getInternalResolution() / 2u : getRenderer().getInternalResolution();
 
-			if(g_preferComputeCVar)
+			if(g_cvarRenderPreferCompute)
 			{
 				rgraphCtx.bindUav(0, 0, finalRt);
 				dispatchPPCompute(cmdb, 8, 8, rez.x(), rez.y());

+ 7 - 7
AnKi/Renderer/Ssao.h

@@ -14,16 +14,16 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U32> g_ssaoSampleCountCVar("R", "SsaoSampleCount", 4, 1, 1024, "SSAO sample count");
-inline NumericCVar<F32> g_ssaoRadiusCVar("R", "SsaoRadius", 2.0f, 0.1f, 100.0f, "SSAO radius in meters");
-inline BoolCVar g_ssaoQuarterRezCVar("R", "SsaoQuarterResolution", ANKI_PLATFORM_MOBILE, "Render SSAO in quarter rez");
-inline NumericCVar<F32> g_ssaoPowerCVar("R", "SsaoPower", 1.5f, 0.1f, 100.0f, "SSAO power");
-inline NumericCVar<U8> g_ssaoSpatialDenoiseSampleCountCVar(
-	"R", "SsaoSpatialDenoiseSampleCount", (ANKI_PLATFORM_MOBILE) ? 3 : 9,
+ANKI_CVAR2(NumericCVar<U32>, Render, Ssao, SampleCount, 4, 1, 1024, "SSAO sample count")
+ANKI_CVAR2(NumericCVar<F32>, Render, Ssao, Radius, 2.0f, 0.1f, 100.0f, "SSAO radius in meters")
+ANKI_CVAR2(BoolCVar, Render, Ssao, QuarterRez, ANKI_PLATFORM_MOBILE, "Render SSAO in quarter rez")
+ANKI_CVAR2(NumericCVar<F32>, Render, Ssao, Power, 1.5f, 0.1f, 100.0f, "SSAO power")
+ANKI_CVAR2(
+	NumericCVar<U8>, Render, Ssao, SpatialDenoiseSampleCout, (ANKI_PLATFORM_MOBILE) ? 3 : 9,
 	[](U8 val) {
 		return val == 3 || val == 5 || val == 7 || val == 9;
 	},
-	"SSAO spatial denoise quality");
+	"SSAO spatial denoise quality")
 
 /// Screen space ambient occlusion.
 class Ssao : public RendererObject

+ 3 - 3
AnKi/Renderer/TemporalAA.cpp

@@ -21,7 +21,7 @@ Error TemporalAA::init()
 	for(U32 i = 0; i < 2; ++i)
 	{
 		TextureUsageBit usage = TextureUsageBit::kSrvPixel | TextureUsageBit::kSrvCompute;
-		usage |= (g_preferComputeCVar) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
+		usage |= (g_cvarRenderPreferCompute) ? TextureUsageBit::kUavCompute : TextureUsageBit::kRtvDsvWrite;
 
 		TextureInitInfo texinit =
 			getRenderer().create2DRenderTargetInitInfo(getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y(),
@@ -40,7 +40,7 @@ void TemporalAA::populateRenderGraph(RenderingContext& ctx)
 
 	const U32 historyRtIdx = (getRenderer().getFrameCount() + 1) & 1;
 	const U32 renderRtIdx = !historyRtIdx;
-	const Bool preferCompute = g_preferComputeCVar;
+	const Bool preferCompute = g_cvarRenderPreferCompute;
 
 	// Import RTs
 	if(m_rtTexturesImportedOnce) [[likely]]
@@ -96,7 +96,7 @@ void TemporalAA::populateRenderGraph(RenderingContext& ctx)
 		rgraphCtx.bindSrv(1, 0, m_runCtx.m_historyRt);
 		rgraphCtx.bindSrv(2, 0, getRenderer().getMotionVectors().getMotionVectorsRt());
 
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			rgraphCtx.bindUav(0, 0, m_runCtx.m_renderRt);
 

+ 3 - 3
AnKi/Renderer/TemporalUpscaler.cpp

@@ -31,7 +31,7 @@ Error TemporalUpscaler::init()
 		inf.m_sourceTextureResolution = getRenderer().getInternalResolution();
 		inf.m_targetTextureResolution = getRenderer().getPostProcessResolution();
 		inf.m_upscalerType = GrUpscalerType::kDlss2;
-		inf.m_qualityMode = GrUpscalerQualityMode(g_dlssQualityCVar - 1);
+		inf.m_qualityMode = GrUpscalerQualityMode(g_cvarRenderDlssQuality - 1);
 
 		m_grUpscaler = GrManager::getSingleton().newGrUpscaler(inf);
 	}
@@ -94,7 +94,7 @@ void TemporalUpscaler::populateRenderGraph(RenderingContext& ctx)
 	}
 	else
 	{
-		const Bool preferCompute = g_preferComputeCVar;
+		const Bool preferCompute = g_cvarRenderPreferCompute;
 
 		TextureUsageBit readUsage;
 		TextureUsageBit writeUsage;
@@ -133,7 +133,7 @@ void TemporalUpscaler::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, getRenderer().getLightShading().getRt());
 			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
 
-			const Bool preferCompute = g_preferComputeCVar;
+			const Bool preferCompute = g_cvarRenderPreferCompute;
 
 			if(preferCompute)
 			{

+ 1 - 1
AnKi/Renderer/TemporalUpscaler.h

@@ -12,7 +12,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<U8> g_dlssQualityCVar("R", "DlssQuality", 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality");
+ANKI_CVAR(NumericCVar<U8>, Render, DlssQuality, 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality")
 
 /// Upscales.
 class TemporalUpscaler : public RendererObject

+ 2 - 2
AnKi/Renderer/Tonemapping.cpp

@@ -88,7 +88,7 @@ void Tonemapping::populateRenderGraph(RenderingContext& ctx)
 		const RenderTargetHandle outRt = m_runCtx.m_rt;
 
 		RenderPassBase* ppass;
-		if(g_preferComputeCVar)
+		if(g_cvarRenderPreferCompute)
 		{
 			NonGraphicsRenderPass& pass = ctx.m_renderGraphDescr.newNonGraphicsRenderPass("Tonemap");
 			pass.newTextureDependency(inRt, TextureUsageBit::kSrvCompute);
@@ -107,7 +107,7 @@ void Tonemapping::populateRenderGraph(RenderingContext& ctx)
 		ppass->setWork([this](RenderPassWorkContext& rgraphCtx) {
 			ANKI_TRACE_SCOPED_EVENT(Tonemapping);
 			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-			const Bool preferCompute = g_preferComputeCVar;
+			const Bool preferCompute = g_cvarRenderPreferCompute;
 			const RenderTargetHandle inRt = (getRenderer().getTemporalUpscaler().getEnabled()) ? getRenderer().getTemporalUpscaler().getRt()
 																							   : getRenderer().getTemporalAA().getRt();
 			const RenderTargetHandle outRt = m_runCtx.m_rt;

+ 5 - 8
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -25,11 +25,8 @@ constexpr U32 kMaxVisibleObjects = 30 * 1024;
 constexpr U32 kMaxVisiblePrimitives = 40'000'000;
 constexpr U32 kMaxVisibleMeshlets = kMaxVisiblePrimitives / kMaxPrimitivesPerMeshlet;
 
-static StatCounter g_gpuVisMemoryAllocatedStatVar(StatCategory::kRenderer, "GPU vis mem",
-												  StatFlag::kBytes | StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame);
-
-static StatCounter g_maxGpuVisMemoryAllocatedStatVar(StatCategory::kRenderer, "GPU vis mem: max ever used/frame",
-													 StatFlag::kBytes | StatFlag::kMainThreadUpdates);
+ANKI_SVAR(GpuVisMemoryAllocated, StatCategory::kRenderer, "GPU vis mem", StatFlag::kBytes | StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame)
+ANKI_SVAR(MaxGpuVisMemoryAllocated, StatCategory::kRenderer, "GPU vis mem: max ever used/frame", StatFlag::kBytes | StatFlag::kMainThreadUpdates)
 
 class GpuVisLimits
 {
@@ -47,7 +44,7 @@ static GpuVisLimits computeLimits(RenderingTechnique t)
 	const RenderStateBucketContainer& buckets = RenderStateBucketContainer::getSingleton();
 
 	const U32 meshletUserCount = buckets.getBucketsActiveUserCountWithMeshletSupport(t);
-	ANKI_ASSERT(meshletUserCount == 0 || (g_meshletRenderingCVar || GrManager::getSingleton().getDeviceCapabilities().m_meshShaders));
+	ANKI_ASSERT(meshletUserCount == 0 || (g_cvarCoreMeshletRendering || GrManager::getSingleton().getDeviceCapabilities().m_meshShaders));
 	out.m_totalLegacyRenderables = buckets.getBucketsActiveUserCountWithNoMeshletSupport(t);
 	out.m_maxVisibleLegacyRenderables = min(out.m_totalLegacyRenderables, kMaxVisibleObjects);
 
@@ -69,7 +66,7 @@ public:
 
 			m_maxMemUsedInFrame = max(m_maxMemUsedInFrame, m_memUsedThisFrame);
 			m_memUsedThisFrame = 0;
-			g_maxGpuVisMemoryAllocatedStatVar.set(m_maxMemUsedInFrame);
+			g_svarMaxGpuVisMemoryAllocated.set(m_maxMemUsedInFrame);
 		}
 
 		m_memUsedThisFrame += size;
@@ -88,7 +85,7 @@ static BufferView allocateStructuredBuffer(U32 count)
 
 	if(count > 0)
 	{
-		g_gpuVisMemoryAllocatedStatVar.increment(sizeof(T) * count);
+		g_svarGpuVisMemoryAllocated.increment(sizeof(T) * count);
 		out = GpuVisibleTransientMemoryPool::getSingleton().allocateStructuredBuffer<T>(count);
 
 		GpuVisMemoryStats::getSingleton().informAboutAllocation(sizeof(T) * count);

+ 3 - 3
AnKi/Renderer/VolumetricFog.cpp

@@ -18,9 +18,9 @@ namespace anki {
 Error VolumetricFog::init()
 {
 	// Misc
-	const F32 qualityXY = g_volumetricLightingAccumulationQualityXYCVar;
-	const F32 qualityZ = g_volumetricLightingAccumulationQualityZCVar;
-	m_finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_volumetricLightingAccumulationFinalZSplitCVar);
+	const F32 qualityXY = g_cvarRenderVolumetricLightingAccumulationQualityXY;
+	const F32 qualityZ = g_cvarRenderVolumetricLightingAccumulationQualityZ;
+	m_finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_cvarRenderVolumetricLightingAccumulationFinalZSplit);
 
 	m_volumeSize[0] = U32(F32(getRenderer().getTileCounts().x()) * qualityXY);
 	m_volumeSize[1] = U32(F32(getRenderer().getTileCounts().y()) * qualityXY);

+ 4 - 4
AnKi/Renderer/VolumetricLightingAccumulation.cpp

@@ -19,9 +19,9 @@ namespace anki {
 Error VolumetricLightingAccumulation::init()
 {
 	// Misc
-	const F32 qualityXY = g_volumetricLightingAccumulationQualityXYCVar;
-	const F32 qualityZ = g_volumetricLightingAccumulationQualityZCVar;
-	const U32 finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_volumetricLightingAccumulationFinalZSplitCVar);
+	const F32 qualityXY = g_cvarRenderVolumetricLightingAccumulationQualityXY;
+	const F32 qualityZ = g_cvarRenderVolumetricLightingAccumulationQualityZ;
+	const U32 finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_cvarRenderVolumetricLightingAccumulationFinalZSplit);
 
 	m_volumeSize[0] = U32(F32(getRenderer().getTileCounts().x()) * qualityXY);
 	m_volumeSize[1] = U32(F32(getRenderer().getTileCounts().y()) * qualityXY);
@@ -136,7 +136,7 @@ void VolumetricLightingAccumulation::populateRenderGraph(RenderingContext& ctx)
 		}
 		consts.m_volumeSize = UVec3(m_volumeSize);
 
-		const U32 finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_volumetricLightingAccumulationFinalZSplitCVar);
+		const U32 finalZSplit = min<U32>(getRenderer().getZSplitCount() - 1, g_cvarRenderVolumetricLightingAccumulationFinalZSplit);
 		consts.m_maxZSplitsToProcessf = F32(finalZSplit + 1);
 
 		cmdb.setFastConstants(&consts, sizeof(consts));

+ 4 - 6
AnKi/Renderer/VolumetricLightingAccumulation.h

@@ -12,12 +12,10 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<F32> g_volumetricLightingAccumulationQualityXYCVar("R", "VolumetricLightingAccumulationQualityXY", 4.0f, 1.0f, 16.0f,
-																	  "Quality of XY dimensions of volumetric lights");
-inline NumericCVar<F32> g_volumetricLightingAccumulationQualityZCVar("R", "VolumetricLightingAccumulationQualityZ", 4.0f, 1.0f, 16.0f,
-																	 "Quality of Z dimension of volumetric lights");
-inline NumericCVar<U32> g_volumetricLightingAccumulationFinalZSplitCVar("R", "VolumetricLightingAccumulationFinalZSplit", 26, 1, 256,
-																		"Final cluster split that will recieve volumetric lights");
+ANKI_CVAR2(NumericCVar<F32>, Render, VolumetricLightingAccumulation, QualityXY, 4.0f, 1.0f, 16.0f, "Quality of XY dimensions of volumetric lights")
+ANKI_CVAR2(NumericCVar<F32>, Render, VolumetricLightingAccumulation, QualityZ, 4.0f, 1.0f, 16.0f, "Quality of Z dimension of volumetric lights")
+ANKI_CVAR2(NumericCVar<U32>, Render, VolumetricLightingAccumulation, FinalZSplit, 26, 1, 256,
+		   "Final cluster split that will recieve volumetric lights")
 
 /// Volumetric lighting. It accumulates lighting in a volume texture.
 class VolumetricLightingAccumulation : public RendererObject

+ 4 - 4
AnKi/Renderer/VrsSriGeneration.cpp

@@ -51,7 +51,7 @@ Error VrsSriGeneration::init()
 		variantInit.addMutation("SHARED_MEMORY", 1);
 	}
 
-	variantInit.addMutation("LIMIT_RATE_TO_2X2", g_vrsLimitTo2x2CVar);
+	variantInit.addMutation("LIMIT_RATE_TO_2X2", g_cvarRenderVrsLimitTo2x2);
 
 	const ShaderProgramResourceVariant* variant;
 	m_prog->getOrCreateVariant(variantInit, variant);
@@ -81,7 +81,7 @@ void VrsSriGeneration::getDebugRenderTarget(CString rtName, Array<RenderTargetHa
 
 void VrsSriGeneration::importRenderTargets(RenderingContext& ctx)
 {
-	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar;
+	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_cvarGrVrs;
 	if(!enableVrs)
 	{
 		return;
@@ -102,7 +102,7 @@ void VrsSriGeneration::importRenderTargets(RenderingContext& ctx)
 
 void VrsSriGeneration::populateRenderGraph(RenderingContext& ctx)
 {
-	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_vrsCVar;
+	const Bool enableVrs = GrManager::getSingleton().getDeviceCapabilities().m_vrs && g_cvarGrVrs;
 	if(!enableVrs)
 	{
 		return;
@@ -128,7 +128,7 @@ void VrsSriGeneration::populateRenderGraph(RenderingContext& ctx)
 			rgraphCtx.bindSrv(0, 0, getRenderer().getLightShading().getRt());
 			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
 			rgraphCtx.bindUav(0, 0, m_runCtx.m_rt);
-			const Vec4 pc(1.0f / Vec2(getRenderer().getInternalResolution()), g_vrsThresholdCVar, 0.0f);
+			const Vec4 pc(1.0f / Vec2(getRenderer().getInternalResolution()), g_cvarRenderVrsThreshold, 0.0f);
 			cmdb.setFastConstants(&pc, sizeof(pc));
 
 			const U32 fakeWorkgroupSizeXorY = m_sriTexelDimension;

+ 1 - 1
AnKi/Renderer/VrsSriGeneration.h

@@ -12,7 +12,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline NumericCVar<F32> g_vrsThresholdCVar("R", "VrsThreshold", 0.1f, 0.0f, 1.0f, "Threshold under which a lower shading rate will be applied");
+ANKI_CVAR(NumericCVar<F32>, Render, VrsThreshold, 0.1f, 0.0f, 1.0f, "Threshold under which a lower shading rate will be applied")
 
 /// Computes the shading rate image to be used by a number of passes.
 class VrsSriGeneration : public RendererObject

+ 3 - 3
AnKi/Resource/AsyncLoader.cpp

@@ -10,7 +10,7 @@
 
 namespace anki {
 
-static StatCounter g_asyncTasksInFlightStatVar(StatCategory::kMisc, "Async loader tasks", StatFlag::kNone);
+ANKI_SVAR(AsyncTasksInFlight, StatCategory::kMisc, "Async loader tasks", StatFlag::kNone)
 
 AsyncLoader::AsyncLoader()
 	: m_thread("AsyncLoad")
@@ -94,7 +94,7 @@ Error AsyncLoader::threadWorker()
 			{
 				ANKI_TRACE_SCOPED_EVENT(RsrcAsyncTask);
 				err = (*task)(ctx);
-				g_asyncTasksInFlightStatVar.decrement(1u);
+				g_svarAsyncTasksInFlight.decrement(1u);
 			}
 
 			if(!err)
@@ -128,7 +128,7 @@ void AsyncLoader::submitTask(AsyncLoaderTask* task)
 	ANKI_ASSERT(task);
 
 	m_tasksInFlightCount.fetchAdd(1);
-	g_asyncTasksInFlightStatVar.increment(1);
+	g_svarAsyncTasksInFlight.increment(1);
 
 	LockGuard<Mutex> lock(m_mtx);
 	m_taskQueue.pushBack(task);

+ 1 - 1
AnKi/Resource/ImageResource.cpp

@@ -66,7 +66,7 @@ Error ImageResource::load(const ResourceFilename& filename, Bool async)
 	ResourceFilePtr file;
 	ANKI_CHECK(openFile(filename, file));
 
-	ANKI_CHECK(loader.load(file, filename, g_maxImageSizeCVar));
+	ANKI_CHECK(loader.load(file, filename, g_cvarRsrcMaxImageSize));
 
 	// Various sizes
 	init.m_width = loader.getWidth();

+ 1 - 1
AnKi/Resource/ImageResource.h

@@ -13,7 +13,7 @@ namespace anki {
 /// @addtogroup resource
 /// @{
 
-inline NumericCVar<U32> g_maxImageSizeCVar("Rsrc", "MaxImageSize", 1024u * 1024u, 4u, kMaxU32, "Max image size to load");
+ANKI_CVAR(NumericCVar<U32>, Rsrc, MaxImageSize, 1024u * 1024u, 4u, kMaxU32, "Max image size to load")
 
 /// Image resource class. It loads or creates an image and then loads it in the GPU. It supports compressed and uncompressed TGAs, PNGs, JPEG and
 /// AnKi's image format.

+ 1 - 1
AnKi/Resource/MaterialResource.cpp

@@ -533,7 +533,7 @@ const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey&
 	}
 
 	const Bool meshShadersSupported = GrManager::getSingleton().getDeviceCapabilities().m_meshShaders;
-	ANKI_ASSERT(!(key.getMeshletRendering() && (!meshShadersSupported && !g_meshletRenderingCVar))
+	ANKI_ASSERT(!(key.getMeshletRendering() && (!meshShadersSupported && !g_cvarCoreMeshletRendering))
 				&& "Can't be asking for meshlet rendering if mesh shaders or SW meshlet rendering are not supported/enabled");
 	if(key.getMeshletRendering() && !(m_shaderTechniques & (ShaderTechniqueBit::kMeshSaders | ShaderTechniqueBit::kSwMeshletRendering)))
 	{

+ 1 - 1
AnKi/Resource/MeshResource.cpp

@@ -142,7 +142,7 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 		}
 
 		// Meshlet
-		if(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_meshletRenderingCVar)
+		if(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_cvarCoreMeshletRendering)
 		{
 			const PtrSize meshletIndicesSize = header.m_meshletPrimitiveCounts[l] * sizeof(U8Vec4);
 			lod.m_meshletIndices = UnifiedGeometryBuffer::getSingleton().allocate(meshletIndicesSize, sizeof(U8Vec4));

+ 2 - 2
AnKi/Resource/ResourceFilesystem.cpp

@@ -230,7 +230,7 @@ ResourceFilesystem::~ResourceFilesystem()
 Error ResourceFilesystem::init()
 {
 	ResourceStringList paths;
-	paths.splitString(g_dataPathsCVar, ':');
+	paths.splitString(g_cvarRsrcDataPaths, ':');
 
 	// Workaround the fact that : is used in drives in Windows
 #if ANKI_OS_WINDOWS
@@ -259,7 +259,7 @@ Error ResourceFilesystem::init()
 
 	if(paths.getSize() < 1)
 	{
-		ANKI_RESOURCE_LOGE("Config option \"g_dataPathsCVar\" is empty");
+		ANKI_RESOURCE_LOGE("Config option \"g_cvarRsrcDataPaths\" is empty");
 		return Error::kUserData;
 	}
 

+ 4 - 5
AnKi/Resource/ResourceFilesystem.h

@@ -17,11 +17,10 @@ namespace anki {
 /// @addtogroup resource
 /// @{
 
-inline StringCVar
-	g_dataPathsCVar("Rsrc", "DataPaths", ".",
-					"The engine loads assets only in from these paths. Separate them with : (it's smart enough to identify drive letters in "
-					"Windows). After a path you can add an optional | and what follows it is a number of words to include or exclude paths. "
-					"eg. my_path|include_this,include_that,+exclude_this");
+ANKI_CVAR(StringCVar, Rsrc, DataPaths, ".",
+		  "The engine loads assets only in from these paths. Separate them with : (it's smart enough to identify drive letters in Windows). After a "
+		  "path you can add an optional | and what follows it is a number of words to include or exclude paths. eg. "
+		  "my_path|include_this,include_that,+exclude_this")
 
 /// Resource filesystem file. An interface that abstracts the resource file.
 class ResourceFile

+ 1 - 1
AnKi/Resource/ResourceManager.cpp

@@ -61,7 +61,7 @@ Error ResourceManager::init(AllocAlignedCallback allocCallback, void* allocCallb
 	AsyncLoader::allocateSingleton();
 
 	TransferGpuAllocator::allocateSingleton();
-	ANKI_CHECK(TransferGpuAllocator::getSingleton().init(g_transferScratchMemorySizeCVar));
+	ANKI_CHECK(TransferGpuAllocator::getSingleton().init(g_cvarRsrcTransferScratchMemorySize));
 
 	// Init the programs
 	ShaderProgramResourceSystem::allocateSingleton();

+ 1 - 2
AnKi/Resource/ResourceManager.h

@@ -28,8 +28,7 @@ class AccelerationStructureScratchAllocator;
 /// @addtogroup resource
 /// @{
 
-inline NumericCVar<PtrSize> g_transferScratchMemorySizeCVar("Rsrc", "TransferScratchMemorySize", 256_MB, 1_MB, 4_GB,
-															"Memory that is used fot texture and buffer uploads");
+ANKI_CVAR(NumericCVar<PtrSize>, Rsrc, TransferScratchMemorySize, 256_MB, 1_MB, 4_GB, "Memory that is used fot texture and buffer uploads")
 
 /// Resource manager. It holds a few global variables
 class ResourceManager : public MakeSingleton<ResourceManager>

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

@@ -160,13 +160,13 @@ F32 GlobalIlluminationProbeComponent::getRenderRadius() const
 {
 	F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
 	effectiveDistance = max(effectiveDistance, m_halfSize.z());
-	effectiveDistance = max<F32>(effectiveDistance, g_probeEffectiveDistanceCVar);
+	effectiveDistance = max<F32>(effectiveDistance, g_cvarSceneProbeEffectiveDistance);
 	return effectiveDistance;
 }
 
 F32 GlobalIlluminationProbeComponent::getShadowsRenderRadius() const
 {
-	return min<F32>(getRenderRadius(), g_probeShadowEffectiveDistanceCVar);
+	return min<F32>(getRenderRadius(), g_cvarSceneProbeShadowEffectiveDistance);
 }
 
 } // end namespace anki

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

@@ -203,7 +203,7 @@ void MaterialComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 
 			meshLod.m_renderableIndex = m_gpuSceneRenderable.getIndex();
 
-			if(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_meshletRenderingCVar)
+			if(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_cvarCoreMeshletRendering)
 			{
 				U32 dummy;
 				PtrSize meshletBoundingVolumesUgbOffset, meshletGometryDescriptorsUgbOffset;
@@ -303,7 +303,7 @@ void MaterialComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 			key.setRenderingTechnique(t);
 			key.setSkinned(hasSkin);
 			key.setVelocity(moved);
-			key.setMeshletRendering(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_meshletRenderingCVar);
+			key.setMeshletRendering(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_cvarCoreMeshletRendering);
 
 			const MaterialVariant& mvariant = mtl.getOrCreateVariant(key);
 

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

@@ -21,7 +21,7 @@ ReflectionProbeComponent::ReflectionProbeComponent(SceneNode* node)
 	TextureInitInfo texInit("ReflectionProbe");
 	texInit.m_format =
 		(GrManager::getSingleton().getDeviceCapabilities().m_unalignedBbpTextureFormats) ? Format::kR16G16B16_Sfloat : Format::kR16G16B16A16_Sfloat;
-	texInit.m_width = g_reflectionProbeResolutionCVar;
+	texInit.m_width = g_cvarRenderProbeReflectionsResolution;
 	texInit.m_height = texInit.m_width;
 	texInit.m_mipmapCount = computeMaxMipmapCount2d(texInit.m_width, texInit.m_height, 8);
 	texInit.m_type = TextureType::kCube;
@@ -74,13 +74,13 @@ F32 ReflectionProbeComponent::getRenderRadius() const
 {
 	F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
 	effectiveDistance = max(effectiveDistance, m_halfSize.z());
-	effectiveDistance = max<F32>(effectiveDistance, g_probeEffectiveDistanceCVar);
+	effectiveDistance = max<F32>(effectiveDistance, g_cvarSceneProbeEffectiveDistance);
 	return effectiveDistance;
 }
 
 F32 ReflectionProbeComponent::getShadowsRenderRadius() const
 {
-	return min<F32>(getRenderRadius(), g_probeShadowEffectiveDistanceCVar);
+	return min<F32>(getRenderRadius(), g_cvarSceneProbeShadowEffectiveDistance);
 }
 
 } // end namespace anki

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

@@ -15,8 +15,7 @@ namespace anki {
 /// @addtogroup scene
 /// @{
 
-inline NumericCVar<U32> g_reflectionProbeResolutionCVar("Scene", "ReflectionProbeResolution", 128, 8, 2048,
-														"The resolution of the reflection probe's reflection");
+ANKI_CVAR2(NumericCVar<U32>, Render, ProbeReflections, Resolution, 128, 8, 2048, "The resolution of the reflection probe's reflection")
 
 /// Reflection probe component.
 class ReflectionProbeComponent : public SceneComponent

+ 14 - 14
AnKi/Scene/GpuSceneArrays.def.h

@@ -13,33 +13,33 @@
 #define ANKI_TRF_ARR Array<Mat3x4, 2>
 #define ANKI_MESH_ARR Array<GpuSceneMeshLod, kMaxLodCount>
 
-ANKI_CAT_TYPE(Transform, ANKI_TRF_ARR, 0, g_minGpuSceneTransformsCVar)
+ANKI_CAT_TYPE(Transform, ANKI_TRF_ARR, 0, g_cvarSceneMinGpuSceneTransforms)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(MeshLod, ANKI_MESH_ARR, 0, g_minGpuSceneMeshesCVar)
+ANKI_CAT_TYPE(MeshLod, ANKI_MESH_ARR, 0, g_cvarSceneMinGpuSceneMeshes)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(ParticleEmitter, GpuSceneParticleEmitter, 0, g_minGpuSceneParticleEmittersCVar)
+ANKI_CAT_TYPE(ParticleEmitter, GpuSceneParticleEmitter, 0, g_cvarSceneMinGpuSceneParticleEmitters)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(LightVisibleRenderablesHash, GpuSceneLightVisibleRenderablesHash, 0, g_minGpuSceneLightsCVar)
+ANKI_CAT_TYPE(LightVisibleRenderablesHash, GpuSceneLightVisibleRenderablesHash, 0, g_cvarSceneMinGpuSceneLights)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(Light, GpuSceneLight, 0, g_minGpuSceneLightsCVar)
+ANKI_CAT_TYPE(Light, GpuSceneLight, 0, g_cvarSceneMinGpuSceneLights)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(ReflectionProbe, GpuSceneReflectionProbe, 0, g_minGpuSceneReflectionProbesCVar)
+ANKI_CAT_TYPE(ReflectionProbe, GpuSceneReflectionProbe, 0, g_cvarSceneMinGpuSceneReflectionProbes)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(GlobalIlluminationProbe, GpuSceneGlobalIlluminationProbe, 0, g_minGpuSceneGlobalIlluminationProbesCVar)
+ANKI_CAT_TYPE(GlobalIlluminationProbe, GpuSceneGlobalIlluminationProbe, 0, g_cvarSceneMinGpuSceneGlobalIlluminationProbes)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(Decal, GpuSceneDecal, 0, g_minGpuSceneDecalsCVar)
+ANKI_CAT_TYPE(Decal, GpuSceneDecal, 0, g_cvarSceneMinGpuSceneDecals)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(FogDensityVolume, GpuSceneFogDensityVolume, 0, g_minGpuSceneFogDensityVolumesCVar)
+ANKI_CAT_TYPE(FogDensityVolume, GpuSceneFogDensityVolume, 0, g_cvarSceneMinGpuSceneFogDensityVolumes)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(Renderable, GpuSceneRenderable, 0, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_TYPE(Renderable, GpuSceneRenderable, 0, g_cvarSceneMinGpuSceneRenderables)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(RenderableBoundingVolumeGBuffer, GpuSceneRenderableBoundingVolume, 0, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_TYPE(RenderableBoundingVolumeGBuffer, GpuSceneRenderableBoundingVolume, 0, g_cvarSceneMinGpuSceneRenderables)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(RenderableBoundingVolumeForward, GpuSceneRenderableBoundingVolume, 1, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_TYPE(RenderableBoundingVolumeForward, GpuSceneRenderableBoundingVolume, 1, g_cvarSceneMinGpuSceneRenderables)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(RenderableBoundingVolumeDepth, GpuSceneRenderableBoundingVolume, 2, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_TYPE(RenderableBoundingVolumeDepth, GpuSceneRenderableBoundingVolume, 2, g_cvarSceneMinGpuSceneRenderables)
 ANKI_CAT_SEPARATOR
-ANKI_CAT_TYPE(RenderableBoundingVolumeRt, GpuSceneRenderableBoundingVolume, 3, g_minGpuSceneRenderablesCVar)
+ANKI_CAT_TYPE(RenderableBoundingVolumeRt, GpuSceneRenderableBoundingVolume, 3, g_cvarSceneMinGpuSceneRenderables)
 
 #undef ANKI_TRF_ARR
 #undef ANKI_MESH_ARR

+ 8 - 9
AnKi/Scene/SceneGraph.cpp

@@ -37,10 +37,9 @@
 
 namespace anki {
 
-static StatCounter g_sceneUpdateTimeStatVar(StatCategory::kTime, "All scene update",
-											StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
-static StatCounter g_sceneComponentsUpdatedStatVar(StatCategory::kScene, "Scene components updated per frame", StatFlag::kZeroEveryFrame);
-static StatCounter g_sceneNodesUpdatedStatVar(StatCategory::kScene, "Scene nodes updated per frame", StatFlag::kZeroEveryFrame);
+ANKI_SVAR(SceneUpdateTime, StatCategory::kTime, "All scene update", StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates)
+ANKI_SVAR(SceneComponentsUpdated, StatCategory::kScene, "Scene components updated per frame", StatFlag::kZeroEveryFrame)
+ANKI_SVAR(SceneNodesUpdated, StatCategory::kScene, "Scene nodes updated per frame", StatFlag::kZeroEveryFrame)
 
 constexpr U32 kUpdateNodeBatchSize = 10;
 
@@ -101,10 +100,10 @@ Error SceneGraph::init(AllocAlignedCallback allocCallback, void* allocCallbackDa
 	RenderStateBucketContainer::allocateSingleton();
 
 	// Construct a few common nodex
-	if(g_displayStatsCVar > 0)
+	if(g_cvarCoreDisplayStats > 0)
 	{
 		StatsUiNode* statsNode = newSceneNode<StatsUiNode>("_StatsUi");
-		statsNode->setFpsOnly(g_displayStatsCVar == 1);
+		statsNode->setFpsOnly(g_cvarCoreDisplayStats == 1);
 	}
 
 	newSceneNode<DeveloperConsoleUiNode>("_DevConsole");
@@ -234,7 +233,7 @@ void SceneGraph::update(Second prevUpdateTime, Second crntTime)
 #define ANKI_CAT_TYPE(arrayName, gpuSceneType, id, cvarName) GpuSceneArrays::arrayName::getSingleton().flush();
 #include <AnKi/Scene/GpuSceneArrays.def.h>
 
-	g_sceneUpdateTimeStatVar.set((HighRezTimer::getCurrentTime() - startUpdateTime) * 1000.0);
+	g_svarSceneUpdateTime.set((HighRezTimer::getCurrentTime() - startUpdateTime) * 1000.0);
 }
 
 void SceneGraph::updateNode(Second prevTime, Second crntTime, SceneNode& node)
@@ -270,8 +269,8 @@ void SceneGraph::updateNode(Second prevTime, Second crntTime, SceneNode& node)
 		if(sceneComponentUpdatedCount)
 		{
 			node.setComponentMaxTimestamp(GlobalFrameIndex::getSingleton().m_value);
-			g_sceneComponentsUpdatedStatVar.increment(sceneComponentUpdatedCount);
-			g_sceneNodesUpdatedStatVar.increment(1);
+			g_svarSceneComponentsUpdated.increment(sceneComponentUpdatedCount);
+			g_svarSceneNodesUpdated.increment(1);
 		}
 		else
 		{

+ 12 - 21
AnKi/Scene/SceneGraph.h

@@ -20,29 +20,20 @@ namespace anki {
 /// @addtogroup scene
 /// @{
 
-inline NumericCVar<F32> g_probeEffectiveDistanceCVar("Scene", "ProbeEffectiveDistance", 256.0f, 1.0f, kMaxF32, "How far various probes can render");
-inline NumericCVar<F32> g_probeShadowEffectiveDistanceCVar("Scene", "ProbeShadowEffectiveDistance", 32.0f, 1.0f, kMaxF32,
-														   "How far to render shadows for the various probes");
+ANKI_CVAR(NumericCVar<F32>, Scene, ProbeEffectiveDistance, 256.0f, 1.0f, kMaxF32, "How far various probes can render")
+ANKI_CVAR(NumericCVar<F32>, Scene, ProbeShadowEffectiveDistance, 32.0f, 1.0f, kMaxF32, "How far to render shadows for the various probes")
 
 // Gpu scene arrays
-inline NumericCVar<U32> g_minGpuSceneTransformsCVar("Scene", "MinGpuSceneTransforms", 2 * 10 * 1024, 8, 100 * 1024,
-													"The min number of transforms stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneMeshesCVar("Scene", "MinGpuSceneMeshes", 8 * 1024, 8, 100 * 1024,
-												"The min number of meshes stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneParticleEmittersCVar("Scene", "MinGpuSceneParticleEmitters", 1 * 1024, 8, 100 * 1024,
-														  "The min number of particle emitters stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneLightsCVar("Scene", "MinGpuSceneLights", 2 * 1024, 8, 100 * 1024,
-												"The min number of lights stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneReflectionProbesCVar("Scene", "MinGpuSceneReflectionProbes", 128, 8, 100 * 1024,
-														  "The min number of reflection probes stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneGlobalIlluminationProbesCVar("Scene", "MinGpuSceneGlobalIlluminationProbes", 128, 8, 100 * 1024,
-																  "The min number of GI probes stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneDecalsCVar("Scene", "MinGpuSceneDecals", 2 * 1024, 8, 100 * 1024,
-												"The min number of decals stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneFogDensityVolumesCVar("Scene", "MinGpuSceneFogDensityVolumes", 512, 8, 100 * 1024,
-														   "The min number fog density volumes stored in the GPU scene");
-inline NumericCVar<U32> g_minGpuSceneRenderablesCVar("Scene", "MinGpuSceneRenderables", 10 * 1024, 8, 100 * 1024,
-													 "The min number of renderables stored in the GPU scene");
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneTransforms, 2 * 10 * 1024, 8, 100 * 1024, "The min number of transforms stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneMeshes, 8 * 1024, 8, 100 * 1024, "The min number of meshes stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneParticleEmitters, 1 * 1024, 8, 100 * 1024,
+		  "The min number of particle emitters stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneLights, 2 * 1024, 8, 100 * 1024, "The min number of lights stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneReflectionProbes, 128, 8, 100 * 1024, "The min number of reflection probes stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneGlobalIlluminationProbes, 128, 8, 100 * 1024, "The min number of GI probes stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneDecals, 2 * 1024, 8, 100 * 1024, "The min number of decals stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneFogDensityVolumes, 512, 8, 100 * 1024, "The min number fog density volumes stored in the GPU scene")
+ANKI_CVAR(NumericCVar<U32>, Scene, MinGpuSceneRenderables, 10 * 1024, 8, 100 * 1024, "The min number of renderables stored in the GPU scene")
 
 class SceneComponentArrays
 {

+ 2 - 2
AnKi/Scene/StatsUiNode.cpp

@@ -156,9 +156,9 @@ void StatsUiNode::draw(CanvasPtr& canvas)
 		}
 		else
 		{
-			const Second maxTime = max(g_cpuTotalTimeStatVar.getValue<F64>(), g_rendererGpuTimeStatVar.getValue<F64>()) / 1000.0;
+			const Second maxTime = max(g_svarCpuTotalTime.getValue<F64>(), g_svarRendererGpuTime.getValue<F64>()) / 1000.0;
 			const F32 fps = F32(1.0 / maxTime);
-			const Bool cpuBound = g_cpuTotalTimeStatVar.getValue<F64>() > g_rendererGpuTimeStatVar.getValue<F64>();
+			const Bool cpuBound = g_svarCpuTotalTime.getValue<F64>() > g_svarRendererGpuTime.getValue<F64>();
 			ImGui::TextColored((cpuBound) ? Vec4(1.0f, 0.5f, 0.5f, 1.0f) : Vec4(0.5f, 1.0f, 0.5f, 1.0f), "FPS %.1f", fps);
 		}
 	}

+ 216 - 0
AnKi/Script/Globals.cpp

@@ -0,0 +1,216 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Script/LuaBinder.h>
+#include <AnKi/Script/ScriptManager.h>
+#include <AnKi/Util/CVarSet.h>
+
+namespace anki {
+
+static CVar* findCVar(CString name)
+{
+	CVar* foundCVar = nullptr;
+
+	CString prefix = "cvar";
+	const PtrSize pos = name.find(prefix);
+	if(name.getLength() > prefix.getLength() && pos == 0)
+	{
+		// Possibly a CVAR
+
+		CString cvarName = name.getBegin() + prefix.getLength();
+		CVarSet::getSingleton().iterateCVars([&](CVar& cvar) -> Bool {
+			ScriptString cvarName2 = cvar.getName();
+			cvarName2.replaceAll(".", "");
+
+			if(cvarName == cvarName2)
+			{
+				foundCVar = &cvar;
+				return true;
+			}
+
+			return false;
+		});
+	}
+
+	return foundCVar;
+}
+
+static inline int pwrap__newindex(lua_State* l)
+{
+	if(LuaBinder::checkArgsCount(l, 3))
+	{
+		return -1;
+	}
+
+	const Char* varName_;
+	if(LuaBinder::checkString(l, 2, varName_))
+	{
+		return -1;
+	}
+	CString varName(varName_);
+
+	CVar* cvar = findCVar(varName);
+	if(cvar)
+	{
+		// Found
+
+#define ANKI_CVAR_NUMERIC_TYPE(type) \
+	case CVarValueType::kNumeric##type: \
+	{ \
+		type val; \
+		if(LuaBinder::checkNumber(l, 3, val)) \
+		{ \
+			return -1; \
+		} \
+		static_cast<NumericCVar<type>&>(*cvar) = val; \
+	} \
+	break;
+
+		switch(cvar->getValueType())
+		{
+		case CVarValueType::kString:
+		{
+			const Char* val;
+			if(LuaBinder::checkString(l, 3, val))
+			{
+				return -1;
+			}
+			static_cast<StringCVar&>(*cvar) = val;
+		}
+		break;
+		case CVarValueType::kBool:
+		{
+			I32 val;
+			if(LuaBinder::checkNumber(l, 3, val))
+			{
+				return -1;
+			}
+			static_cast<BoolCVar&>(*cvar) = val;
+		}
+		break;
+			ANKI_CVAR_NUMERIC_TYPE(U8)
+			ANKI_CVAR_NUMERIC_TYPE(U16)
+			ANKI_CVAR_NUMERIC_TYPE(U32)
+			ANKI_CVAR_NUMERIC_TYPE(PtrSize)
+			ANKI_CVAR_NUMERIC_TYPE(F32)
+			ANKI_CVAR_NUMERIC_TYPE(F64)
+		default:
+			ANKI_ASSERT(0);
+		}
+
+#undef ANKI_CVAR_NUMERIC_TYPE
+	}
+	else
+	{
+		ANKI_SCRIPT_LOGE("Global variable not found: %s", varName.cstr());
+		return -1;
+	}
+
+	return 0;
+}
+
+static int wrap__newindex(lua_State* l)
+{
+	const int res = pwrap__newindex(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+static inline int pwrap__index(lua_State* l)
+{
+	if(LuaBinder::checkArgsCount(l, 2))
+	{
+		return -1;
+	}
+
+	const Char* varName_;
+	if(LuaBinder::checkString(l, 2, varName_))
+	{
+		return -1;
+	}
+	CString varName(varName_);
+
+	CVar* cvar = findCVar(varName);
+	if(cvar)
+	{
+		// Found
+
+#define ANKI_CVAR_NUMERIC_TYPE(type) \
+	case CVarValueType::kNumeric##type: \
+	{ \
+		lua_pushnumber(l, lua_Number(static_cast<NumericCVar<type>&>(*cvar))); \
+	} \
+	break;
+
+		switch(cvar->getValueType())
+		{
+		case CVarValueType::kString:
+		{
+			lua_pushstring(l, CString(static_cast<StringCVar&>(*cvar)).cstr());
+		}
+		break;
+		case CVarValueType::kBool:
+		{
+			lua_pushnumber(l, static_cast<BoolCVar&>(*cvar));
+		}
+		break;
+			ANKI_CVAR_NUMERIC_TYPE(U8)
+			ANKI_CVAR_NUMERIC_TYPE(U16)
+			ANKI_CVAR_NUMERIC_TYPE(U32)
+			ANKI_CVAR_NUMERIC_TYPE(PtrSize)
+			ANKI_CVAR_NUMERIC_TYPE(F32)
+			ANKI_CVAR_NUMERIC_TYPE(F64)
+		default:
+			ANKI_ASSERT(0);
+		}
+
+#undef ANKI_CVAR_NUMERIC_TYPE
+	}
+	else
+	{
+		ANKI_SCRIPT_LOGE("Global variable not found: %s", varName.cstr());
+		return -1;
+	}
+
+	return 1;
+}
+
+static int wrap__index(lua_State* l)
+{
+	const int res = pwrap__index(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+void wrapModuleGlobals(lua_State* l)
+{
+	lua_newtable(l); // push table
+
+	lua_newtable(l); // push meta_table
+
+	lua_pushcfunction(l, wrap__index); // push func
+	lua_setfield(l, -2, "__index"); // meta_table[__index] = stack[-2] and pop func
+
+	lua_pushcfunction(l, wrap__newindex); // push func
+	lua_setfield(l, -2, "__newindex"); // meta_table[__newindex] = stack[-2] and pop func
+
+	lua_setmetatable(l, -2); // setmetatable(table, meta_table) and pop meta_table
+
+	lua_setglobal(l, "g"); // setglobal(table, "g") and pop table
+
+	lua_settop(l, 0);
+}
+
+} // namespace anki

+ 2 - 0
AnKi/Script/LuaBinder.cpp

@@ -15,6 +15,7 @@ ANKI_SCRIPT_CALL_WRAP(Logger);
 ANKI_SCRIPT_CALL_WRAP(Math);
 ANKI_SCRIPT_CALL_WRAP(Renderer);
 ANKI_SCRIPT_CALL_WRAP(Scene);
+ANKI_SCRIPT_CALL_WRAP(Globals);
 #undef ANKI_SCRIPT_CALL_WRAP
 
 static void wrapModules(lua_State* l)
@@ -24,6 +25,7 @@ static void wrapModules(lua_State* l)
 	ANKI_SCRIPT_CALL_WRAP(Math);
 	ANKI_SCRIPT_CALL_WRAP(Renderer);
 	ANKI_SCRIPT_CALL_WRAP(Scene);
+	ANKI_SCRIPT_CALL_WRAP(Globals);
 #undef ANKI_SCRIPT_CALL_WRAP
 }
 

+ 2 - 1
AnKi/Ui/Font.cpp

@@ -30,7 +30,7 @@ Error Font::init(const CString& filename, ConstWeakArray<U32> fontHeights)
 	m_fontData.resize(U32(file->getSize()));
 	ANKI_CHECK(file->read(&m_fontData[0], file->getSize()));
 
-	m_fonts.resize(U32(fontHeights.getSize()));
+	m_fonts.resize(fontHeights.getSize());
 
 	// Bake font
 	ImFontConfig cfg;
@@ -38,6 +38,7 @@ Error Font::init(const CString& filename, ConstWeakArray<U32> fontHeights)
 	U32 count = 0;
 	for(U32 height : fontHeights)
 	{
+		height = U32(F32(height) * g_cvarUiGlobalFontScale) + g_cvarUiGlobalFontBias;
 		cfg.SizePixels = F32(height);
 
 		m_fonts[count].m_imFont = m_imFontAtlas->AddFontFromMemoryTTF(&m_fontData[0], I32(m_fontData.getSize()), F32(height), &cfg);

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