From 0a24aa6af26cc55c079e265a071a42569d28d2c0 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 22 Feb 2022 13:34:16 -0300
Subject: Allow textures to have their data partially mapped (#2629)

* Allow textures to have their data partially mapped

* Explicitly check for invalid memory ranges on the MultiRangeList

* Update GetWritableRegion to also support unmapped ranges
---
 Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 57 +++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 12 deletions(-)

(limited to 'Ryujinx.Graphics.Gpu/Image/TextureCache.cs')

diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 203a3a12..89ad8aa0 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -40,6 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         private readonly PhysicalMemory _physicalMemory;
 
         private readonly MultiRangeList<Texture> _textures;
+        private readonly HashSet<Texture> _partiallyMappedTextures;
 
         private Texture[] _textureOverlaps;
         private OverlapInfo[] _overlapInfo;
@@ -57,6 +58,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             _physicalMemory = physicalMemory;
 
             _textures = new MultiRangeList<Texture>();
+            _partiallyMappedTextures = new HashSet<Texture>();
 
             _textureOverlaps = new Texture[OverlapsBufferInitialCapacity];
             _overlapInfo = new OverlapInfo[OverlapsBufferInitialCapacity];
@@ -74,17 +76,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             Texture[] overlaps = new Texture[10];
             int overlapCount;
 
-            MultiRange unmapped;
-
-            try
-            {
-                unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
-            }
-            catch (InvalidMemoryRegionException)
-            {
-                // This event fires on Map in case any mappings are overwritten. In that case, there may not be an existing mapping.
-                return;
-            }
+            MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
 
             lock (_textures)
             {
@@ -95,6 +87,24 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 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++)
+            {
+                if (unmapped.GetSubRange(i).Address == MemoryManager.PteUnmapped)
+                {
+                    lock (_partiallyMappedTextures)
+                    {
+                        foreach (var texture in _partiallyMappedTextures)
+                        {
+                            texture.Unmapped(unmapped);
+                        }
+                    }
+
+                    break;
+                }
+            }
         }
 
         /// <summary>
@@ -495,10 +505,20 @@ namespace Ryujinx.Graphics.Gpu.Image
             SizeInfo sizeInfo = info.CalculateSizeInfo(layerSize);
 
             ulong size = (ulong)sizeInfo.TotalSize;
+            bool partiallyMapped = false;
 
             if (range == null)
             {
                 range = memoryManager.GetPhysicalRegions(info.GpuAddress, size);
+
+                for (int i = 0; i < range.Value.Count; i++)
+                {
+                    if (range.Value.GetSubRange(i).Address == MemoryManager.PteUnmapped)
+                    {
+                        partiallyMapped = true;
+                        break;
+                    }
+                }
             }
 
             // Find view compatible matches.
@@ -668,7 +688,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                     else
                     {
                         bool dataOverlaps = texture.DataOverlaps(overlap, compatibility);
-                        
+
                         if (!overlap.IsView && dataOverlaps && !incompatibleOverlaps.Exists(incompatible => incompatible.Group == overlap.Group))
                         {
                             incompatibleOverlaps.Add(new TextureIncompatibleOverlap(overlap.Group, compatibility));
@@ -784,6 +804,14 @@ namespace Ryujinx.Graphics.Gpu.Image
                 _textures.Add(texture);
             }
 
+            if (partiallyMapped)
+            {
+                lock (_partiallyMappedTextures)
+                {
+                    _partiallyMappedTextures.Add(texture);
+                }
+            }
+
             ShrinkOverlapsBufferIfNeeded();
 
             for (int i = 0; i < overlapsCount; i++)
@@ -1079,6 +1107,11 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 _textures.Remove(texture);
             }
+
+            lock (_partiallyMappedTextures)
+            {
+                _partiallyMappedTextures.Remove(texture);
+            }
         }
 
         /// <summary>
-- 
cgit v1.2.3-70-g09d2