From 66f16f43921bdd6d0f706d09aa37166d374dec2e Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 13 Sep 2022 03:53:55 -0300
Subject: [PATCH] Fix bindless 1D textures having a buffer type on the shader
 (#3697)

* Fix bindless 1D textures having a buffer type on the shader

* Shader cache version bump
---
 .../Shader/DiskCache/DiskCacheHostStorage.cs  |  2 +-
 .../Instructions/InstEmitTexture.cs           |  2 +-
 .../IntermediateRepresentation/Operation.cs   | 12 ++++
 .../TextureOperation.cs                       |  5 ++
 .../Optimizations/BindlessElimination.cs      | 55 ++++++++++++++++---
 5 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index d257c19307..24b05b90b2 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         private const ushort FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMinor = 2;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
-        private const uint CodeGenVersion = 3644;
+        private const uint CodeGenVersion = 3697;
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 4d20a5ce10..c54b79cdcb 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
             { 0b0111, 0b1011, 0b1101, 0b1110, 0b1111, 0b0000, 0b0000, 0b0000 }
         };
 
-        private const bool Sample1DAs2D = true;
+        public const bool Sample1DAs2D = true;
 
         private enum TexsType
         {
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
index 955beafded..961326338c 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
@@ -180,6 +180,18 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
             _sources[index] = source;
         }
 
+        public void InsertSource(int index, Operand source)
+        {
+            Operand[] newSources = new Operand[_sources.Length + 1];
+
+            Array.Copy(_sources, 0, newSources, 0, index);
+            Array.Copy(_sources, index, newSources, index + 1, _sources.Length - index);
+
+            newSources[index] = source;
+
+            _sources = newSources;
+        }
+
         protected void RemoveSource(int index)
         {
             SetSource(index, null);
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
index ea9ae39ce3..8cfcb0e9af 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
@@ -60,5 +60,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
             CbufSlot = cbufSlot;
             Handle = handle;
         }
+
+        public void SetLodLevelFlag()
+        {
+            Flags |= TextureFlags.LodLevel;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 73d89761e1..0c196c4d09 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -1,4 +1,5 @@
-using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.Instructions;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using System.Collections.Generic;
 
 namespace Ryujinx.Graphics.Shader.Translation.Optimizations
@@ -30,11 +31,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     texOp.Inst == Instruction.TextureSize)
                 {
                     Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
-                    bool rewriteSamplerType = texOp.Inst == Instruction.TextureSize;
+
+                    // Some instructions do not encode an accurate sampler type:
+                    // - Most instructions uses the same type for 1D and Buffer.
+                    // - Query instructions may not have any type.
+                    // For those cases, we need to try getting the type from current GPU state,
+                    // as long bindless elimination is successful and we know where the texture descriptor is located.
+                    bool rewriteSamplerType =
+                        texOp.Type == SamplerType.TextureBuffer ||
+                        texOp.Inst == Instruction.TextureSize;
 
                     if (bindlessHandle.Type == OperandType.ConstantBuffer)
                     {
-                        SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType);
+                        SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType, isImage: false);
                         continue;
                     }
 
@@ -137,7 +146,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             texOp,
                             TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType),
                             TextureHandle.PackSlots(src0.GetCbufSlot(), 0),
-                            rewriteSamplerType);
+                            rewriteSamplerType,
+                            isImage: false);
                     }
                     else if (src1.Type == OperandType.ConstantBuffer)
                     {
@@ -146,7 +156,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             texOp,
                             TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType),
                             TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()),
-                            rewriteSamplerType);
+                            rewriteSamplerType,
+                            isImage: false);
                     }
                 }
                 else if (texOp.Inst == Instruction.ImageLoad ||
@@ -172,7 +183,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             }
                         }
 
-                        SetHandle(config, texOp, cbufOffset, cbufSlot, false);
+                        bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer;
+
+                        SetHandle(config, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true);
                     }
                 }
             }
@@ -209,13 +222,39 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
             return null;
         }
 
-        private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType)
+        private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage)
         {
             texOp.SetHandle(cbufOffset, cbufSlot);
 
             if (rewriteSamplerType)
             {
-                texOp.Type = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
+                SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
+
+                if (texOp.Inst.IsTextureQuery())
+                {
+                    texOp.Type = newType;
+                }
+                else if (texOp.Type == SamplerType.TextureBuffer && newType == SamplerType.Texture1D)
+                {
+                    int coordsCount = 1;
+
+                    if (InstEmit.Sample1DAs2D)
+                    {
+                        newType = SamplerType.Texture2D;
+                        texOp.InsertSource(coordsCount++, OperandHelper.Const(0));
+                    }
+
+                    if (!isImage &&
+                        (texOp.Flags & TextureFlags.IntCoords) != 0 &&
+                        (texOp.Flags & TextureFlags.LodLevel) == 0)
+                    {
+                        // IntCoords textures must always have explicit LOD.
+                        texOp.SetLodLevelFlag();
+                        texOp.InsertSource(coordsCount, OperandHelper.Const(0));
+                    }
+
+                    texOp.Type = newType;
+                }
             }
 
             config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);