diff --git a/src/common/debugCounters.h b/src/common/debugCounters.h index cf4e96b84..5d346da28 100644 --- a/src/common/debugCounters.h +++ b/src/common/debugCounters.h @@ -29,6 +29,8 @@ enum class Counter { TextureUploadBytes, TextureDownloadBytes, TextureEvictions, + ColorMetadataReadbacks, // CPU blocked reading back GPU-written DCC/CMASK metadata. + ColorMetadataReadbackNs, BufferUploadBytes, BufferDownloadBytes, BufferEvictions, diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 6a95f07e4..8c834e368 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -1070,6 +1070,9 @@ void TextureCache::MaterializeColorClear(ImageId id, const ImageDesc& desc, // Finish native metadata writes before reading backing bytes. This can submit the scheduler, // so discovery runs before final draw uploads and never holds the texture lock across it. if (m_buffer_cache.IsRegionGpuModified(range.address, range.size)) { + Common::DebugCounters::ScopedTimer timer( + Common::DebugCounters::Counter::ColorMetadataReadbacks, + Common::DebugCounters::Counter::ColorMetadataReadbackNs); m_buffer_cache.ReadMemory(range.address, range.size, false); } const auto slice_size = range.size / layers; diff --git a/src/graphics/presentation/performanceOverlay.cpp b/src/graphics/presentation/performanceOverlay.cpp index ac8da4cc9..1f8a71d6b 100644 --- a/src/graphics/presentation/performanceOverlay.cpp +++ b/src/graphics/presentation/performanceOverlay.cpp @@ -310,6 +310,9 @@ void GpuActivityRows(const Snapshot& shown) { Row("CPU waiting on GPU", Fmt("%.0f ms/s (%.0f waits/s)", Rate(shown, Counter::GpuWaitNs) / 1e6, Rate(shown, Counter::GpuWaits))); + Row("DCC/CMASK readbacks", + Fmt("%.0f ms/s (%.0f/s)", Rate(shown, Counter::ColorMetadataReadbackNs) / 1e6, + Rate(shown, Counter::ColorMetadataReadbacks))); } void CompilationRows(const Snapshot& shown) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 40551da77..394013afa 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -1,6 +1,7 @@ #define SPV_ENABLE_UTILITY_CODE #include "common/assert.h" +#include "common/debugCounters.h" #include "common/emulatorConfig.h" #include "common/file.h" #include "common/hostException.h" @@ -12266,7 +12267,15 @@ public: Require(name, "already GPU-owned metadata stays ordered", resources.GetBufferCache().HasGpuDirtyBytes(dcc_address, metadata_size), "a fill discarded pending native writes to its metadata pages"); + Common::DebugCounters::SetEnabled(true); + const auto readbacks = + Common::DebugCounters::Get(Common::DebugCounters::Counter::ColorMetadataReadbacks); bind(); + Common::DebugCounters::SetEnabled(false); + Require(name, "metadata readback counter", + Common::DebugCounters::Get( + Common::DebugCounters::Counter::ColorMetadataReadbacks) == readbacks + 1, + "binding GPU-written metadata did not count exactly one readback"); Require(name, "same-value raw native re-clear", read_texel() == expected, "a repeated metadata fill did not clear an already drawn target");