From c30504e3b3bb64c44d993d6339f15ec6703a3c55 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Fri, 29 Jan 2021 03:19:06 +0000
Subject: [PATCH] Use a descriptor cache for faster pool invalidation. (#1977)

* Use a descriptor cache for faster pool invalidation.

* Speed up comparison by casting to Vector256

Now we never need to worry about this ever again
---
 Ryujinx.Graphics.Gpu/Image/Pool.cs            | 26 ++++++++++++++-----
 .../Image/SamplerDescriptor.cs                | 12 +++++++++
 Ryujinx.Graphics.Gpu/Image/SamplerPool.cs     | 14 ++++++++--
 .../Image/TextureDescriptor.cs                | 12 +++++++++
 Ryujinx.Graphics.Gpu/Image/TexturePool.cs     | 18 +++----------
 5 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs
index c2c1a9a195..c5aef77f69 100644
--- a/Ryujinx.Graphics.Gpu/Image/Pool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs
@@ -8,14 +8,16 @@ namespace Ryujinx.Graphics.Gpu.Image
     /// <summary>
     /// Represents a pool of GPU resources, such as samplers or textures.
     /// </summary>
-    /// <typeparam name="T">Type of the GPU resource</typeparam>
-    abstract class Pool<T> : IDisposable
+    /// <typeparam name="T1">Type of the GPU resource</typeparam>
+    /// <typeparam name="T2">Type of the descriptor</typeparam>
+    abstract class Pool<T1, T2> : IDisposable where T2 : unmanaged
     {
         protected const int DescriptorSize = 0x20;
 
         protected GpuContext Context;
 
-        protected T[] Items;
+        protected T1[] Items;
+        protected T2[] DescriptorCache;
 
         /// <summary>
         /// The maximum ID value of resources on the pool (inclusive).
@@ -47,7 +49,8 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             ulong size = (ulong)(uint)count * DescriptorSize;
 
-            Items = new T[count];
+            Items = new T1[count];
+            DescriptorCache = new T2[count];
 
             Address = address;
             Size    = size;
@@ -56,12 +59,23 @@ namespace Ryujinx.Graphics.Gpu.Image
             _modifiedDelegate = RegionModified;
         }
 
+
+        /// <summary>
+        /// Gets the descriptor for a given ID.
+        /// </summary>
+        /// <param name="id">ID of the descriptor. This is effectively a zero-based index</param>
+        /// <returns>The descriptor</returns>
+        public T2 GetDescriptor(int id)
+        {
+            return Context.PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
+        }
+
         /// <summary>
         /// Gets the GPU resource with the given ID.
         /// </summary>
         /// <param name="id">ID of the resource. This is effectively a zero-based index</param>
         /// <returns>The GPU resource with the given ID</returns>
-        public abstract T Get(int id);
+        public abstract T1 Get(int id);
 
         /// <summary>
         /// Synchronizes host memory with guest memory.
@@ -97,7 +111,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
         protected abstract void InvalidateRangeImpl(ulong address, ulong size);
 
-        protected abstract void Delete(T item);
+        protected abstract void Delete(T1 item);
 
         /// <summary>
         /// Performs the disposal of all resources stored on the pool.
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
index 2c28b743fe..64a146fb3e 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
@@ -1,4 +1,6 @@
 using Ryujinx.Graphics.GAL;
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
 
 namespace Ryujinx.Graphics.Gpu.Image
 {
@@ -244,5 +246,15 @@ namespace Ryujinx.Graphics.Gpu.Image
         {
             return ((Word2 >> 12) & 0xfff) * Frac8ToF32;
         }
+
+        /// <summary>
+        /// Check if two descriptors are equal.
+        /// </summary>
+        /// <param name="other">The descriptor to compare against</param>
+        /// <returns>True if they are equal, false otherwise</returns>
+        public bool Equals(ref SamplerDescriptor other)
+        {
+            return Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref this).Equals(Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref other));
+        }
     }
 }
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
index ca13a7d6f9..1395aea229 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
@@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Image
     /// <summary>
     /// Sampler pool.
     /// </summary>
-    class SamplerPool : Pool<Sampler>
+    class SamplerPool : Pool<Sampler, SamplerDescriptor>
     {
         private int _sequenceNumber;
 
@@ -38,11 +38,13 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             if (sampler == null)
             {
-                SamplerDescriptor descriptor = Context.PhysicalMemory.Read<SamplerDescriptor>(Address + (ulong)id * DescriptorSize);
+                SamplerDescriptor descriptor = GetDescriptor(id);
 
                 sampler = new Sampler(Context, descriptor);
 
                 Items[id] = sampler;
+
+                DescriptorCache[id] = descriptor;
             }
 
             return sampler;
@@ -65,6 +67,14 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                 if (sampler != null)
                 {
+                    SamplerDescriptor descriptor = GetDescriptor(id);
+
+                    // If the descriptors are the same, the sampler is still valid.
+                    if (descriptor.Equals(ref DescriptorCache[id]))
+                    {
+                        continue;
+                    }
+
                     sampler.Dispose();
 
                     Items[id] = null;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
index 76d97bf8c9..e85df136be 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
@@ -1,4 +1,6 @@
 using Ryujinx.Graphics.Gpu.Shader.Cache.Definition;
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
 
 namespace Ryujinx.Graphics.Gpu.Image
 {
@@ -248,5 +250,15 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             return result;
         }
+
+        /// <summary>
+        /// Check if two descriptors are equal.
+        /// </summary>
+        /// <param name="other">The descriptor to compare against</param>
+        /// <returns>True if they are equal, false otherwise</returns>
+        public bool Equals(ref TextureDescriptor other)
+        {
+            return Unsafe.As<TextureDescriptor, Vector256<byte>>(ref this).Equals(Unsafe.As<TextureDescriptor, Vector256<byte>>(ref other));
+        }
     }
 }
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index dfcd8a528a..58e881ca73 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -1,6 +1,5 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Memory;
 using Ryujinx.Graphics.Texture;
 using System;
 using System.Collections.Generic;
@@ -10,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Image
     /// <summary>
     /// Texture pool.
     /// </summary>
-    class TexturePool : Pool<Texture>
+    class TexturePool : Pool<Texture, TextureDescriptor>
     {
         private int _sequenceNumber;
 
@@ -65,6 +64,8 @@ namespace Ryujinx.Graphics.Gpu.Image
                 texture.IncrementReferenceCount();
 
                 Items[id] = texture;
+
+                DescriptorCache[id] = descriptor;
             }
             else
             {
@@ -91,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             return texture;
         }
 
-        /// <summary>
-        /// Gets the texture descriptor from a given texture ID.
-        /// </summary>
-        /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
-        /// <returns>The texture descriptor</returns>
-        public TextureDescriptor GetDescriptor(int id)
-        {
-            return Context.PhysicalMemory.Read<TextureDescriptor>(Address + (ulong)id * DescriptorSize);
-        }
-
         /// <summary>
         /// Implementation of the texture pool range invalidation.
         /// </summary>
@@ -122,8 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                     // If the descriptors are the same, the texture is the same,
                     // we don't need to remove as it was not modified. Just continue.
-                    if (texture.Info.GpuAddress == descriptor.UnpackAddress() &&
-                        texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch)
+                    if (descriptor.Equals(ref DescriptorCache[id]))
                     {
                         continue;
                     }