From 5afd521c5a75da956448df76e415528316ee8a8d Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sat, 2 Jul 2022 15:03:35 -0300
Subject: [PATCH] Bindless elimination for constant sampler handle (#3424)

* Bindless elimination for constant sampler handle

* Shader cache version bump

* Update TextureHandle.ReadPackedId for new bindless elimination
---
 .../Image/TextureBindingsManager.cs           | 20 ++++--
 .../Shader/DiskCache/DiskCacheHostStorage.cs  |  2 +-
 Ryujinx.Graphics.Shader/IGpuAccessor.cs       |  2 +-
 Ryujinx.Graphics.Shader/TextureHandle.cs      | 17 ++++-
 .../Optimizations/BindlessElimination.cs      | 62 ++++++++++++++-----
 5 files changed, 78 insertions(+), 25 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 18f5a74a0a..fcd2344143 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -792,13 +792,23 @@ namespace Ryujinx.Graphics.Gpu.Image
             // turn that into a regular texture access and produce those special handles with values on the higher 16 bits.
             if (handleType != TextureHandleType.CombinedSampler)
             {
-                ulong samplerBufferAddress = _isCompute
-                    ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
-                    : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
+                int samplerHandle;
 
-                int samplerHandle = _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4);
+                if (handleType != TextureHandleType.SeparateConstantSamplerHandle)
+                {
+                    ulong samplerBufferAddress = _isCompute
+                        ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
+                        : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
 
-                if (handleType == TextureHandleType.SeparateSamplerId)
+                    samplerHandle = _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4);
+                }
+                else
+                {
+                    samplerHandle = samplerWordOffset;
+                }
+
+                if (handleType == TextureHandleType.SeparateSamplerId ||
+                    handleType == TextureHandleType.SeparateConstantSamplerHandle)
                 {
                     samplerHandle <<= 20;
                 }
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 5d99957f0f..59801001a1 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         private const ushort FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMinor = 1;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
-        private const uint CodeGenVersion = 1;
+        private const uint CodeGenVersion = 3424;
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 180fc18746..42f210a54c 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -237,7 +237,7 @@ namespace Ryujinx.Graphics.Shader
         /// <returns>True if the coordinates are normalized, false otherwise</returns>
         bool QueryTextureCoordNormalized(int handle, int cbufSlot = -1)
         {
-            return false;
+            return true;
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Shader/TextureHandle.cs b/Ryujinx.Graphics.Shader/TextureHandle.cs
index d468188b87..a2842bb891 100644
--- a/Ryujinx.Graphics.Shader/TextureHandle.cs
+++ b/Ryujinx.Graphics.Shader/TextureHandle.cs
@@ -7,7 +7,8 @@ namespace Ryujinx.Graphics.Shader
     {
         CombinedSampler = 0, // Must be 0.
         SeparateSamplerHandle = 1,
-        SeparateSamplerId = 2
+        SeparateSamplerId = 2,
+        SeparateConstantSamplerHandle = 3
     }
 
     public static class TextureHandle
@@ -97,9 +98,19 @@ namespace Ryujinx.Graphics.Shader
             // turn that into a regular texture access and produce those special handles with values on the higher 16 bits.
             if (handleType != TextureHandleType.CombinedSampler)
             {
-                int samplerHandle = cachedSamplerBuffer[samplerWordOffset];
+                int samplerHandle;
 
-                if (handleType == TextureHandleType.SeparateSamplerId)
+                if (handleType != TextureHandleType.SeparateConstantSamplerHandle)
+                {
+                    samplerHandle = cachedSamplerBuffer[samplerWordOffset];
+                }
+                else
+                {
+                    samplerHandle = samplerWordOffset;
+                }
+
+                if (handleType == TextureHandleType.SeparateSamplerId ||
+                    handleType == TextureHandleType.SeparateConstantSamplerHandle)
                 {
                     samplerHandle <<= 20;
                 }
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 1b303caf19..73d89761e1 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -51,16 +51,32 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block);
                     Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block);
 
+                    // For cases where we have a constant, ensure that the constant is always
+                    // the second operand.
+                    // Since this is a commutative operation, both are fine,
+                    // and having a "canonical" representation simplifies some checks below.
+                    if (src0.Type == OperandType.Constant && src1.Type != OperandType.Constant)
+                    {
+                        Operand temp = src1;
+                        src1 = src0;
+                        src0 = temp;
+                    }
+
                     TextureHandleType handleType = TextureHandleType.SeparateSamplerHandle;
 
-                    // Try to match masked pattern:
-                    // - samplerHandle = samplerHandle & 0xFFF00000;
-                    // - textureHandle = textureHandle & 0xFFFFF;
-                    // - combinedHandle = samplerHandle | textureHandle;
-                    // where samplerHandle and textureHandle comes from a constant buffer, and shifted pattern:
-                    // - samplerHandle = samplerId << 20;
-                    // - combinedHandle = samplerHandle | textureHandle;
-                    // where samplerId and textureHandle comes from a constant buffer.
+                    // Try to match the following patterns:
+                    // Masked pattern:
+                    //  - samplerHandle = samplerHandle & 0xFFF00000;
+                    //  - textureHandle = textureHandle & 0xFFFFF;
+                    //  - combinedHandle = samplerHandle | textureHandle;
+                    //  Where samplerHandle and textureHandle comes from a constant buffer.
+                    // Shifted pattern:
+                    //  - samplerHandle = samplerId << 20;
+                    //  - combinedHandle = samplerHandle | textureHandle;
+                    //  Where samplerId and textureHandle comes from a constant buffer.
+                    // Constant pattern:
+                    //  - combinedHandle = samplerHandleConstant | textureHandle;
+                    //  Where samplerHandleConstant is a constant value, and textureHandle comes from a constant buffer.
                     if (src0.AsgOp is Operation src0AsgOp)
                     {
                         if (src1.AsgOp is Operation src1AsgOp &&
@@ -104,18 +120,34 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             handleType = TextureHandleType.SeparateSamplerId;
                         }
                     }
+                    else if (src1.Type == OperandType.Constant && (src1.Value & 0xfffff) == 0)
+                    {
+                        handleType = TextureHandleType.SeparateConstantSamplerHandle;
+                    }
 
-                    if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer)
+                    if (src0.Type != OperandType.ConstantBuffer)
                     {
                         continue;
                     }
 
-                    SetHandle(
-                        config,
-                        texOp,
-                        TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType),
-                        TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()),
-                        rewriteSamplerType);
+                    if (handleType == TextureHandleType.SeparateConstantSamplerHandle)
+                    {
+                        SetHandle(
+                            config,
+                            texOp,
+                            TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType),
+                            TextureHandle.PackSlots(src0.GetCbufSlot(), 0),
+                            rewriteSamplerType);
+                    }
+                    else if (src1.Type == OperandType.ConstantBuffer)
+                    {
+                        SetHandle(
+                            config,
+                            texOp,
+                            TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType),
+                            TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()),
+                            rewriteSamplerType);
+                    }
                 }
                 else if (texOp.Inst == Instruction.ImageLoad ||
                          texOp.Inst == Instruction.ImageStore ||