graphics: honor CPU ownership in image dirty-region queries

This commit is contained in:
nmzik
2026-09-28 21:34:07 +04:00
parent 6ee1bf9db0
commit 8e61798bfd
2 changed files with 28 additions and 8 deletions
+4 -1
View File
@@ -1867,7 +1867,10 @@ bool TextureCache::IsRegionGpuModified(uint64_t address, uint64_t size) {
std::scoped_lock lock {m_lock}; std::scoped_lock lock {m_lock};
for (const auto id: FindImagesInRegion(address, size, false)) { for (const auto id: FindImagesInRegion(address, size, false)) {
const auto& image = m_slot_images[id]; const auto& image = m_slot_images[id];
if (!image.depth_id && image.IsGpuModified()) { // PPSA17168: S_LOAD_DWORD reads shader data at an address overlapping an old
// render target whose memory the CPU has reused. The cached image still retains
// its earlier GPU-modified flag.
if (!image.depth_id && image.IsGpuModified() && !image.IsDefinitelyCpuDirty()) {
return true; return true;
} }
} }
+24 -7
View File
@@ -6169,7 +6169,11 @@ public:
!texture_cache.GetImage(fault_a_image).IsTracked() && !texture_cache.GetImage(fault_a_image).IsTracked() &&
!texture_cache.GetImage(fault_b_image).IsTracked() && !texture_cache.GetImage(fault_b_image).IsTracked() &&
texture_cache.GetImage(fault_a_image).IsMaybeCpuDirty() && texture_cache.GetImage(fault_a_image).IsMaybeCpuDirty() &&
texture_cache.GetImage(fault_b_image).IsMaybeCpuDirty(), texture_cache.GetImage(fault_b_image).IsMaybeCpuDirty() &&
texture_cache.IsRegionGpuModified(base + 0x8000,
sizeof(fault_a)) &&
texture_cache.IsRegionGpuModified(base + 0x8010,
sizeof(fault_b)),
"a byte-disjoint CPU write discarded authoritative images"); "a byte-disjoint CPU write discarded authoritative images");
const auto retracked_a = texture_cache.FindImage(fault_a_desc); const auto retracked_a = texture_cache.FindImage(fault_a_desc);
const auto retracked_b = texture_cache.FindImage(fault_b_desc); const auto retracked_b = texture_cache.FindImage(fault_b_desc);
@@ -7346,18 +7350,31 @@ public:
Require(name, "GPU image range validity", Require(name, "GPU image range validity",
texture_cache.FindImageFromRange( texture_cache.FindImageFromRange(
gc_image_desc_a.info.data.address, gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size) == gc_images[0], gc_image_desc_a.info.data.size) == gc_images[0] &&
texture_cache.IsRegionGpuModified(
gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size),
"FindImageFromRange rejected a clean GPU-current image"); "FindImageFromRange rejected a clean GPU-current image");
texture_cache.GetImage(gc_images[0]) auto &gc_native = texture_cache.GetImage(gc_images[0]);
.InvalidateCpuWrite(gc_image_desc_a.info.data.address, texture_cache.InvalidateMemory(gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size); gc_image_desc_a.info.data.size);
Require( Require(
name, "CPU-dirty image range validity", name, "CPU-dirty image range validity",
!texture_cache.FindImageFromRange(gc_image_desc_a.info.data.address, !texture_cache.FindImageFromRange(gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size) && gc_image_desc_a.info.data.size) &&
!TextureCacheTestAccess::TryDownload(texture_cache, gc_images[0]), !TextureCacheTestAccess::TryDownload(texture_cache, gc_images[0]) &&
"CPU-dirty native contents remained eligible for image readback"); !texture_cache.IsRegionGpuModified(
gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size) &&
gc_native.IsDefinitelyCpuDirty() && gc_native.IsGpuModified() &&
!gc_native.IsTracked(),
"CPU writes did not supersede native contents while retaining GPU history");
texture_cache.MarkGpuWritten(gc_images[0]); texture_cache.MarkGpuWritten(gc_images[0]);
Require(name, "GPU image reacquisition",
texture_cache.IsRegionGpuModified(
gc_image_desc_a.info.data.address,
gc_image_desc_a.info.data.size),
"a new GPU write did not reclaim image authority");
for (size_t index = 0; index < gc_image_offsets.size(); index++) { for (size_t index = 0; index < gc_image_offsets.size(); index++) {
Libs::LibKernel::Memory::WriteBacking(base + gc_image_offsets[index], Libs::LibKernel::Memory::WriteBacking(base + gc_image_offsets[index],
&gc_stale_values[index], &gc_stale_values[index],