Browse Source

Prefer truly perfect texture matches over fomat aliased ones (#1754)

riperiperi 5 years ago
parent
commit
0108004691

+ 12 - 10
Ryujinx.Graphics.Gpu/Image/Texture.cs

@@ -800,29 +800,31 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         /// <param name="info">Texture information to compare against</param>
         /// <param name="flags">Comparison flags</param>
-        /// <returns>True if the textures are strictly equal or similar, false otherwise</returns>
-        public bool IsPerfectMatch(TextureInfo info, TextureSearchFlags flags)
+        /// <returns>A value indicating how well this texture matches the given info</returns>
+        public TextureMatchQuality IsExactMatch(TextureInfo info, TextureSearchFlags flags)
         {
-            if (!TextureCompatibility.FormatMatches(Info, info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0))
+            TextureMatchQuality matchQuality = TextureCompatibility.FormatMatches(Info, info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0);
+
+            if (matchQuality == TextureMatchQuality.NoMatch)
             {
-                return false;
+                return matchQuality;
             }
 
             if (!TextureCompatibility.LayoutMatches(Info, info))
             {
-                return false;
+                return TextureMatchQuality.NoMatch;
             }
 
             if (!TextureCompatibility.SizeMatches(Info, info, (flags & TextureSearchFlags.Strict) == 0))
             {
-                return false;
+                return TextureMatchQuality.NoMatch;
             }
 
             if ((flags & TextureSearchFlags.ForSampler) != 0 || (flags & TextureSearchFlags.Strict) != 0)
             {
                 if (!TextureCompatibility.SamplerParamsMatches(Info, info))
                 {
-                    return false;
+                    return TextureMatchQuality.NoMatch;
                 }
             }
 
@@ -832,15 +834,15 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                 if (!msTargetCompatible && !TextureCompatibility.TargetAndSamplesCompatible(Info, info))
                 {
-                    return false;
+                    return TextureMatchQuality.NoMatch;
                 }
             }
             else if (!TextureCompatibility.TargetAndSamplesCompatible(Info, info))
             {
-                return false;
+                return TextureMatchQuality.NoMatch;
             }
 
-            return Info.Address == info.Address && Info.Levels == info.Levels;
+            return Info.Address == info.Address && Info.Levels == info.Levels ? matchQuality : TextureMatchQuality.NoMatch;
         }
 
         /// <summary>

+ 7 - 7
Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs

@@ -125,14 +125,14 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="rhs">Texture information to compare with</param>
         /// <param name="forSampler">Indicates that the texture will be used for shader sampling</param>
         /// <param name="forCopy">Indicates that the texture will be used as copy source or target</param>
-        /// <returns>True if the format matches, with the given comparison rules</returns>
-        public static bool FormatMatches(TextureInfo lhs, TextureInfo rhs, bool forSampler, bool forCopy)
+        /// <returns>A value indicating how well the formats match</returns>
+        public static TextureMatchQuality FormatMatches(TextureInfo lhs, TextureInfo rhs, bool forSampler, bool forCopy)
         {
             // D32F and R32F texture have the same representation internally,
             // however the R32F format is used to sample from depth textures.
             if (lhs.FormatInfo.Format == Format.D32Float && rhs.FormatInfo.Format == Format.R32Float && (forSampler || forCopy))
             {
-                return true;
+                return TextureMatchQuality.FormatAlias;
             }
 
             if (forCopy)
@@ -141,22 +141,22 @@ namespace Ryujinx.Graphics.Gpu.Image
                 // use equivalent color formats. We must also consider them as compatible.
                 if (lhs.FormatInfo.Format == Format.S8Uint && rhs.FormatInfo.Format == Format.R8Unorm)
                 {
-                    return true;
+                    return TextureMatchQuality.FormatAlias;
                 }
 
                 if (lhs.FormatInfo.Format == Format.D16Unorm && rhs.FormatInfo.Format == Format.R16Unorm)
                 {
-                    return true;
+                    return TextureMatchQuality.FormatAlias;
                 }
 
                 if ((lhs.FormatInfo.Format == Format.D24UnormS8Uint ||
                      lhs.FormatInfo.Format == Format.D24X8Unorm) && rhs.FormatInfo.Format == Format.B8G8R8A8Unorm)
                 {
-                    return true;
+                    return TextureMatchQuality.FormatAlias;
                 }
             }
 
-            return lhs.FormatInfo.Format == rhs.FormatInfo.Format;
+            return lhs.FormatInfo.Format == rhs.FormatInfo.Format ? TextureMatchQuality.Perfect : TextureMatchQuality.NoMatch;
         }
 
         /// <summary>

+ 29 - 14
Ryujinx.Graphics.Gpu/Image/TextureManager.cs

@@ -682,26 +682,43 @@ namespace Ryujinx.Graphics.Gpu.Image
                 sameAddressOverlapsCount = _textures.FindOverlaps(info.Address, ref _textureOverlaps);
             }
 
+            Texture texture = null;
+
+            TextureMatchQuality bestQuality = TextureMatchQuality.NoMatch;
+
             for (int index = 0; index < sameAddressOverlapsCount; index++)
             {
                 Texture overlap = _textureOverlaps[index];
 
-                if (overlap.IsPerfectMatch(info, flags))
+                TextureMatchQuality matchQuality = overlap.IsExactMatch(info, flags);
+
+                if (matchQuality == TextureMatchQuality.Perfect)
                 {
-                    if (!isSamplerTexture)
-                    {
-                        // If not a sampler texture, it is managed by the auto delete
-                        // cache, ensure that it is on the "top" of the list to avoid
-                        // deletion.
-                        _cache.Lift(overlap);
-                    }
+                    texture = overlap;
+                    break;
+                }
+                else if (matchQuality > bestQuality)
+                {
+                    texture = overlap;
+                    bestQuality = matchQuality;
+                }
+            }
 
-                    ChangeSizeIfNeeded(info, overlap, isSamplerTexture, sizeHint);
+            if (texture != null)
+            {
+                if (!isSamplerTexture)
+                {
+                    // If not a sampler texture, it is managed by the auto delete
+                    // cache, ensure that it is on the "top" of the list to avoid
+                    // deletion.
+                    _cache.Lift(texture);
+                }
 
-                    overlap.SynchronizeMemory();
+                ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint);
 
-                    return overlap;
-                }
+                texture.SynchronizeMemory();
+
+                return texture;
             }
 
             // Calculate texture sizes, used to find all overlapping textures.
@@ -743,8 +760,6 @@ namespace Ryujinx.Graphics.Gpu.Image
                 overlapsCount = _textures.FindOverlaps(info.Address, size, ref _textureOverlaps);
             }
 
-            Texture texture = null;
-
             for (int index = 0; index < overlapsCount; index++)
             {
                 Texture overlap = _textureOverlaps[index];

+ 9 - 0
Ryujinx.Graphics.Gpu/Image/TextureMatchQuality.cs

@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Gpu.Image
+{
+    enum TextureMatchQuality
+    {
+        NoMatch,
+        FormatAlias,
+        Perfect
+    }
+}

+ 1 - 1
Ryujinx.Graphics.Gpu/Image/TexturePool.cs

@@ -121,7 +121,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.IsPerfectMatch(GetInfo(descriptor), TextureSearchFlags.Strict))
+                    if (texture.IsExactMatch(GetInfo(descriptor), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch)
                     {
                         continue;
                     }