From 934a78005e75653529c320cf90e78fe6536447c2 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Mon, 9 Nov 2020 19:35:04 -0300
Subject: [PATCH] Simplify logic for bindless texture handling (#1667)

* Simplify logic for bindless texture handling

* Nits
---
 Ryujinx.Graphics.Gpu/Engine/Compute.cs        | 27 ++++----
 Ryujinx.Graphics.Gpu/Engine/Methods.cs        | 22 ++++---
 .../Image/TextureBindingInfo.cs               | 66 ++++---------------
 .../Image/TextureBindingsManager.cs           | 29 ++------
 .../CodeGen/Glsl/CodeGenContext.cs            | 11 +---
 .../CodeGen/Glsl/Declarations.cs              | 24 ++-----
 .../Glsl/Instructions/InstGenMemory.cs        | 36 +++++++++-
 .../CodeGen/Glsl/OperandManager.cs            | 19 ++----
 .../TextureOperation.cs                       | 16 +++--
 .../StructuredIr/AstTextureOperation.cs       |  3 +
 .../StructuredIr/StructuredProgram.cs         |  1 +
 Ryujinx.Graphics.Shader/TextureDescriptor.cs  | 33 ++--------
 .../Optimizations/BindlessElimination.cs      | 29 +++++---
 .../Translation/{Lowering.cs => Rewriter.cs}  |  2 +-
 .../Translation/Translator.cs                 |  2 +-
 Ryujinx.Graphics.Texture/BCnDecoder.cs        |  2 +-
 16 files changed, 131 insertions(+), 191 deletions(-)
 rename Ryujinx.Graphics.Shader/Translation/{Lowering.cs => Rewriter.cs} (99%)

diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
index 3ea98f3e48..cd5002ca9b 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
@@ -111,19 +111,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                 Target target = ShaderTexture.GetTarget(descriptor.Type);
 
-                if (descriptor.IsBindless)
-                {
-                    textureBindings[index] = new TextureBindingInfo(
-                        target,
-                        descriptor.Binding,
-                        descriptor.CbufOffset,
-                        descriptor.CbufSlot,
-                        descriptor.Flags);
-                }
-                else
-                {
-                    textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
-                }
+                textureBindings[index] = new TextureBindingInfo(
+                    target,
+                    descriptor.Binding,
+                    descriptor.CbufSlot,
+                    descriptor.HandleIndex,
+                    descriptor.Flags);
             }
 
             TextureManager.SetComputeTextures(textureBindings);
@@ -137,7 +130,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 Target target = ShaderTexture.GetTarget(descriptor.Type);
                 Format format = ShaderTexture.GetFormat(descriptor.Format);
 
-                imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
+                imageBindings[index] = new TextureBindingInfo(
+                    target,
+                    format,
+                    descriptor.Binding,
+                    descriptor.CbufSlot,
+                    descriptor.HandleIndex,
+                    descriptor.Flags);
             }
 
             TextureManager.SetComputeImages(imageBindings);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 8bc2c22d0b..ef073a25a1 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -1024,14 +1024,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                     Target target = ShaderTexture.GetTarget(descriptor.Type);
 
-                    if (descriptor.IsBindless)
-                    {
-                        textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags);
-                    }
-                    else
-                    {
-                        textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
-                    }
+                    textureBindings[index] = new TextureBindingInfo(
+                        target,
+                        descriptor.Binding,
+                        descriptor.CbufSlot,
+                        descriptor.HandleIndex,
+                        descriptor.Flags);
                 }
 
                 TextureManager.SetGraphicsTextures(stage, textureBindings);
@@ -1045,7 +1043,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
                     Target target = ShaderTexture.GetTarget(descriptor.Type);
                     Format format = ShaderTexture.GetFormat(descriptor.Format);
 
-                    imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
+                    imageBindings[index] = new TextureBindingInfo(
+                        target,
+                        format,
+                        descriptor.Binding,
+                        descriptor.CbufSlot,
+                        descriptor.HandleIndex,
+                        descriptor.Flags);
                 }
 
                 TextureManager.SetGraphicsImages(stage, imageBindings);
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs
index a328fc2b69..be94f310e0 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs
@@ -25,28 +25,14 @@ namespace Ryujinx.Graphics.Gpu.Image
         public int Binding { get; }
 
         /// <summary>
