From cb378365e160e1762fb39d3f1c39a462a9b77208 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 23 Aug 2026 17:38:31 +0200 Subject: [PATCH] renderer: avoid allocating for dirty range probes --- src/graphics/host_gpu/rangeSet.h | 9 +++++++++ .../host_gpu/renderer/cache/bufferCache.cpp | 15 ++++++--------- tests/MemoryTrackerTests.cpp | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/graphics/host_gpu/rangeSet.h b/src/graphics/host_gpu/rangeSet.h index 6a96cf55b..e22ade453 100644 --- a/src/graphics/host_gpu/rangeSet.h +++ b/src/graphics/host_gpu/rangeSet.h @@ -59,6 +59,15 @@ public: return result; } + [[nodiscard]] bool Intersects(uint64_t address, uint64_t size) const { + const auto end = End(address, size); + auto it = m_ranges.lower_bound(address); + if (it != m_ranges.begin() && std::prev(it)->second > address) { + return true; + } + return it != m_ranges.end() && it->first < end; + } + [[nodiscard]] bool Contains(uint64_t address, uint64_t size) const { const auto end = End(address, size); auto it = m_ranges.upper_bound(address); diff --git a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp index 3d4da6bcb..24134f0c1 100644 --- a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp @@ -167,7 +167,7 @@ void BufferCache::QueueGarbageDownload(std::span copies, Buf // query therefore cannot orphan a dirty sibling on an edge page. m_memory_tracker.UnmarkRegionAsGpuModified(address, size); if (m_memory_tracker.IsRegionGpuModified(address, size) || - !m_gpu_modified_ranges.Intersections(address, size).empty()) { + m_gpu_modified_ranges.Intersects(address, size)) { EXIT("BufferCache: asynchronous garbage collection retained GPU ownership\n"); } m_memory_tracker.UntrackMemory(address, size); @@ -314,8 +314,7 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) { !m_memory_tracker.IsRegionGpuModified(begin, buffer.Size())) { continue; } - const auto dirty = m_gpu_modified_ranges.Intersections(begin, buffer.Size()); - if (dirty.empty()) { + if (!m_gpu_modified_ranges.Intersects(begin, buffer.Size())) { EXIT("BufferCache: GPU-modified buffer has no dirty ranges\n"); } modified_buffers.emplace_back(begin, buffer.Size()); @@ -350,7 +349,7 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) { for (const auto& [begin, bytes]: retired_buffers) { m_memory_tracker.MarkRegionAsCpuModified(begin, bytes); } - if (!m_gpu_modified_ranges.Intersections(vaddr, size).empty()) { + if (m_gpu_modified_ranges.Intersects(vaddr, size)) { EXIT("BufferCache: unmap retained dirty byte ranges\n"); } m_memory_tracker.UntrackMemory(vaddr, size); @@ -557,8 +556,7 @@ std::pair BufferCache::ObtainBufferForImage(uint64_t vaddr, u { const bool cpu_modified = m_memory_tracker.IsRegionCpuModified(vaddr, size); const bool gpu_modified = m_memory_tracker.IsRegionGpuModified(vaddr, size); - const auto dirty = m_gpu_modified_ranges.Intersections(vaddr, size); - const bool has_dirty_buffer_source = !dirty.empty(); + const bool has_dirty_buffer_source = m_gpu_modified_ranges.Intersects(vaddr, size); m_memory_tracker.ValidateGpuDirtyOwnership(m_gpu_modified_ranges, vaddr, size, "image source"); @@ -592,8 +590,7 @@ std::pair BufferCache::ObtainBufferForImage(uint64_t vaddr, u } m_staging_buffer.Commit(); - const auto dirty = m_gpu_modified_ranges.Intersections(vaddr, size); - const bool has_dirty_buffer_source = !dirty.empty(); + const bool has_dirty_buffer_source = m_gpu_modified_ranges.Intersects(vaddr, size); auto* owner = find_owner(); if (has_dirty_buffer_source && owner == nullptr) { EXIT("BufferCache: GPU-dirty image source lost its native owner\n"); @@ -756,7 +753,7 @@ bool BufferCache::IsRegionGpuModified(uint64_t vaddr, uint64_t size) { } bool BufferCache::HasGpuDirtyBytes(uint64_t vaddr, uint64_t size) { - return !m_gpu_modified_ranges.Intersections(vaddr, size).empty(); + return m_gpu_modified_ranges.Intersects(vaddr, size); } bool BufferCache::IsRegionCpuModified(uint64_t vaddr, uint64_t size) { diff --git a/tests/MemoryTrackerTests.cpp b/tests/MemoryTrackerTests.cpp index a34408c01..994cac14d 100644 --- a/tests/MemoryTrackerTests.cpp +++ b/tests/MemoryTrackerTests.cpp @@ -191,6 +191,10 @@ void TestRangeSet() { ranges.Add(0x1200, 0x40); Check(ranges.Contains(0x1010, 0xe0) && !ranges.Contains(0x1010, 0x200), "range set containment did not require full coverage"); + Check(ranges.Intersects(0x0fff, 2) && ranges.Intersects(0x11ff, 2) && + !ranges.Intersects(0x1100, 0x100) && + !ranges.Intersects(0x1240, 1), + "range set intersection did not preserve half-open boundaries"); auto intersections = ranges.Intersections(0x1070, 0x1b0); Check(intersections.size() == 2 && intersections[0].address == 0x1070 && intersections[0].size == 0x90 &&