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
This commit is contained in:
parent
680e548022
commit
36f10df775
7 changed files with 135 additions and 19 deletions
|
@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles removal of textures written to a memory region being unmapped.
|
||||
/// Handles marking of textures written to a memory region being (partially) remapped.
|
||||
/// </summary>
|
||||
/// <param name="sender">Sender object</param>
|
||||
/// <param name="e">Event arguments</param>
|
||||
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
|
||||
/// <param name="address">The virtual address of the texture</param>
|
||||
/// <param name="texture">The texture to be marked</param>
|
||||
/// <returns>The physical regions for the texture, found when evaluating whether the texture was partially mapped</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a texture to the short duration cache. This typically keeps it alive for two ticks.
|
||||
/// </summary>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue