From 36f10df775cf0c678548b97346432095823dfd8a Mon Sep 17 00:00:00 2001 From: riperiperi Date: Mon, 1 May 2023 19:32:32 +0100 Subject: GPU: Fix errors handling texture remapping (#4745) * GPU: Fix errors handling texture remapping - Fixes an error where a pool entry and memory mapping changing at the same time could cause a texture to rebind its data from the wrong GPU VA (data swaps) - Fixes an error where the texture pool could act on a mapping change before the mapping has actually been changed ("Unmapped" event happens before change, we need to signal it changed _after_ it completes) TODO: remove textures from partially mapped list... if they aren't. * Add Remap actions for handling post-mapping behaviours * Remove unused code. * Address feedback * Nit --- src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 79 +++++++++++++++++++++----- 1 file changed, 66 insertions(+), 13 deletions(-) (limited to 'src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs') diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index c3243cf2..97d78a34 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Gpu.Image } /// - /// Handles removal of textures written to a memory region being unmapped. + /// Handles marking of textures written to a memory region being (partially) remapped. /// /// Sender object /// Event arguments @@ -80,26 +80,41 @@ namespace Ryujinx.Graphics.Gpu.Image overlapCount = _textures.FindOverlaps(unmapped, ref overlaps); } - for (int i = 0; i < overlapCount; i++) + if (overlapCount > 0) { - overlaps[i].Unmapped(unmapped); + for (int i = 0; i < overlapCount; i++) + { + overlaps[i].Unmapped(unmapped); + } } - // If any range was previously unmapped, we also need to purge - // all partially mapped texture, as they might be fully mapped now. - for (int i = 0; i < unmapped.Count; i++) + lock (_partiallyMappedTextures) { - if (unmapped.GetSubRange(i).Address == MemoryManager.PteUnmapped) + if (overlapCount > 0 || _partiallyMappedTextures.Count > 0) { - lock (_partiallyMappedTextures) + e.AddRemapAction(() => { - foreach (var texture in _partiallyMappedTextures) + lock (_partiallyMappedTextures) { - texture.Unmapped(unmapped); - } - } + if (overlapCount > 0) + { + for (int i = 0; i < overlapCount; i++) + { + _partiallyMappedTextures.Add(overlaps[i]); + } + } - break; + // Any texture that has been unmapped at any point or is partially unmapped + // should update their pool references after the remap completes. + + MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size); + + foreach (var texture in _partiallyMappedTextures) + { + texture.UpdatePoolMappings(); + } + } + }); } } } @@ -1135,6 +1150,44 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Queries a texture's memory range and marks it as partially mapped or not. + /// Partially mapped textures re-evaluate their memory range after each time GPU memory is mapped. + /// + /// GPU memory manager where the texture is mapped + /// The virtual address of the texture + /// The texture to be marked + /// The physical regions for the texture, found when evaluating whether the texture was partially mapped + public MultiRange UpdatePartiallyMapped(MemoryManager memoryManager, ulong address, Texture texture) + { + MultiRange range; + lock (_partiallyMappedTextures) + { + range = memoryManager.GetPhysicalRegions(address, texture.Size); + bool partiallyMapped = false; + + for (int i = 0; i < range.Count; i++) + { + if (range.GetSubRange(i).Address == MemoryManager.PteUnmapped) + { + partiallyMapped = true; + break; + } + } + + if (partiallyMapped) + { + _partiallyMappedTextures.Add(texture); + } + else + { + _partiallyMappedTextures.Remove(texture); + } + } + + return range; + } + /// /// Adds a texture to the short duration cache. This typically keeps it alive for two ticks. /// -- cgit v1.2.3