#pragma once #include #include #include namespace mln::particle { // Debug/Validation-only cumulative renderer observability. These atomics are // intentionally not connected to Host APIs and compile to no-ops in release. enum class RendererDebugCounter : uint8_t { WeatherColorNeedsRepaint, ParticleNeedsRepaint, WeatherColorUpdate, ParticleUpdate, ParticleSimulationAdvance, WeatherColorDrawableRebuild, ParticleDrawableRebuild, FieldTextureUpload, GpuResourceCreate, GpuResourceRelease, TrailTargetCreateOrResize, V4ProjectionMaterialize, FieldWindowRevision, FullRendererFrame, RetainedUnderlayBuild, RetainedUnderlayReuse, RetainedUnderlayFallback, RetainedUnderlayInvalidation, RetainedUnderlayStaticGroupDraw, RetainedDynamicGroupDraw, ParticleFastFrameHit, ParticleFastFrameMiss, ParticleFullFrame, Count, }; #ifndef NDEBUG struct RendererDebugCounterSnapshot { uint64_t weatherColorNeedsRepaint = 0; uint64_t particleNeedsRepaint = 0; uint64_t weatherColorUpdate = 0; uint64_t particleUpdate = 0; uint64_t particleSimulationAdvance = 0; uint64_t weatherColorDrawableRebuild = 0; uint64_t particleDrawableRebuild = 0; uint64_t fieldTextureUpload = 0; uint64_t gpuResourceCreate = 0; uint64_t gpuResourceRelease = 0; uint64_t trailTargetCreateOrResize = 0; uint64_t v4ProjectionMaterialize = 0; uint64_t fieldWindowRevision = 0; uint64_t fullRendererFrame = 0; uint64_t retainedUnderlayBuild = 0; uint64_t retainedUnderlayReuse = 0; uint64_t retainedUnderlayFallback = 0; uint64_t retainedUnderlayInvalidation = 0; uint64_t retainedUnderlayStaticGroupDraw = 0; uint64_t retainedDynamicGroupDraw = 0; uint64_t particleFastFrameHit = 0; uint64_t particleFastFrameMiss = 0; uint64_t particleFullFrame = 0; }; inline std::atomic_uint64_t* rendererDebugCounterStorage() { static std::atomic_uint64_t counters[static_cast(RendererDebugCounter::Count)]{}; return counters; } inline void incrementRendererDebugCounter(const RendererDebugCounter counter) { rendererDebugCounterStorage()[static_cast(counter)].fetch_add(1, std::memory_order_relaxed); } inline RendererDebugCounterSnapshot rendererDebugCounterSnapshot() { const auto* values = rendererDebugCounterStorage(); RendererDebugCounterSnapshot result; #define MLN_LOAD_RENDERER_COUNTER(field, counter) \ result.field = values[static_cast(RendererDebugCounter::counter)].load(std::memory_order_relaxed) MLN_LOAD_RENDERER_COUNTER(weatherColorNeedsRepaint, WeatherColorNeedsRepaint); MLN_LOAD_RENDERER_COUNTER(particleNeedsRepaint, ParticleNeedsRepaint); MLN_LOAD_RENDERER_COUNTER(weatherColorUpdate, WeatherColorUpdate); MLN_LOAD_RENDERER_COUNTER(particleUpdate, ParticleUpdate); MLN_LOAD_RENDERER_COUNTER(particleSimulationAdvance, ParticleSimulationAdvance); MLN_LOAD_RENDERER_COUNTER(weatherColorDrawableRebuild, WeatherColorDrawableRebuild); MLN_LOAD_RENDERER_COUNTER(particleDrawableRebuild, ParticleDrawableRebuild); MLN_LOAD_RENDERER_COUNTER(fieldTextureUpload, FieldTextureUpload); MLN_LOAD_RENDERER_COUNTER(gpuResourceCreate, GpuResourceCreate); MLN_LOAD_RENDERER_COUNTER(gpuResourceRelease, GpuResourceRelease); MLN_LOAD_RENDERER_COUNTER(trailTargetCreateOrResize, TrailTargetCreateOrResize); MLN_LOAD_RENDERER_COUNTER(v4ProjectionMaterialize, V4ProjectionMaterialize); MLN_LOAD_RENDERER_COUNTER(fieldWindowRevision, FieldWindowRevision); MLN_LOAD_RENDERER_COUNTER(fullRendererFrame, FullRendererFrame); MLN_LOAD_RENDERER_COUNTER(retainedUnderlayBuild, RetainedUnderlayBuild); MLN_LOAD_RENDERER_COUNTER(retainedUnderlayReuse, RetainedUnderlayReuse); MLN_LOAD_RENDERER_COUNTER(retainedUnderlayFallback, RetainedUnderlayFallback); MLN_LOAD_RENDERER_COUNTER(retainedUnderlayInvalidation, RetainedUnderlayInvalidation); MLN_LOAD_RENDERER_COUNTER(retainedUnderlayStaticGroupDraw, RetainedUnderlayStaticGroupDraw); MLN_LOAD_RENDERER_COUNTER(retainedDynamicGroupDraw, RetainedDynamicGroupDraw); MLN_LOAD_RENDERER_COUNTER(particleFastFrameHit, ParticleFastFrameHit); MLN_LOAD_RENDERER_COUNTER(particleFastFrameMiss, ParticleFastFrameMiss); MLN_LOAD_RENDERER_COUNTER(particleFullFrame, ParticleFullFrame); #undef MLN_LOAD_RENDERER_COUNTER return result; } #else inline void incrementRendererDebugCounter(RendererDebugCounter) {} #endif } // namespace mln::particle