From 24ee8c39f1fd8ae2dc2d92cda1cdb41e8af45f0a Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Thu, 19 Sep 2024 14:38:30 -0300
Subject: Add support for sampler sRGB disable (#7312)

---
 src/Ryujinx.Graphics.Gpu/Image/Sampler.cs          |  7 ++++++
 .../Image/SamplerDescriptor.cs                     |  9 +++++++
 .../Image/TextureBindingsManager.cs                | 10 ++++----
 src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs      | 28 ++++++++++++++++++++--
 4 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs
index d6a3d975..b007c159 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/Sampler.cs
@@ -13,6 +13,11 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         public bool IsDisposed { get; private set; }
 
+        /// <summary>
+        /// True if the sampler has sRGB conversion enabled, false otherwise.
+        /// </summary>
+        public bool IsSrgb { get; }
+
         /// <summary>
         /// Host sampler object.
         /// </summary>
@@ -30,6 +35,8 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="descriptor">The Maxwell sampler descriptor</param>
         public Sampler(GpuContext context, SamplerDescriptor descriptor)
         {
+            IsSrgb = descriptor.UnpackSrgb();
+
             MinFilter minFilter = descriptor.UnpackMinFilter();
             MagFilter magFilter = descriptor.UnpackMagFilter();
 
diff --git a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
index e04c31df..836a3260 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs
@@ -113,6 +113,15 @@ namespace Ryujinx.Graphics.Gpu.Image
             return (CompareOp)(((Word0 >> 10) & 7) + 1);
         }
 
+        /// <summary>
+        /// Unpacks the sampler sRGB format flag.
+        /// </summary>
+        /// <returns>True if the has sampler is sRGB conversion enabled, false otherwise</returns>
+        public readonly bool UnpackSrgb()
+        {
+            return (Word0 & (1 << 13)) != 0;
+        }
+
         /// <summary>
         /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
         /// </summary>
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index ad018f15..f96ddfb1 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -187,7 +187,9 @@ namespace Ryujinx.Graphics.Gpu.Image
         {
             (TexturePool texturePool, SamplerPool samplerPool) = GetPools();
 
-            return (texturePool.Get(textureId), samplerPool.Get(samplerId));
+            Sampler sampler = samplerPool?.Get(samplerId);
+
+            return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler);
         }
 
         /// <summary>
@@ -508,11 +510,11 @@ namespace Ryujinx.Graphics.Gpu.Image
                 state.TextureHandle = textureId;
                 state.SamplerHandle = samplerId;
 
-                ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
+                Sampler sampler = samplerPool?.Get(samplerId);
 
-                specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
+                ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture);
 
-                Sampler sampler = samplerPool?.Get(samplerId);
+                specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
 
                 ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
                 ISampler hostSampler = sampler?.GetHostSampler(texture);
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index 5f43c182..be7cb0b8 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -227,6 +227,17 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
         /// <returns>The texture with the given ID</returns>
         public override Texture Get(int id)
+        {
+            return Get(id, srgbSampler: true);
+        }
+
+        /// <summary>
+        /// Gets the texture with the given ID.
+        /// </summary>
+        /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
+        /// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
+        /// <returns>The texture with the given ID</returns>
+        public Texture Get(int id, bool srgbSampler)
         {
             if ((uint)id >= Items.Length)
             {
@@ -240,7 +251,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 SynchronizeMemory();
             }
 
-            GetInternal(id, out Texture texture);
+            GetForBinding(id, srgbSampler, out Texture texture);
 
             return texture;
         }
@@ -252,9 +263,10 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// This method assumes that the pool has been manually synchronized before doing binding.
         /// </remarks>
         /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
+        /// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
         /// <param name="texture">The texture with the given ID</param>
         /// <returns>The texture descriptor with the given ID</returns>
-        public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture)
+        public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture)
         {
             if ((uint)id >= Items.Length)
             {
@@ -264,6 +276,18 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             // When getting for binding, assume the pool has already been synchronized.
 
+            if (!srgbSampler)
+            {
+                // If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format.
+                ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id);
+
+                if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo))
+                {
+                    // Get a view of the texture with the right format.
+                    return ref GetForBinding(id, formatInfo, out texture);
+                }
+            }
+
             return ref GetInternal(id, out texture);
         }
 
-- 
cgit v1.2.3-70-g09d2