From fbb4019ed5c12c4a888c7b09db648ac595366896 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 29 Jun 2021 14:32:02 -0300
Subject: Initial support for separate GPU address spaces (#2394)

* Make GPU memory manager a member of GPU channel

* Move physical memory instance to the memory manager, and the caches to the physical memory

* PR feedback
---
 Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 86 ++++++++++++++++++++----------
 1 file changed, 58 insertions(+), 28 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 24fa723a..37a2219f 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         private const int OverlapsBufferMaxCapacity     = 10000;
 
         private readonly GpuContext _context;
+        private readonly PhysicalMemory _physicalMemory;
 
         private readonly MultiRangeList<Texture> _textures;
 
@@ -44,9 +45,11 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// Constructs a new instance of the texture manager.
         /// </summary>
         /// <param name="context">The GPU context that the texture manager belongs to</param>
-        public TextureCache(GpuContext context)
+        /// <param name="physicalMemory">Physical memory where the textures managed by this cache are mapped</param>
+        public TextureCache(GpuContext context, PhysicalMemory physicalMemory)
         {
             _context = context;
+            _physicalMemory = physicalMemory;
 
             _textures = new MultiRangeList<Texture>();
 
@@ -68,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             lock (_textures)
             {
-                overlapCount = _textures.FindOverlaps(_context.MemoryManager.Translate(e.Address), e.Size, ref overlaps);
+                overlapCount = _textures.FindOverlaps(((MemoryManager)sender).Translate(e.Address), e.Size, ref overlaps);
             }
 
             for (int i = 0; i < overlapCount; i++)
@@ -139,13 +142,20 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// Tries to find an existing texture, or create a new one if not found.
         /// </summary>
+        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="copyTexture">Copy texture to find or create</param>
         /// <param name="offset">Offset to be added to the physical texture address</param>
         /// <param name="formatInfo">Format information of the copy texture</param>
         /// <param name="preferScaling">Indicates if the texture should be scaled from the start</param>
         /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
         /// <returns>The texture</returns>
-        public Texture FindOrCreateTexture(CopyTexture copyTexture, ulong offset, FormatInfo formatInfo, bool preferScaling = true, Size? sizeHint = null)
+        public Texture FindOrCreateTexture(
+            MemoryManager memoryManager,
+            CopyTexture copyTexture,
+            ulong offset,
+            FormatInfo formatInfo,
+            bool preferScaling = true,
+            Size? sizeHint = null)
         {
             int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY();
             int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ();
@@ -184,7 +194,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 flags |= TextureSearchFlags.WithUpscale;
             }
 
-            Texture texture = FindOrCreateTexture(flags, info, 0, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0, sizeHint);
 
             texture?.SynchronizeMemory();
 
@@ -194,12 +204,13 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// Tries to find an existing texture, or create a new one if not found.
         /// </summary>
+        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="colorState">Color buffer texture to find or create</param>
         /// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
         /// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
         /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
         /// <returns>The texture</returns>
-        public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
+        public Texture FindOrCreateTexture(MemoryManager memoryManager, RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
         {
             bool isLinear = colorState.MemoryLayout.UnpackIsLinear();
 
@@ -263,7 +274,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             int layerSize = !isLinear ? colorState.LayerSize * 4 : 0;
 
-            Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
 
             texture?.SynchronizeMemory();
 
@@ -273,13 +284,20 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// Tries to find an existing texture, or create a new one if not found.
         /// </summary>
+        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="dsState">Depth-stencil buffer texture to find or create</param>
         /// <param name="size">Size of the depth-stencil texture</param>
         /// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
         /// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
         /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
         /// <returns>The texture</returns>
-        public Texture FindOrCreateTexture(RtDepthStencilState dsState, Size3D size, int samplesInX, int samplesInY, Size sizeHint)
+        public Texture FindOrCreateTexture(
+            MemoryManager memoryManager,
+            RtDepthStencilState dsState,
+            Size3D size,
+            int samplesInX,
+            int samplesInY,
+            Size sizeHint)
         {
             int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
             int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
@@ -306,7 +324,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 target,
                 formatInfo);
 
-            Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
 
             texture?.SynchronizeMemory();
 
@@ -316,13 +334,20 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// Tries to find an existing texture, or create a new one if not found.
         /// </summary>
+        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="flags">The texture search flags, defines texture comparison rules</param>
         /// <param name="info">Texture information of the texture to be found or created</param>
         /// <param name="layerSize">Size in bytes of a single texture layer</param>
         /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
         /// <param name="range">Optional ranges of physical memory where the texture data is located</param>
         /// <returns>The texture</returns>
-        public Texture FindOrCreateTexture(TextureSearchFlags flags, TextureInfo info, int layerSize = 0, Size? sizeHint = null, MultiRange? range = null)
+        public Texture FindOrCreateTexture(
+            MemoryManager memoryManager,
+            TextureSearchFlags flags,
+            TextureInfo info,
+            int layerSize = 0,
+            Size? sizeHint = null,
+            MultiRange? range = null)
         {
             bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;
 
@@ -342,7 +367,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             }
             else
             {
-                address = _context.MemoryManager.Translate(info.GpuAddress);
+                address = memoryManager.Translate(info.GpuAddress);
 
                 if (address == MemoryManager.PteUnmapped)
                 {
@@ -371,22 +396,26 @@ namespace Ryujinx.Graphics.Gpu.Image
                 if (matchQuality != TextureMatchQuality.NoMatch)
                 {
                     // If the parameters match, we need to make sure the texture is mapped to the same memory regions.
-
-                    // If a range of memory was supplied, just check if the ranges match.
-                    if (range != null && !overlap.Range.Equals(range.Value))
+                    if (range != null)
                     {
-                        continue;
+                        // If a range of memory was supplied, just check if the ranges match.
+                        if (!overlap.Range.Equals(range.Value))
+                        {
+                            continue;
+                        }
                     }
-
-                    // If no range was supplied, we can check if the GPU virtual address match. If they do,
-                    // we know the textures are located at the same memory region.
-                    // If they don't, it may still be mapped to the same physical region, so we
-                    // do a more expensive check to tell if they are mapped into the same physical regions.
-                    // If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
-                    if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
-                        !_context.MemoryManager.CompareRange(overlap.Range, info.GpuAddress))
+                    else
                     {
-                        continue;
+                        // If no range was supplied, we can check if the GPU virtual address match. If they do,
+                        // we know the textures are located at the same memory region.
+                        // If they don't, it may still be mapped to the same physical region, so we
+                        // do a more expensive check to tell if they are mapped into the same physical regions.
+                        // If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
+                        if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
+                            !memoryManager.CompareRange(overlap.Range, info.GpuAddress))
+                        {
+                            continue;
+                        }
                     }
                 }
 
@@ -426,7 +455,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             if (range == null)
             {
-                range = _context.MemoryManager.GetPhysicalRegions(info.GpuAddress, size);
+                range = memoryManager.GetPhysicalRegions(info.GpuAddress, size);
             }
 
             // Find view compatible matches.
@@ -495,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 {
                     // Only copy compatible. If there's another choice for a FULLY compatible texture, choose that instead.
 
-                    texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
+                    texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
                     texture.InitializeGroup(true, true);
                     texture.InitializeData(false, false);
 
@@ -531,7 +560,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             // No match, create a new texture.
             if (texture == null)
             {
-                texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
+                texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
 
                 // Step 1: Find textures that are view compatible with the new texture.
                 // Any textures that are incompatible will contain garbage data, so they should be removed where possible.
@@ -722,14 +751,15 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// Tries to find an existing texture matching the given buffer copy destination. If none is found, returns null.
         /// </summary>
+        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="tex">The texture information</param>
         /// <param name="cbp">The copy buffer parameters</param>
         /// <param name="swizzle">The copy buffer swizzle</param>
         /// <param name="linear">True if the texture has a linear layout, false otherwise</param>
         /// <returns>A matching texture, or null if there is no match</returns>
-        public Texture FindTexture(CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
+        public Texture FindTexture(MemoryManager memoryManager, CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
         {
-            ulong address = _context.MemoryManager.Translate(cbp.DstAddress.Pack());
+            ulong address = memoryManager.Translate(cbp.DstAddress.Pack());
 
             if (address == MemoryManager.PteUnmapped)
             {
-- 
cgit v1.2.3-70-g09d2