graphics: unwatch image heap pages on writes next to a table

This commit is contained in:
nmzik
2026-10-25 03:50:55 +01:00
parent 597137e8b1
commit 463a096249
2 changed files with 16 additions and 3 deletions
@@ -254,10 +254,12 @@ void ImageHeap::Unwatch(const Memory& memory) {
void ImageHeap::InvalidateMemory(uint64_t address, uint64_t size) {
std::scoped_lock lock {m_mutex};
for (auto& memory: m_memories) {
const auto begin = std::max(address, memory->base);
const auto end = std::min(address + size, memory->base + memory->size);
if (begin >= end) continue;
// Watches cover whole pages, so a write next to the table must unwatch its page too.
const auto origin = Common::AlignDown(memory->base, TRACKER_PAGE_SIZE);
const auto begin = std::max(address, origin);
const auto end = std::min(address + size,
origin + memory->dirty_pages.size() * TRACKER_PAGE_SIZE);
if (begin >= end) continue;
MarkDirty(*memory, (begin - origin) / TRACKER_PAGE_SIZE,
(end - 1u - origin) / TRACKER_PAGE_SIZE + 1u);
}
+11
View File
@@ -242,6 +242,10 @@ struct ImageHeapTestAccess {
static ImageId ImageOf(const ImageHeap &heap, uint32_t entry) {
return Element(heap, entry).binding.image_id;
}
// Whether the newest table no longer watches its last page.
static bool TailPageDirty(const ImageHeap &heap) {
return heap.m_memories.back()->dirty_pages.back() != 0u;
}
};
struct TextureCacheTestAccess {
@@ -5518,6 +5522,13 @@ public:
acquire(sampled, idle_table) && view.kinds.empty() &&
ImageHeapTestAccess::MemoryCount(heap) == 1u,
"an all-null table was not kept resident");
// A write past a table's end, in its watched tail page, must unwatch the page.
constexpr uint64_t unaligned_table = base + 0x1a0800;
Require(name, "tail page fault",
acquire(sampled, unaligned_table) &&
context.HandleFault(PageFaultAccess::Write, unaligned_table + table_size) &&
ImageHeapTestAccess::TailPageDirty(heap),
"a write fault next to a table left its page watched");
draw();
context.UnmapMemory(base, idle_table - base);
scheduler.Finish();