-        /// Shader texture handle.
-        /// This is an index into the texture constant buffer.
-        /// </summary>
-        public int Handle { get; }
-
-        /// <summary>
-        /// Indicates if the texture is a bindless texture.
-        /// </summary>
-        /// <remarks>
-        /// For those textures, Handle is ignored.
-        /// </remarks>
-        public bool IsBindless { get; }
-
-        /// <summary>
-        /// Constant buffer slot with the bindless texture handle, for bindless texture.
+        /// Constant buffer slot with the texture handle.
         /// </summary>
         public int CbufSlot { get; }
 
         /// <summary>
-        /// Constant buffer offset of the bindless texture handle, for bindless texture.
+        /// Index of the texture handle on the constant buffer at slot <see cref="CbufSlot"/>.
         /// </summary>
-        public int CbufOffset { get; }
+        public int Handle { get; }
 
         /// <summary>
         /// Flags from the texture descriptor that indicate how the texture is used.
@@ -59,21 +45,17 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="target">The shader sampler target type</param>
         /// <param name="format">Format of the image as declared on the shader</param>
         /// <param name="binding">The shader texture binding point</param>
+        /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
         /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
         /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
-        public TextureBindingInfo(Target target, Format format, int binding, int handle, TextureUsageFlags flags)
+        public TextureBindingInfo(Target target, Format format, int binding, int cbufSlot, int handle, TextureUsageFlags flags)
         {
-            Target  = target;
-            Format  = format;
-            Binding = binding;
-            Handle  = handle;
-
-            IsBindless = false;
-
-            CbufSlot   = 0;
-            CbufOffset = 0;
-
-            Flags = flags;
+            Target   = target;
+            Format   = format;
+            Binding  = binding;
+            CbufSlot = cbufSlot;
+            Handle   = handle;
+            Flags    = flags;
         }
 
         /// <summary>
@@ -81,33 +63,11 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         /// <param name="target">The shader sampler target type</param>
         /// <param name="binding">The shader texture binding point</param>
+        /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
         /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
         /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
-        public TextureBindingInfo(Target target, int binding, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, handle, flags)
+        public TextureBindingInfo(Target target, int binding, int cbufSlot, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, cbufSlot, handle, flags)
         {
         }
-
-        /// <summary>
-        /// Constructs the bindless texture binding information structure.
-        /// </summary>
-        /// <param name="target">The shader sampler target type</param>
-        /// <param name="binding">The shader texture binding point</param>
-        /// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param>
-        /// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param>
-        /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
-        public TextureBindingInfo(Target target, int binding, int cbufSlot, int cbufOffset, TextureUsageFlags flags)
-        {
-            Target  = target;
-            Format  = 0;
-            Binding = binding;
-            Handle  = 0;
-
-            IsBindless = true;
-
-            CbufSlot   = cbufSlot;
-            CbufOffset = cbufOffset;
-
-            Flags = flags;
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index bfb6da2513..8d44165c6b 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -267,30 +267,9 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
 
-                int packedId;
-
-                if (bindingInfo.IsBindless)
-                {
-                    ulong address;
-
-                    var bufferManager = _context.Methods.BufferManager;
-
-                    if (_isCompute)
-                    {
-                        address = bufferManager.GetComputeUniformBufferAddress(bindingInfo.CbufSlot);
-                    }
-                    else
-                    {
-                        address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, bindingInfo.CbufSlot);
-                    }
-
-                    packedId = _context.PhysicalMemory.Read<int>(address + (ulong)bindingInfo.CbufOffset * 4);
-                }
-                else
-                {
-                    packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex);
-                }
+                int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
 
+                int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
                 int textureId = UnpackTextureId(packedId);
                 int samplerId;
 
@@ -361,7 +340,9 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
 
-                int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex);
+                int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
+
+                int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
                 int textureId = UnpackTextureId(packedId);
 
                 Texture texture = pool.Get(textureId);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
index f86e82da2d..e20df384e3 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs
@@ -86,18 +86,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
         private int FindDescriptorIndex(List<TextureDescriptor> list, AstTextureOperation texOp)
         {
-            AstOperand operand = texOp.GetSource(0) as AstOperand;
-            bool bindless = (texOp.Flags & TextureFlags.Bindless) > 0;
-
-            int cBufSlot = bindless ? operand.CbufSlot : 0;
-            int cBufOffset = bindless ? operand.CbufOffset : 0;
-
             return list.FindIndex(descriptor =>
                 descriptor.Type == texOp.Type &&
+                descriptor.CbufSlot == texOp.CbufSlot &&
                 descriptor.HandleIndex == texOp.Handle &&
-                descriptor.Format == texOp.Format &&
-                descriptor.CbufSlot == cBufSlot &&
-                descriptor.CbufOffset == cBufOffset);
+                descriptor.Format == texOp.Format);
         }
 
         public int FindTextureDescriptorIndex(AstTextureOperation texOp)
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 56a0126412..825564b8c5 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -305,24 +305,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
                 string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
 
-                if (!samplers.Add(samplerName))
+                if ((texOp.Flags & TextureFlags.Bindless) != 0 || !samplers.Add(samplerName))
                 {
                     continue;
                 }
 
                 int firstBinding = -1;
 
-                if ((texOp.Flags & TextureFlags.Bindless) != 0)
-                {
-                    AstOperand operand = texOp.GetSource(0) as AstOperand;
-
-                    firstBinding = context.Config.Counts.IncrementTexturesCount();
-
-                    var desc = new TextureDescriptor(firstBinding, texOp.Type, operand.CbufSlot, operand.CbufOffset);
-
-                    context.TextureDescriptors.Add(desc);
-                }
-                else if ((texOp.Type & SamplerType.Indexed) != 0)
+                if ((texOp.Type & SamplerType.Indexed) != 0)
                 {
                     for (int index = 0; index < texOp.ArraySize; index++)
                     {
@@ -333,7 +323,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                             firstBinding = binding;
                         }
 
-                        var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
+                        var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle + index * 2);
 
                         context.TextureDescriptors.Add(desc);
                     }
@@ -342,7 +332,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 {
                     firstBinding = context.Config.Counts.IncrementTexturesCount();
 
-                    var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
+                    var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle);
 
                     context.TextureDescriptors.Add(desc);
                 }
@@ -363,7 +353,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
                 string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
 
-                if (!images.Add(imageName))
+                if ((texOp.Flags & TextureFlags.Bindless) != 0 || !images.Add(imageName))
                 {
                     continue;
                 }
@@ -381,7 +371,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                             firstBinding = binding;
                         }
 
-                        var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
+                        var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle + index * 2);
 
                         context.ImageDescriptors.Add(desc);
                     }
@@ -390,7 +380,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 {
                     firstBinding = context.Config.Counts.IncrementImagesCount();
 
-                    var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
+                    var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.CbufSlot, texOp.Handle);
 
                     context.ImageDescriptors.Add(desc);
                 }
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index f10eb101b9..6244f68b62 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -15,7 +15,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 
             bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
 
-            bool isArray   = (texOp.Type & SamplerType.Array) != 0;
+            // TODO: Bindless texture support. For now we just return 0/do nothing.
+            if (isBindless)
+            {
+                return texOp.Inst == Instruction.ImageLoad ? NumberFormatter.FormatFloat(0) : "// imageStore(bindless)";
+            }
+
+            bool isArray   = (texOp.Type & SamplerType.Array)   != 0;
             bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
 
             string texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore";
@@ -79,7 +85,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                     flags |= TextureUsageFlags.ResScaleUnsupported;
                 }
 
-                context.ImageDescriptors[index] = context.ImageDescriptors[index].SetFlag(flags);
+                if (!isBindless)
+                {
+                    context.ImageDescriptors[index] = context.ImageDescriptors[index].SetFlag(flags);
+                }
 
                 return vector;
             }
@@ -212,6 +221,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 
             bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
 
+            // TODO: Bindless texture support. For now we just return 0.
+            if (isBindless)
+            {
+                return NumberFormatter.FormatFloat(0);
+            }
+
             bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
 
             string indexExpr = null;
@@ -306,6 +321,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
             bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
             bool isShadow      = (texOp.Type & SamplerType.Shadow)      != 0;
 
+            // TODO: Bindless texture support. For now we just return 0.
+            if (isBindless)
+            {
+                return NumberFormatter.FormatFloat(0);
+            }
+
             // This combination is valid, but not available on GLSL.
             // For now, ignore the LOD level and do a normal sample.
             // TODO: How to implement it properly?
@@ -469,7 +490,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                         flags |= TextureUsageFlags.ResScaleUnsupported;
                     }
 
-                    context.TextureDescriptors[index] = context.TextureDescriptors[index].SetFlag(flags);
+                    if (!isBindless)
+                    {
+                        context.TextureDescriptors[index] = context.TextureDescriptors[index].SetFlag(flags);
+                    }
                 }
 
                 return vector;
@@ -572,6 +596,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 
             bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
 
+            // TODO: Bindless texture support. For now we just return 0.
+            if (isBindless)
+            {
+                return NumberFormatter.FormatInt(0);
+            }
+
             bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
 
             string indexExpr = null;
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 8e878b0d03..5c5d4403ed 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -241,22 +241,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
         public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
         {
-            string suffix;
+            string suffix = texOp.CbufSlot < 0 ? $"_tcb_{texOp.Handle:X}" : $"_cb{texOp.CbufSlot}_{texOp.Handle:X}";
 
-            if ((texOp.Flags & TextureFlags.Bindless) != 0)
+            if ((texOp.Type & SamplerType.Indexed) != 0)
             {
-                AstOperand operand = texOp.GetSource(0) as AstOperand;
-
-                suffix = $"_{texOp.Type.ToGlslSamplerType()}_cb{operand.CbufSlot}_{operand.CbufOffset}";
-            }
-            else
-            {
-                suffix = texOp.Handle.ToString("X");
-
-                if ((texOp.Type & SamplerType.Indexed) != 0)
-                {
-                    suffix += $"a[{indexExpr}]";
-                }
+                suffix += $"a[{indexExpr}]";
             }
 
             return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
@@ -264,7 +253,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
         public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
         {
-            string suffix = texOp.Handle.ToString("X") + "_" + texOp.Format.ToGlslFormat();
+            string suffix = texOp.CbufSlot < 0 ? $"_tcb_{texOp.Handle:X}_{texOp.Format.ToGlslFormat()}" : $"_cb{texOp.CbufSlot}_{texOp.Handle:X}_{texOp.Format.ToGlslFormat()}";
 
             if ((texOp.Type & SamplerType.Indexed) != 0)
             {
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
index 9c5cd25c16..52f02bfb9f 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
@@ -2,9 +2,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 {
     class TextureOperation : Operation
     {
+        private const int DefaultCbufSlot = -1;
+
         public SamplerType  Type  { get; private set; }
         public TextureFlags Flags { get; private set; }
 
+        public int CbufSlot { get; private set; }
+
         public int Handle { get; private set; }
 
         public TextureFormat Format { get; set; }
@@ -18,9 +22,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
             Operand          dest,
             params Operand[] sources) : base(inst, compIndex, dest, sources)
         {
-            Type   = type;
-            Flags  = flags;
-            Handle = handle;
+            Type     = type;
+            Flags    = flags;
+            CbufSlot = DefaultCbufSlot;
+            Handle   = handle;
         }
 
         public void TurnIntoIndexed(int handle)
@@ -30,7 +35,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
             Handle = handle;
         }
 
-        public void SetHandle(int handle)
+        public void SetHandle(int handle, int cbufSlot = DefaultCbufSlot)
         {
             if ((Flags & TextureFlags.Bindless) != 0)
             {
@@ -39,7 +44,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
                 RemoveSource(0);
             }
 
-            Handle = handle;
+            CbufSlot = cbufSlot;
+            Handle   = handle;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
index 188bf91918..cdb9748805 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
         public TextureFormat Format { get; }
         public TextureFlags  Flags  { get; }
 
+        public int CbufSlot  { get; }
         public int Handle    { get; }
         public int ArraySize { get; }
 
@@ -16,6 +17,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             SamplerType       type,
             TextureFormat     format,
             TextureFlags      flags,
+            int               cbufSlot,
             int               handle,
             int               arraySize,
             int               index,
@@ -24,6 +26,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             Type      = type;
             Format    = format;
             Flags     = flags;
+            CbufSlot  = cbufSlot;
             Handle    = handle;
             ArraySize = arraySize;
         }
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
index 66570dc98d..733805cde5 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
@@ -117,6 +117,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
                     texOp.Type,
                     texOp.Format,
                     texOp.Flags,
+                    texOp.CbufSlot,
                     texOp.Handle,
                     4, // TODO: Non-hardcoded array size.
                     texOp.Index,
diff --git a/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/Ryujinx.Graphics.Shader/TextureDescriptor.cs
index b39d6c3d1a..95f5e01dfc 100644
--- a/Ryujinx.Graphics.Shader/TextureDescriptor.cs
+++ b/Ryujinx.Graphics.Shader/TextureDescriptor.cs
@@ -5,46 +5,21 @@ namespace Ryujinx.Graphics.Shader
         public int Binding { get; }
 
         public SamplerType Type { get; }
-
         public TextureFormat Format { get; }
 
+        public int CbufSlot { get; }
         public int HandleIndex { get; }
 
-        public bool IsBindless { get; }
-
-        public int CbufSlot   { get; }
-        public int CbufOffset { get; }
-
         public TextureUsageFlags Flags { get; set; }
 
-        public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int handleIndex)
+        public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int cbufSlot, int handleIndex)
         {
             Binding     = binding;
             Type        = type;
             Format      = format;
+            CbufSlot    = cbufSlot;
             HandleIndex = handleIndex;
-
-            IsBindless = false;
-
-            CbufSlot   = 0;
-            CbufOffset = 0;
-
-            Flags = TextureUsageFlags.None;
-        }
-
-        public TextureDescriptor(int binding, SamplerType type, int cbufSlot, int cbufOffset)
-        {
-            Binding     = binding;
-            Type        = type;
-            Format      = TextureFormat.Unknown;
-            HandleIndex = 0;
-
-            IsBindless = true;
-
-            CbufSlot   = cbufSlot;
-            CbufOffset = cbufOffset;
-
-            Flags = TextureUsageFlags.None;
+            Flags       = TextureUsageFlags.None;
         }
 
         public TextureDescriptor SetFlag(TextureUsageFlags flag)
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index a26c81c93e..b326aaa435 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -5,15 +5,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 {
     class BindlessElimination
     {
-        private const int NvnTextureBufferSlot = 2;
-
         public static void RunPass(BasicBlock block, ShaderConfig config)
         {
             // We can turn a bindless into regular access by recognizing the pattern
             // produced by the compiler for separate texture and sampler.
             // We check for the following conditions:
+            // - The handle is a constant buffer value.
             // - The handle is the result of a bitwise OR logical operation.
-            // - Both sources of the OR operation comes from CB2 (used by NVN to hold texture handles).
+            // - Both sources of the OR operation comes from a constant buffer.
             for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
             {
                 if (!(node.Value is TextureOperation texOp))
@@ -26,9 +25,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     continue;
                 }
 
-                if (texOp.Inst == Instruction.TextureSample)
+                if (texOp.Inst == Instruction.Lod ||
+                    texOp.Inst == Instruction.TextureSample ||
+                    texOp.Inst == Instruction.TextureSize)
                 {
-                    if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp))
+                    Operand bindlessHandle = texOp.GetSource(0);
+
+                    if (bindlessHandle.Type == OperandType.ConstantBuffer)
+                    {
+                        texOp.SetHandle(bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
+                        continue;
+                    }
+
+                    if (!(bindlessHandle.AsgOp is Operation handleCombineOp))
                     {
                         continue;
                     }
@@ -41,21 +50,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     Operand src0 = handleCombineOp.GetSource(0);
                     Operand src1 = handleCombineOp.GetSource(1);
 
-                    if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != NvnTextureBufferSlot ||
-                        src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != NvnTextureBufferSlot)
+                    if (src0.Type != OperandType.ConstantBuffer ||
+                        src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
                     {
                         continue;
                     }
 
-                    texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16));
+                    texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
                 }
                 else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
                 {
                     Operand src0 = texOp.GetSource(0);
 
-                    if (src0.Type == OperandType.ConstantBuffer && src0.GetCbufSlot() == NvnTextureBufferSlot)
+                    if (src0.Type == OperandType.ConstantBuffer)
                     {
-                        texOp.SetHandle(src0.GetCbufOffset());
+                        texOp.SetHandle(src0.GetCbufOffset(), src0.GetCbufSlot());
                         texOp.Format = config.GetTextureFormat(texOp.Handle);
                     }
                 }
diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
similarity index 99%
rename from Ryujinx.Graphics.Shader/Translation/Lowering.cs
rename to Ryujinx.Graphics.Shader/Translation/Rewriter.cs
index 6da25983ae..a928f93571 100644
--- a/Ryujinx.Graphics.Shader/Translation/Lowering.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
@@ -8,7 +8,7 @@ using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
 
 namespace Ryujinx.Graphics.Shader.Translation
 {
-    static class Lowering
+    static class Rewriter
     {
         public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
         {
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index f86b69647c..3485b5ed9d 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 
                     Optimizer.RunPass(cfg.Blocks, config);
 
-                    Lowering.RunPass(cfg.Blocks, config);
+                    Rewriter.RunPass(cfg.Blocks, config);
                 }
 
                 funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
diff --git a/Ryujinx.Graphics.Texture/BCnDecoder.cs b/Ryujinx.Graphics.Texture/BCnDecoder.cs
index 398e835842..b8b04bac2e 100644
--- a/Ryujinx.Graphics.Texture/BCnDecoder.cs
+++ b/Ryujinx.Graphics.Texture/BCnDecoder.cs
@@ -192,7 +192,7 @@ namespace Ryujinx.Graphics.Texture
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-         private static void CalculateBC3Alpha(Span<byte> alpha)
+        private static void CalculateBC3Alpha(Span<byte> alpha)
         {
             for (int i = 2; i < 8; i++)
             {