Просмотр исходного кода

Replace constant buffer access on shader with new Load instruction (#4646)

gdkchan 2 лет назад
Родитель
Сommit
402f05b8ef
42 измененных файлов с 784 добавлено и 621 удалено
  1. 1 1
      src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
  2. 18 1
      src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
  3. 26 68
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
  4. 0 10
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
  5. 2 2
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl
  6. 2 2
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl
  7. 2 2
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl
  8. 0 3
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
  9. 0 1
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
  10. 47 51
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
  11. 0 3
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/IoMap.cs
  12. 16 51
      src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
  13. 1 29
      src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
  14. 48 81
      src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
  15. 63 130
      src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
  16. 4 4
      src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ScalingHelpers.cs
  17. 1 1
      src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
  18. 36 3
      src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
  19. 0 1
      src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
  20. 0 3
      src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IoVariable.cs
  21. 1 13
      src/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs
  22. 20 0
      src/Ryujinx.Graphics.Shader/StructuredIr/BufferDefinition.cs
  23. 8 0
      src/Ryujinx.Graphics.Shader/StructuredIr/BufferLayout.cs
  24. 0 1
      src/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
  25. 0 1
      src/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs
  26. 21 0
      src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs
  27. 28 0
      src/Ryujinx.Graphics.Shader/StructuredIr/StructureType.cs
  28. 23 16
      src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
  29. 27 5
      src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs
  30. 26 0
      src/Ryujinx.Graphics.Shader/SupportBuffer.cs
  31. 31 0
      src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
  32. 3 3
      src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
  33. 26 20
      src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
  34. 0 1
      src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
  35. 28 4
      src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
  36. 16 3
      src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
  37. 12 10
      src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
  38. 4 4
      src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
  39. 126 0
      src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
  40. 102 13
      src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
  41. 14 79
      src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
  42. 1 1
      src/Ryujinx.Graphics.Shader/Translation/Translator.cs

+ 1 - 1
src/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 FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMinor = 2;
         private const ushort FileFormatVersionMinor = 2;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
-        private const uint CodeGenVersion = 5027;
+        private const uint CodeGenVersion = 4646;
 
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
         private const string SharedDataFileName = "shared.data";

+ 18 - 1
src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs

@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Threed;
 using Ryujinx.Graphics.Gpu.Image;
 using Ryujinx.Graphics.Gpu.Image;
 using Ryujinx.Graphics.Shader;
 using Ryujinx.Graphics.Shader;
 using Ryujinx.Graphics.Shader.Translation;
 using Ryujinx.Graphics.Shader.Translation;
+using System;
 
 
 namespace Ryujinx.Graphics.Gpu.Shader
 namespace Ryujinx.Graphics.Gpu.Shader
 {
 {
@@ -16,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
         private readonly ResourceCounts _resourceCounts;
         private readonly ResourceCounts _resourceCounts;
         private readonly int _stageIndex;
         private readonly int _stageIndex;
 
 
+        private readonly int[] _constantBufferBindings;
+
         /// <summary>
         /// <summary>
         /// Creates a new GPU accessor.
         /// Creates a new GPU accessor.
         /// </summary>
         /// </summary>
@@ -25,6 +28,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
             _context = context;
             _context = context;
             _resourceCounts = resourceCounts;
             _resourceCounts = resourceCounts;
             _stageIndex = stageIndex;
             _stageIndex = stageIndex;
+
+            if (context.Capabilities.Api != TargetApi.Vulkan)
+            {
+                _constantBufferBindings = new int[Constants.TotalGpUniformBuffers];
+                _constantBufferBindings.AsSpan().Fill(-1);
+            }
         }
         }
 
 
         public int QueryBindingConstantBuffer(int index)
         public int QueryBindingConstantBuffer(int index)
@@ -36,7 +45,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
             }
             }
             else
             else
             {
             {
-                return _resourceCounts.UniformBuffersCount++;
+                int binding = _constantBufferBindings[index];
+
+                if (binding < 0)
+                {
+                    binding = _resourceCounts.UniformBuffersCount++;
+                    _constantBufferBindings[index] = binding;
+                }
+
+                return binding;
             }
             }
         }
         }
 
 

+ 26 - 68
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs

@@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.StructuredIr;
 using Ryujinx.Graphics.Shader.Translation;
 using Ryujinx.Graphics.Shader.Translation;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Numerics;
 using System.Numerics;
 
 
@@ -102,13 +103,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 context.AppendLine();
                 context.AppendLine();
             }
             }
 
 
-            var cBufferDescriptors = context.Config.GetConstantBufferDescriptors();
-            if (cBufferDescriptors.Length != 0)
-            {
-                DeclareUniforms(context, cBufferDescriptors);
-
-                context.AppendLine();
-            }
+            DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values);
 
 
             var sBufferDescriptors = context.Config.GetStorageBufferDescriptors();
             var sBufferDescriptors = context.Config.GetStorageBufferDescriptors();
             if (sBufferDescriptors.Length != 0)
             if (sBufferDescriptors.Length != 0)
@@ -265,18 +260,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                         scaleElements++; // Also includes render target scale, for gl_FragCoord.
                         scaleElements++; // Also includes render target scale, for gl_FragCoord.
                     }
                     }
 
 
-                    DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
-
                     if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
                     if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
                     {
                     {
                         AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
                         AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
                         context.AppendLine();
                         context.AppendLine();
                     }
                     }
                 }
                 }
-                else if (isFragment || context.Config.Stage == ShaderStage.Vertex)
-                {
-                    DeclareSupportUniformBlock(context, context.Config.Stage, 0);
-                }
             }
             }
 
 
             if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0)
             if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0)
@@ -389,36 +378,38 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             };
             };
         }
         }
 
 
-        private static void DeclareUniforms(CodeGenContext context, BufferDescriptor[] descriptors)
+        private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
         {
         {
-            string ubSize = "[" + NumberFormatter.FormatInt(Constants.ConstantBufferSize / 16) + "]";
-
-            if (context.Config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
+            foreach (BufferDefinition buffer in buffers)
             {
             {
-                string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
-
-                ubName += "_" + DefaultNames.UniformNamePrefix;
-
-                string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
+                string layout = buffer.Layout switch
+                {
+                    BufferLayout.Std140 => "std140",
+                    _ => "std430"
+                };
 
 
-                context.AppendLine($"layout (binding = {context.Config.FirstConstantBufferBinding}, std140) uniform {blockName}");
+                context.AppendLine($"layout (binding = {buffer.Binding}, {layout}) uniform _{buffer.Name}");
                 context.EnterScope();
                 context.EnterScope();
-                context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
-                context.LeaveScope($" {ubName}[{NumberFormatter.FormatInt(descriptors.Max(x => x.Slot) + 1)}];");
-            }
-            else
-            {
-                foreach (var descriptor in descriptors)
+
+                foreach (StructureField field in buffer.Type.Fields)
                 {
                 {
-                    string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+                    if (field.Type.HasFlag(AggregateType.Array))
+                    {
+                        string typeName = GetVarTypeName(context, field.Type & ~AggregateType.Array);
+                        string arraySize = field.ArrayLength.ToString(CultureInfo.InvariantCulture);
 
 
-                    ubName += "_" + DefaultNames.UniformNamePrefix + descriptor.Slot;
+                        context.AppendLine($"{typeName} {field.Name}[{arraySize}];");
+                    }
+                    else
+                    {
+                        string typeName = GetVarTypeName(context, field.Type);
 
 
-                    context.AppendLine($"layout (binding = {descriptor.Binding}, std140) uniform {ubName}");
-                    context.EnterScope();
-                    context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, descriptor.Slot, false) + ubSize + ";");
-                    context.LeaveScope(";");
+                        context.AppendLine($"{typeName} {field.Name};");
+                    }
                 }
                 }
+
+                context.LeaveScope($" {buffer.Name};");
+                context.AppendLine();
             }
             }
         }
         }
 
 
@@ -759,39 +750,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             context.AppendLine($"layout (location = {location}) patch out vec4 {name};");
             context.AppendLine($"layout (location = {location}) patch out vec4 {name};");
         }
         }
 
 
-        private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
-        {
-            bool needsSupportBlock = stage == ShaderStage.Fragment ||
-                (context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable());
-
-            if (!needsSupportBlock && scaleElements == 0)
-            {
-                return;
-            }
-
-            context.AppendLine($"layout (binding = 0, std140) uniform {DefaultNames.SupportBlockName}");
-            context.EnterScope();
-
-            switch (stage)
-            {
-                case ShaderStage.Fragment:
-                case ShaderStage.Vertex:
-                    context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
-                    context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
-                    context.AppendLine($"vec4 {DefaultNames.SupportBlockViewportInverse};");
-                    context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};");
-                    break;
-                case ShaderStage.Compute:
-                    context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];");
-                    break;
-            }
-
-            context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{SupportBuffer.RenderScaleMaxCount}];");
-
-            context.LeaveScope(";");
-            context.AppendLine();
-        }
-
         private static void AppendHelperFunction(CodeGenContext context, string filename)
         private static void AppendHelperFunction(CodeGenContext context, string filename)
         {
         {
             string code = EmbeddedResources.ReadAllText(filename);
             string code = EmbeddedResources.ReadAllText(filename);

+ 0 - 10
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs

@@ -15,18 +15,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
 
         public const string DataName = "data";
         public const string DataName = "data";
 
 
-        public const string SupportBlockName = "support_block";
-        public const string SupportBlockAlphaTestName = "s_alpha_test";
-        public const string SupportBlockIsBgraName = "s_is_bgra";
-        public const string SupportBlockViewportInverse = "s_viewport_inverse";
-        public const string SupportBlockFragmentScaleCount = "s_frag_scale_count";
-        public const string SupportBlockRenderScaleName = "s_render_scale";
-
         public const string BlockSuffix = "block";
         public const string BlockSuffix = "block";
 
 
-        public const string UniformNamePrefix = "c";
-        public const string UniformNameSuffix = "data";
-
         public const string LocalMemoryName  = "local_mem";
         public const string LocalMemoryName  = "local_mem";
         public const string SharedMemoryName = "shared_mem";
         public const string SharedMemoryName = "shared_mem";
 
 

+ 2 - 2
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl

@@ -1,6 +1,6 @@
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 {
 {
-    float scale = s_render_scale[samplerIndex];
+    float scale = support_buffer.s_render_scale[1 + samplerIndex];
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return inputVec;
         return inputVec;
@@ -10,7 +10,7 @@
 
 
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 {
 {
-    float scale = s_render_scale[samplerIndex];
+    float scale = support_buffer.s_render_scale[1 + samplerIndex];
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return size;
         return size;

+ 2 - 2
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl

@@ -1,6 +1,6 @@
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 {
 {
-    float scale = s_render_scale[1 + samplerIndex];
+    float scale = support_buffer.s_render_scale[1 + samplerIndex];
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return inputVec;
         return inputVec;
@@ -17,7 +17,7 @@
 
 
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 {
 {
-    float scale = abs(s_render_scale[1 + samplerIndex]);
+    float scale = abs(support_buffer.s_render_scale[1 + samplerIndex]);
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return size;
         return size;

+ 2 - 2
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl

@@ -1,6 +1,6 @@
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
 {
 {
-    float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
+    float scale = abs(support_buffer.s_render_scale[1 + samplerIndex + support_buffer.s_frag_scale_count]);
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return inputVec;
         return inputVec;
@@ -11,7 +11,7 @@
 
 
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 int Helper_TextureSizeUnscale(int size, int samplerIndex)
 {
 {
-    float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
+    float scale = abs(support_buffer.s_render_scale[1 + samplerIndex + support_buffer.s_frag_scale_count]);
     if (scale == 1.0)
     if (scale == 1.0)
     {
     {
         return size;
         return size;

+ 0 - 3
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs

@@ -167,9 +167,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                     case Instruction.Load:
                     case Instruction.Load:
                         return Load(context, operation);
                         return Load(context, operation);
 
 
-                    case Instruction.LoadConstant:
-                        return LoadConstant(context, operation);
-
                     case Instruction.LoadLocal:
                     case Instruction.LoadLocal:
                         return LoadLocal(context, operation);
                         return LoadLocal(context, operation);
 
 

+ 0 - 1
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs

@@ -83,7 +83,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
             Add(Instruction.ImageAtomic,              InstType.Special);
             Add(Instruction.ImageAtomic,              InstType.Special);
             Add(Instruction.IsNan,                    InstType.CallUnary,      "isnan");
             Add(Instruction.IsNan,                    InstType.CallUnary,      "isnan");
             Add(Instruction.Load,                     InstType.Special);
             Add(Instruction.Load,                     InstType.Special);
-            Add(Instruction.LoadConstant,             InstType.Special);
             Add(Instruction.LoadLocal,                InstType.Special);
             Add(Instruction.LoadLocal,                InstType.Special);
             Add(Instruction.LoadShared,               InstType.Special);
             Add(Instruction.LoadShared,               InstType.Special);
             Add(Instruction.LoadStorage,              InstType.Special);
             Add(Instruction.LoadStorage,              InstType.Special);

+ 47 - 51
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs

@@ -215,29 +215,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
             return GenerateLoadOrStore(context, operation, isStore: false);
             return GenerateLoadOrStore(context, operation, isStore: false);
         }
         }
 
 
-        public static string LoadConstant(CodeGenContext context, AstOperation operation)
-        {
-            IAstNode src1 = operation.GetSource(0);
-            IAstNode src2 = operation.GetSource(1);
-
-            string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
-            offsetExpr = Enclose(offsetExpr, src2, Instruction.ShiftRightS32, isLhs: true);
-
-            var config = context.Config;
-            bool indexElement = !config.GpuAccessor.QueryHostHasVectorIndexingBug();
-
-            if (src1 is AstOperand operand && operand.Type == OperandType.Constant)
-            {
-                bool cbIndexable = config.UsedFeatures.HasFlag(Translation.FeatureFlags.CbIndexing);
-                return OperandManager.GetConstantBufferName(operand.Value, offsetExpr, config.Stage, cbIndexable, indexElement);
-            }
-            else
-            {
-                string slotExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
-                return OperandManager.GetConstantBufferName(slotExpr, offsetExpr, config.Stage, indexElement);
-            }
-        }
-
         public static string LoadLocal(CodeGenContext context, AstOperation operation)
         public static string LoadLocal(CodeGenContext context, AstOperation operation)
         {
         {
             return LoadLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
             return LoadLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
@@ -809,9 +786,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
             string varName;
             string varName;
             AggregateType varType;
             AggregateType varType;
             int srcIndex = 0;
             int srcIndex = 0;
+            int inputsCount = isStore ? operation.SourcesCount - 1 : operation.SourcesCount;
 
 
             switch (storageKind)
             switch (storageKind)
             {
             {
+                case StorageKind.ConstantBuffer:
+                    if (!(operation.GetSource(srcIndex++) is AstOperand bindingIndex) || bindingIndex.Type != OperandType.Constant)
+                    {
+                        throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
+                    }
+
+                    int binding = bindingIndex.Value;
+                    BufferDefinition buffer = context.Config.Properties.ConstantBuffers[binding];
+
+                    if (!(operation.GetSource(srcIndex++) is AstOperand fieldIndex) || fieldIndex.Type != OperandType.Constant)
+                    {
+                        throw new InvalidOperationException($"Second input of {operation.Inst} with {storageKind} storage must be a constant operand.");
+                    }
+
+                    StructureField field = buffer.Type.Fields[fieldIndex.Value];
+                    varName = $"{buffer.Name}.{field.Name}";
+                    varType = field.Type;
+                    break;
+
                 case StorageKind.Input:
                 case StorageKind.Input:
                 case StorageKind.InputPerPatch:
                 case StorageKind.InputPerPatch:
                 case StorageKind.Output:
                 case StorageKind.Output:
@@ -864,40 +861,39 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                             varName = $"gl_out[{expr}].{varName}";
                             varName = $"gl_out[{expr}].{varName}";
                         }
                         }
                     }
                     }
-
-                    int firstSrcIndex = srcIndex;
-                    int inputsCount = isStore ? operation.SourcesCount - 1 : operation.SourcesCount;
-
-                    for (; srcIndex < inputsCount; srcIndex++)
-                    {
-                        IAstNode src = operation.GetSource(srcIndex);
-
-                        if ((varType & AggregateType.ElementCountMask) != 0 &&
-                            srcIndex == inputsCount - 1 &&
-                            src is AstOperand elementIndex &&
-                            elementIndex.Type == OperandType.Constant)
-                        {
-                            varName += "." + "xyzw"[elementIndex.Value & 3];
-                        }
-                        else if (srcIndex == firstSrcIndex && context.Config.Stage == ShaderStage.TessellationControl && storageKind == StorageKind.Output)
-                        {
-                            // GLSL requires that for tessellation control shader outputs,
-                            // that the index expression must be *exactly* "gl_InvocationID",
-                            // otherwise the compilation fails.
-                            // TODO: Get rid of this and use expression propagation to make sure we generate the correct code from IR.
-                            varName += "[gl_InvocationID]";
-                        }
-                        else
-                        {
-                            varName += $"[{GetSoureExpr(context, src, AggregateType.S32)}]";
-                        }
-                    }
                     break;
                     break;
 
 
                 default:
                 default:
                     throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
                     throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
             }
             }
 
 
+            int firstSrcIndex = srcIndex;
+
+            for (; srcIndex < inputsCount; srcIndex++)
+            {
+                IAstNode src = operation.GetSource(srcIndex);
+
+                if ((varType & AggregateType.ElementCountMask) != 0 &&
+                    srcIndex == inputsCount - 1 &&
+                    src is AstOperand elementIndex &&
+                    elementIndex.Type == OperandType.Constant)
+                {
+                    varName += "." + "xyzw"[elementIndex.Value & 3];
+                }
+                else if (srcIndex == firstSrcIndex && context.Config.Stage == ShaderStage.TessellationControl && storageKind == StorageKind.Output)
+                {
+                    // GLSL requires that for tessellation control shader outputs,
+                    // that the index expression must be *exactly* "gl_InvocationID",
+                    // otherwise the compilation fails.
+                    // TODO: Get rid of this and use expression propagation to make sure we generate the correct code from IR.
+                    varName += "[gl_InvocationID]";
+                }
+                else
+                {
+                    varName += $"[{GetSoureExpr(context, src, AggregateType.S32)}]";
+                }
+            }
+
             if (isStore)
             if (isStore)
             {
             {
                 varType &= AggregateType.ElementTypeMask;
                 varType &= AggregateType.ElementTypeMask;

+ 0 - 3
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/IoMap.cs

@@ -27,7 +27,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                 IoVariable.FragmentCoord => ("gl_FragCoord", AggregateType.Vector4 | AggregateType.FP32),
                 IoVariable.FragmentCoord => ("gl_FragCoord", AggregateType.Vector4 | AggregateType.FP32),
                 IoVariable.FragmentOutputColor => GetFragmentOutputColorVariableName(config, location),
                 IoVariable.FragmentOutputColor => GetFragmentOutputColorVariableName(config, location),
                 IoVariable.FragmentOutputDepth => ("gl_FragDepth", AggregateType.FP32),
                 IoVariable.FragmentOutputDepth => ("gl_FragDepth", AggregateType.FP32),
-                IoVariable.FragmentOutputIsBgra => (DefaultNames.SupportBlockIsBgraName, AggregateType.Array | AggregateType.Bool),
                 IoVariable.FrontColorDiffuse => ("gl_FrontColor", AggregateType.Vector4 | AggregateType.FP32), // Deprecated.
                 IoVariable.FrontColorDiffuse => ("gl_FrontColor", AggregateType.Vector4 | AggregateType.FP32), // Deprecated.
                 IoVariable.FrontColorSpecular  => ("gl_FrontSecondaryColor", AggregateType.Vector4 | AggregateType.FP32), // Deprecated.
                 IoVariable.FrontColorSpecular  => ("gl_FrontSecondaryColor", AggregateType.Vector4 | AggregateType.FP32), // Deprecated.
                 IoVariable.FrontFacing => ("gl_FrontFacing", AggregateType.Bool),
                 IoVariable.FrontFacing => ("gl_FrontFacing", AggregateType.Bool),
@@ -46,8 +45,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                 IoVariable.SubgroupLaneId => GetSubgroupInvocationIdVariableName(config),
                 IoVariable.SubgroupLaneId => GetSubgroupInvocationIdVariableName(config),
                 IoVariable.SubgroupLeMask => GetSubgroupMaskVariableName(config, "Le"),
                 IoVariable.SubgroupLeMask => GetSubgroupMaskVariableName(config, "Le"),
                 IoVariable.SubgroupLtMask => GetSubgroupMaskVariableName(config, "Lt"),
                 IoVariable.SubgroupLtMask => GetSubgroupMaskVariableName(config, "Lt"),
-                IoVariable.SupportBlockRenderScale => (DefaultNames.SupportBlockRenderScaleName, AggregateType.Array | AggregateType.FP32),
-                IoVariable.SupportBlockViewInverse => (DefaultNames.SupportBlockViewportInverse, AggregateType.Vector2 | AggregateType.FP32),
                 IoVariable.TessellationCoord => ("gl_TessCoord", AggregateType.Vector3 | AggregateType.FP32),
                 IoVariable.TessellationCoord => ("gl_TessCoord", AggregateType.Vector3 | AggregateType.FP32),
                 IoVariable.TessellationLevelInner => ("gl_TessLevelInner", AggregateType.Array | AggregateType.FP32),
                 IoVariable.TessellationLevelInner => ("gl_TessLevelInner", AggregateType.Array | AggregateType.FP32),
                 IoVariable.TessellationLevelOuter => ("gl_TessLevelOuter", AggregateType.Array | AggregateType.FP32),
                 IoVariable.TessellationLevelOuter => ("gl_TessLevelOuter", AggregateType.Array | AggregateType.FP32),

+ 16 - 51
src/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs

@@ -36,63 +36,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             {
             {
                 OperandType.Argument => GetArgumentName(operand.Value),
                 OperandType.Argument => GetArgumentName(operand.Value),
                 OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
                 OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
-                OperandType.ConstantBuffer => GetConstantBufferName(operand, context.Config),
                 OperandType.LocalVariable => _locals[operand],
                 OperandType.LocalVariable => _locals[operand],
                 OperandType.Undefined => DefaultNames.UndefinedName,
                 OperandType.Undefined => DefaultNames.UndefinedName,
                 _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
                 _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
             };
             };
         }
         }
 
 
-        private static string GetConstantBufferName(AstOperand operand, ShaderConfig config)
-        {
-            return GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage, config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing));
-        }
-
-        public static string GetConstantBufferName(int slot, int offset, ShaderStage stage, bool cbIndexable)
-        {
-            return $"{GetUbName(stage, slot, cbIndexable)}[{offset >> 2}].{GetSwizzleMask(offset & 3)}";
-        }
-
-        private static string GetVec4Indexed(string vectorName, string indexExpr, bool indexElement)
-        {
-            if (indexElement)
-            {
-                return $"{vectorName}[{indexExpr}]";
-            }
-
-            string result = $"{vectorName}.x";
-            for (int i = 1; i < 4; i++)
-            {
-                result = $"(({indexExpr}) == {i}) ? ({vectorName}.{GetSwizzleMask(i)}) : ({result})";
-            }
-            return $"({result})";
-        }
-
-        public static string GetConstantBufferName(int slot, string offsetExpr, ShaderStage stage, bool cbIndexable, bool indexElement)
-        {
-            return GetVec4Indexed(GetUbName(stage, slot, cbIndexable) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
-        }
-
-        public static string GetConstantBufferName(string slotExpr, string offsetExpr, ShaderStage stage, bool indexElement)
-        {
-            return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
-        }
-
-        public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
-        {
-            if (cbIndexable)
-            {
-                return GetUbName(stage, NumberFormatter.FormatInt(slot, AggregateType.S32));
-            }
-
-            return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}{slot}_{DefaultNames.UniformNameSuffix}";
-        }
-
-        private static string GetUbName(ShaderStage stage, string slotExpr)
-        {
-            return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}[{slotExpr}].{DefaultNames.DataName}";
-        }
-
         public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
         public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
         {
         {
             return GetSamplerName(stage, texOp.CbufSlot, texOp.Handle, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
             return GetSamplerName(stage, texOp.CbufSlot, texOp.Handle, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
@@ -168,6 +117,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 {
                 {
                     switch (operation.StorageKind)
                     switch (operation.StorageKind)
                     {
                     {
+                        case StorageKind.ConstantBuffer:
+                            if (!(operation.GetSource(0) is AstOperand bindingIndex) || bindingIndex.Type != OperandType.Constant)
+                            {
+                                throw new InvalidOperationException($"First input of {operation.Inst} with {operation.StorageKind} storage must be a constant operand.");
+                            }
+
+                            if (!(operation.GetSource(1) is AstOperand fieldIndex) || fieldIndex.Type != OperandType.Constant)
+                            {
+                                throw new InvalidOperationException($"Second input of {operation.Inst} with {operation.StorageKind} storage must be a constant operand.");
+                            }
+
+                            BufferDefinition buffer = context.Config.Properties.ConstantBuffers[bindingIndex.Value];
+                            StructureField field = buffer.Type.Fields[fieldIndex.Value];
+
+                            return field.Type & AggregateType.ElementTypeMask;
+
                         case StorageKind.Input:
                         case StorageKind.Input:
                         case StorageKind.InputPerPatch:
                         case StorageKind.InputPerPatch:
                         case StorageKind.Output:
                         case StorageKind.Output:

+ 1 - 29
src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs

@@ -23,9 +23,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
 
         public int InputVertices { get; }
         public int InputVertices { get; }
 
 
-        public Dictionary<int, Instruction> UniformBuffers { get; } = new Dictionary<int, Instruction>();
-        public Instruction SupportBuffer { get; set; }
-        public Instruction UniformBuffersArray { get; set; }
+        public Dictionary<int, Instruction> ConstantBuffers { get; } = new Dictionary<int, Instruction>();
         public Instruction StorageBuffersArray { get; set; }
         public Instruction StorageBuffersArray { get; set; }
         public Instruction LocalMemory { get; set; }
         public Instruction LocalMemory { get; set; }
         public Instruction SharedMemory { get; set; }
         public Instruction SharedMemory { get; set; }
@@ -217,7 +215,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                 {
                 {
                     IrOperandType.Argument => GetArgument(type, operand),
                     IrOperandType.Argument => GetArgument(type, operand),
                     IrOperandType.Constant => GetConstant(type, operand),
                     IrOperandType.Constant => GetConstant(type, operand),
-                    IrOperandType.ConstantBuffer => GetConstantBuffer(type, operand),
                     IrOperandType.LocalVariable => GetLocal(type, operand),
                     IrOperandType.LocalVariable => GetLocal(type, operand),
                     IrOperandType.Undefined => GetUndefined(type),
                     IrOperandType.Undefined => GetUndefined(type),
                     _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
                     _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
@@ -274,31 +271,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             };
             };
         }
         }
 
 
-        public Instruction GetConstantBuffer(AggregateType type, AstOperand operand)
-        {
-            var i1 = Constant(TypeS32(), 0);
-            var i2 = Constant(TypeS32(), operand.CbufOffset >> 2);
-            var i3 = Constant(TypeU32(), operand.CbufOffset & 3);
-
-            Instruction elemPointer;
-
-            if (UniformBuffersArray != null)
-            {
-                var ubVariable = UniformBuffersArray;
-                var i0 = Constant(TypeS32(), operand.CbufSlot);
-
-                elemPointer = AccessChain(TypePointer(StorageClass.Uniform, TypeFP32()), ubVariable, i0, i1, i2, i3);
-            }
-            else
-            {
-                var ubVariable = UniformBuffers[operand.CbufSlot];
-
-                elemPointer = AccessChain(TypePointer(StorageClass.Uniform, TypeFP32()), ubVariable, i1, i2, i3);
-            }
-
-            return BitcastIfNeeded(type, AggregateType.FP32, Load(TypeFP32(), elemPointer));
-        }
-
         public Instruction GetLocalPointer(AstOperand local)
         public Instruction GetLocalPointer(AstOperand local)
         {
         {
             return _locals[local];
             return _locals[local];

+ 48 - 81
src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs

@@ -98,8 +98,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                 DeclareLocalMemory(context, localMemorySize);
                 DeclareLocalMemory(context, localMemorySize);
             }
             }
 
 
-            DeclareSupportBuffer(context);
-            DeclareUniformBuffers(context, context.Config.GetConstantBufferDescriptors());
+            DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values);
             DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors());
             DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors());
             DeclareSamplers(context, context.Config.GetTextureDescriptors());
             DeclareSamplers(context, context.Config.GetTextureDescriptors());
             DeclareImages(context, context.Config.GetImageDescriptors());
             DeclareImages(context, context.Config.GetImageDescriptors());
@@ -127,84 +126,63 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             return variable;
             return variable;
         }
         }
 
 
-        private static void DeclareSupportBuffer(CodeGenContext context)
+        private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
         {
         {
-            if (!context.Config.Stage.SupportsRenderScale() && !(context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable()))
-            {
-                return;
-            }
-
-            var isBgraArrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), SupportBuffer.FragmentIsBgraCount));
-            var viewportInverseVectorType = context.TypeVector(context.TypeFP32(), 4);
-            var renderScaleArrayType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), SupportBuffer.RenderScaleMaxCount));
-
-            context.Decorate(isBgraArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
-            context.Decorate(renderScaleArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
-
-            var supportBufferStructType = context.TypeStruct(false, context.TypeU32(), isBgraArrayType, viewportInverseVectorType, context.TypeS32(), renderScaleArrayType);
+            HashSet<SpvInstruction> decoratedTypes = new HashSet<SpvInstruction>();
 
 
-            context.MemberDecorate(supportBufferStructType, 0, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentAlphaTestOffset);
-            context.MemberDecorate(supportBufferStructType, 1, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentIsBgraOffset);
-            context.MemberDecorate(supportBufferStructType, 2, Decoration.Offset, (LiteralInteger)SupportBuffer.ViewportInverseOffset);
-            context.MemberDecorate(supportBufferStructType, 3, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentRenderScaleCountOffset);
-            context.MemberDecorate(supportBufferStructType, 4, Decoration.Offset, (LiteralInteger)SupportBuffer.GraphicsRenderScaleOffset);
-            context.Decorate(supportBufferStructType, Decoration.Block);
+            foreach (BufferDefinition buffer in buffers)
+            {
+                int alignment = buffer.Layout == BufferLayout.Std140 ? 16 : 4;
+                int alignmentMask = alignment - 1;
+                int offset = 0;
 
 
-            var supportBufferPointerType = context.TypePointer(StorageClass.Uniform, supportBufferStructType);
-            var supportBufferVariable = context.Variable(supportBufferPointerType, StorageClass.Uniform);
+                SpvInstruction[] structFieldTypes = new SpvInstruction[buffer.Type.Fields.Length];
+                int[] structFieldOffsets = new int[buffer.Type.Fields.Length];
 
 
-            context.Decorate(supportBufferVariable, Decoration.DescriptorSet, (LiteralInteger)0);
-            context.Decorate(supportBufferVariable, Decoration.Binding, (LiteralInteger)0);
+                for (int fieldIndex = 0; fieldIndex < buffer.Type.Fields.Length; fieldIndex++)
+                {
+                    StructureField field = buffer.Type.Fields[fieldIndex];
+                    int fieldSize = (field.Type.GetSizeInBytes() + alignmentMask) & ~alignmentMask;
 
 
-            context.AddGlobalVariable(supportBufferVariable);
+                    structFieldTypes[fieldIndex] = context.GetType(field.Type, field.ArrayLength);
+                    structFieldOffsets[fieldIndex] = offset;
 
 
-            context.SupportBuffer = supportBufferVariable;
-        }
+                    if (field.Type.HasFlag(AggregateType.Array))
+                    {
+                        // We can't decorate the type more than once.
+                        if (decoratedTypes.Add(structFieldTypes[fieldIndex]))
+                        {
+                            context.Decorate(structFieldTypes[fieldIndex], Decoration.ArrayStride, (LiteralInteger)fieldSize);
+                        }
 
 
-        private static void DeclareUniformBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
-        {
-            if (descriptors.Length == 0)
-            {
-                return;
-            }
+                        offset += fieldSize * field.ArrayLength;
+                    }
+                    else
+                    {
+                        offset += fieldSize;
+                    }
+                }
 
 
-            uint ubSize = Constants.ConstantBufferSize / 16;
+                var ubStructType = context.TypeStruct(false, structFieldTypes);
 
 
-            var ubArrayType = context.TypeArray(context.TypeVector(context.TypeFP32(), 4), context.Constant(context.TypeU32(), ubSize), true);
-            context.Decorate(ubArrayType, Decoration.ArrayStride, (LiteralInteger)16);
-            var ubStructType = context.TypeStruct(true, ubArrayType);
-            context.Decorate(ubStructType, Decoration.Block);
-            context.MemberDecorate(ubStructType, 0, Decoration.Offset, (LiteralInteger)0);
+                if (decoratedTypes.Add(ubStructType))
+                {
+                    context.Decorate(ubStructType, Decoration.Block);
 
 
-            if (context.Config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
-            {
-                int count = descriptors.Max(x => x.Slot) + 1;
+                    for (int fieldIndex = 0; fieldIndex < structFieldOffsets.Length; fieldIndex++)
+                    {
+                        context.MemberDecorate(ubStructType, fieldIndex, Decoration.Offset, (LiteralInteger)structFieldOffsets[fieldIndex]);
+                    }
+                }
 
 
-                var ubStructArrayType = context.TypeArray(ubStructType, context.Constant(context.TypeU32(), count));
-                var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructArrayType);
+                var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructType);
                 var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
                 var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
 
 
-                context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_u");
-                context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
-                context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstConstantBufferBinding);
+                context.Name(ubVariable, buffer.Name);
+                context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)buffer.Set);
+                context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)buffer.Binding);
                 context.AddGlobalVariable(ubVariable);
                 context.AddGlobalVariable(ubVariable);
-
-                context.UniformBuffersArray = ubVariable;
-            }
-            else
-            {
-                var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructType);
-
-                foreach (var descriptor in descriptors)
-                {
-                    var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
-
-                    context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_c{descriptor.Slot}");
-                    context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
-                    context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
-                    context.AddGlobalVariable(ubVariable);
-                    context.UniformBuffers.Add(descriptor.Slot, ubVariable);
-                }
+                context.ConstantBuffers.Add(buffer.Binding, ubVariable);
             }
             }
         }
         }
 
 
@@ -394,25 +372,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
         {
         {
             foreach (var ioDefinition in info.IoDefinitions)
             foreach (var ioDefinition in info.IoDefinitions)
             {
             {
-                var ioVariable = ioDefinition.IoVariable;
-
-                // Those are actually from constant buffer, rather than being actual inputs or outputs,
-                // so we must ignore them here as they are declared as part of the support buffer.
-                // TODO: Delete this after we represent this properly on the IR (as a constant buffer rather than "input").
-                if (ioVariable == IoVariable.FragmentOutputIsBgra ||
-                    ioVariable == IoVariable.SupportBlockRenderScale ||
-                    ioVariable == IoVariable.SupportBlockViewInverse)
-                {
-                    continue;
-                }
-
-                bool isOutput = ioDefinition.StorageKind.IsOutput();
-                bool isPerPatch = ioDefinition.StorageKind.IsPerPatch();
-
                 PixelImap iq = PixelImap.Unused;
                 PixelImap iq = PixelImap.Unused;
 
 
                 if (context.Config.Stage == ShaderStage.Fragment)
                 if (context.Config.Stage == ShaderStage.Fragment)
                 {
                 {
+                    var ioVariable = ioDefinition.IoVariable;
                     if (ioVariable == IoVariable.UserDefined)
                     if (ioVariable == IoVariable.UserDefined)
                     {
                     {
                         iq = context.Config.ImapTypes[ioDefinition.Location].GetFirstUsedType();
                         iq = context.Config.ImapTypes[ioDefinition.Location].GetFirstUsedType();
@@ -429,6 +393,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                     }
                     }
                 }
                 }
 
 
+                bool isOutput = ioDefinition.StorageKind.IsOutput();
+                bool isPerPatch = ioDefinition.StorageKind.IsPerPatch();
+
                 DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq);
                 DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq);
             }
             }
         }
         }

+ 63 - 130
src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs

@@ -98,7 +98,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             Add(Instruction.ImageStore,               GenerateImageStore);
             Add(Instruction.ImageStore,               GenerateImageStore);
             Add(Instruction.IsNan,                    GenerateIsNan);
             Add(Instruction.IsNan,                    GenerateIsNan);
             Add(Instruction.Load,                     GenerateLoad);
             Add(Instruction.Load,                     GenerateLoad);
-            Add(Instruction.LoadConstant,             GenerateLoadConstant);
             Add(Instruction.LoadLocal,                GenerateLoadLocal);
             Add(Instruction.LoadLocal,                GenerateLoadLocal);
             Add(Instruction.LoadShared,               GenerateLoadShared);
             Add(Instruction.LoadShared,               GenerateLoadShared);
             Add(Instruction.LoadStorage,              GenerateLoadStorage);
             Add(Instruction.LoadStorage,              GenerateLoadStorage);
@@ -313,10 +312,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
 
             for (int i = 0; i < args.Length; i++)
             for (int i = 0; i < args.Length; i++)
             {
             {
-                var operand = (AstOperand)operation.GetSource(i + 1);
+                var operand = operation.GetSource(i + 1);
+
                 if (i >= function.InArguments.Length)
                 if (i >= function.InArguments.Length)
                 {
                 {
-                    args[i] = context.GetLocalPointer(operand);
+                    args[i] = context.GetLocalPointer((AstOperand)operand);
                 }
                 }
                 else
                 else
                 {
                 {
@@ -867,68 +867,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             return GenerateLoadOrStore(context, operation, isStore: false);
             return GenerateLoadOrStore(context, operation, isStore: false);
         }
         }
 
 
-        private static OperationResult GenerateLoadConstant(CodeGenContext context, AstOperation operation)
-        {
-            var src1 = operation.GetSource(0);
-            var src2 = context.Get(AggregateType.S32, operation.GetSource(1));
-
-            var i1 = context.Constant(context.TypeS32(), 0);
-            var i2 = context.ShiftRightArithmetic(context.TypeS32(), src2, context.Constant(context.TypeS32(), 2));
-            var i3 = context.BitwiseAnd(context.TypeS32(), src2, context.Constant(context.TypeS32(), 3));
-
-            SpvInstruction value = null;
-
-            if (context.Config.GpuAccessor.QueryHostHasVectorIndexingBug())
-            {
-                // Test for each component individually.
-                for (int i = 0; i < 4; i++)
-                {
-                    var component = context.Constant(context.TypeS32(), i);
-
-                    SpvInstruction elemPointer;
-                    if (context.UniformBuffersArray != null)
-                    {
-                        var ubVariable = context.UniformBuffersArray;
-                        var i0 = context.Get(AggregateType.S32, src1);
-
-                        elemPointer = context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeFP32()), ubVariable, i0, i1, i2, component);
-                    }
-                    else
-                    {
-                        var ubVariable = context.UniformBuffers[((AstOperand)src1).Value];
-
-                        elemPointer = context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeFP32()), ubVariable, i1, i2, component);
-                    }
-
-                    SpvInstruction newValue = context.Load(context.TypeFP32(), elemPointer);
-
-                    value = value != null ? context.Select(context.TypeFP32(), context.IEqual(context.TypeBool(), i3, component), newValue, value) : newValue;
-                }
-            }
-            else
-            {
-                SpvInstruction elemPointer;
-
-                if (context.UniformBuffersArray != null)
-                {
-                    var ubVariable = context.UniformBuffersArray;
-                    var i0 = context.Get(AggregateType.S32, src1);
-
-                    elemPointer = context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeFP32()), ubVariable, i0, i1, i2, i3);
-                }
-                else
-                {
-                    var ubVariable = context.UniformBuffers[((AstOperand)src1).Value];
-
-                    elemPointer = context.AccessChain(context.TypePointer(StorageClass.Uniform, context.TypeFP32()), ubVariable, i1, i2, i3);
-                }
-
-                value = context.Load(context.TypeFP32(), elemPointer);
-            }
-
-            return new OperationResult(AggregateType.FP32, value);
-        }
-
         private static OperationResult GenerateLoadLocal(CodeGenContext context, AstOperation operation)
         private static OperationResult GenerateLoadLocal(CodeGenContext context, AstOperation operation)
         {
         {
             return GenerateLoadLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory);
             return GenerateLoadLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory);
@@ -1990,12 +1928,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
         {
         {
             StorageKind storageKind = operation.StorageKind;
             StorageKind storageKind = operation.StorageKind;
 
 
-            SpvInstruction pointer;
+            StorageClass storageClass;
+            SpvInstruction baseObj;
             AggregateType varType;
             AggregateType varType;
             int srcIndex = 0;
             int srcIndex = 0;
 
 
             switch (storageKind)
             switch (storageKind)
             {
             {
+                case StorageKind.ConstantBuffer:
+                    if (!(operation.GetSource(srcIndex++) is AstOperand bindingIndex) || bindingIndex.Type != OperandType.Constant)
+                    {
+                        throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
+                    }
+
+                    if (!(operation.GetSource(srcIndex) is AstOperand fieldIndex) || fieldIndex.Type != OperandType.Constant)
+                    {
+                        throw new InvalidOperationException($"Second input of {operation.Inst} with {storageKind} storage must be a constant operand.");
+                    }
+
+                    BufferDefinition buffer = context.Config.Properties.ConstantBuffers[bindingIndex.Value];
+                    StructureField field = buffer.Type.Fields[fieldIndex.Value];
+
+                    storageClass = StorageClass.Uniform;
+                    varType = field.Type & AggregateType.ElementTypeMask;
+                    baseObj = context.ConstantBuffers[bindingIndex.Value];
+                    break;
+
                 case StorageKind.Input:
                 case StorageKind.Input:
                 case StorageKind.InputPerPatch:
                 case StorageKind.InputPerPatch:
                 case StorageKind.Output:
                 case StorageKind.Output:
@@ -2038,33 +1996,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                     {
                     {
                         varType = context.Config.GetFragmentOutputColorType(location);
                         varType = context.Config.GetFragmentOutputColorType(location);
                     }
                     }
-                    else if (ioVariable == IoVariable.FragmentOutputIsBgra)
-                    {
-                        var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeU32());
-                        var elemIndex = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                        pointer = context.AccessChain(pointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 1), elemIndex);
-                        varType = AggregateType.U32;
-
-                        break;
-                    }
-                    else if (ioVariable == IoVariable.SupportBlockRenderScale)
-                    {
-                        var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
-                        var elemIndex = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                        pointer = context.AccessChain(pointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 4), elemIndex);
-                        varType = AggregateType.FP32;
-
-                        break;
-                    }
-                    else if (ioVariable == IoVariable.SupportBlockViewInverse)
-                    {
-                        var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
-                        var elemIndex = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                        pointer = context.AccessChain(pointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 2), elemIndex);
-                        varType = AggregateType.FP32;
-
-                        break;
-                    }
                     else
                     else
                     {
                     {
                         (_, varType) = IoMap.GetSpirvBuiltIn(ioVariable);
                         (_, varType) = IoMap.GetSpirvBuiltIn(ioVariable);
@@ -2072,55 +2003,57 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
 
                     varType &= AggregateType.ElementTypeMask;
                     varType &= AggregateType.ElementTypeMask;
 
 
-                    int inputsCount = (isStore ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
-                    var storageClass = isOutput ? StorageClass.Output : StorageClass.Input;
+                    storageClass = isOutput ? StorageClass.Output : StorageClass.Input;
 
 
                     var ioDefinition = new IoDefinition(storageKind, ioVariable, location, component);
                     var ioDefinition = new IoDefinition(storageKind, ioVariable, location, component);
                     var dict = isPerPatch
                     var dict = isPerPatch
                         ? (isOutput ? context.OutputsPerPatch : context.InputsPerPatch)
                         ? (isOutput ? context.OutputsPerPatch : context.InputsPerPatch)
                         : (isOutput ? context.Outputs : context.Inputs);
                         : (isOutput ? context.Outputs : context.Inputs);
 
 
-                    SpvInstruction baseObj = dict[ioDefinition];
-                    SpvInstruction e0, e1, e2;
-
-                    switch (inputsCount)
-                    {
-                        case 0:
-                            pointer = baseObj;
-                            break;
-                        case 1:
-                            e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0);
-                            break;
-                        case 2:
-                            e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            e1 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0, e1);
-                            break;
-                        case 3:
-                            e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            e1 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            e2 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
-                            pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0, e1, e2);
-                            break;
-                        default:
-                            var indexes = new SpvInstruction[inputsCount];
-                            int index = 0;
-
-                            for (; index < inputsCount; srcIndex++, index++)
-                            {
-                                indexes[index] = context.Get(AggregateType.S32, operation.GetSource(srcIndex));
-                            }
-
-                            pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, indexes);
-                            break;
-                    }
+                    baseObj = dict[ioDefinition];
                     break;
                     break;
 
 
                 default:
                 default:
                     throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
                     throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
             }
             }
 
 
+            int inputsCount = (isStore ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
+            SpvInstruction e0, e1, e2;
+            SpvInstruction pointer;
+
+            switch (inputsCount)
+            {
+                case 0:
+                    pointer = baseObj;
+                    break;
+                case 1:
+                    e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0);
+                    break;
+                case 2:
+                    e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    e1 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0, e1);
+                    break;
+                case 3:
+                    e0 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    e1 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    e2 = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
+                    pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, e0, e1, e2);
+                    break;
+                default:
+                    var indexes = new SpvInstruction[inputsCount];
+                    int index = 0;
+
+                    for (; index < inputsCount; srcIndex++, index++)
+                    {
+                        indexes[index] = context.Get(AggregateType.S32, operation.GetSource(srcIndex));
+                    }
+
+                    pointer = context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, indexes);
+                    break;
+            }
+
             if (isStore)
             if (isStore)
             {
             {
                 context.Store(pointer, context.Get(varType, operation.GetSource(srcIndex)));
                 context.Store(pointer, context.Get(varType, operation.GetSource(srcIndex)));

+ 4 - 4
src/Ryujinx.Graphics.Shader/CodeGen/Spirv/ScalingHelpers.cs

@@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             if (context.Config.Stage == ShaderStage.Vertex)
             if (context.Config.Stage == ShaderStage.Vertex)
             {
             {
                 var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
                 var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
-                var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
+                var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.ConstantBuffers[0], context.Constant(context.TypeU32(), 3));
                 var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
                 var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
 
 
                 scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
                 scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
@@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
 
             scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
             scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
 
 
-            var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
+            var scaleElemPointer = context.AccessChain(pointerType, context.ConstantBuffers[0], fieldIndex, scaleIndex);
             var scale = context.Load(context.TypeFP32(), scaleElemPointer);
             var scale = context.Load(context.TypeFP32(), scaleElemPointer);
 
 
             var ivector2Type = context.TypeVector(context.TypeS32(), 2);
             var ivector2Type = context.TypeVector(context.TypeS32(), 2);
@@ -201,7 +201,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                 if (context.Config.Stage == ShaderStage.Vertex)
                 if (context.Config.Stage == ShaderStage.Vertex)
                 {
                 {
                     var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
                     var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
-                    var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
+                    var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.ConstantBuffers[0], context.Constant(context.TypeU32(), 3));
                     var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
                     var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
 
 
                     scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
                     scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
@@ -209,7 +209,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
 
                 scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
                 scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
 
 
-                var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
+                var scaleElemPointer = context.AccessChain(pointerType, context.ConstantBuffers[0], fieldIndex, scaleIndex);
                 var scale = context.GlslFAbs(context.TypeFP32(), context.Load(context.TypeFP32(), scaleElemPointer));
                 var scale = context.GlslFAbs(context.TypeFP32(), context.Load(context.TypeFP32(), scaleElemPointer));
 
 
                 var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));
                 var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));

+ 1 - 1
src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs

@@ -160,7 +160,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
                 {
                 {
                     // FragCoord X/Y must be divided by the render target scale, if resolution scaling is active,
                     // FragCoord X/Y must be divided by the render target scale, if resolution scaling is active,
                     // because the shader code is not expecting scaled values.
                     // because the shader code is not expecting scaled values.
-                    res = context.FPDivide(res, context.Load(StorageKind.Input, IoVariable.SupportBlockRenderScale, null, Const(0)));
+                    res = context.FPDivide(res, context.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.RenderScale), Const(0)));
                 }
                 }
                 else if (op.Imm10 == AttributeConsts.FrontFacing && context.Config.GpuAccessor.QueryHostHasFrontFacingBug())
                 else if (op.Imm10 == AttributeConsts.FrontFacing && context.Config.GpuAccessor.QueryHostHasFrontFacingBug())
                 {
                 {

+ 36 - 3
src/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs

@@ -1,6 +1,7 @@
 using Ryujinx.Graphics.Shader.Decoders;
 using Ryujinx.Graphics.Shader.Decoders;
 using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using Ryujinx.Graphics.Shader.Translation;
 using Ryujinx.Graphics.Shader.Translation;
+using System.Numerics;
 
 
 using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
 using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -80,7 +81,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
 
             Operand addr = context.IAdd(srcA, Const(Imm16ToSInt(op.CbufOffset)));
             Operand addr = context.IAdd(srcA, Const(Imm16ToSInt(op.CbufOffset)));
             Operand wordOffset = context.ShiftRightU32(addr, Const(2));
             Operand wordOffset = context.ShiftRightU32(addr, Const(2));
-            Operand bitOffset = GetBitOffset(context, addr);
 
 
             for (int index = 0; index < count; index++)
             for (int index = 0; index < count; index++)
             {
             {
@@ -92,11 +92,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
                 }
                 }
 
 
                 Operand offset = context.IAdd(wordOffset, Const(index));
                 Operand offset = context.IAdd(wordOffset, Const(index));
-                Operand value = context.LoadConstant(slot, offset);
+                Operand value = EmitLoadConstant(context, slot, offset);
 
 
                 if (isSmallInt)
                 if (isSmallInt)
                 {
                 {
-                    value = ExtractSmallInt(context, (LsSize)op.LsSize, bitOffset, value);
+                    value = ExtractSmallInt(context, (LsSize)op.LsSize, GetBitOffset(context, addr), value);
                 }
                 }
 
 
                 context.Copy(Register(dest), value);
                 context.Copy(Register(dest), value);
@@ -154,6 +154,39 @@ namespace Ryujinx.Graphics.Shader.Instructions
             EmitStore(context, MemoryRegion.Shared, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
             EmitStore(context, MemoryRegion.Shared, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
         }
         }
 
 
+        private static Operand EmitLoadConstant(EmitterContext context, Operand slot, Operand offset)
+        {
+            Operand vecIndex = context.ShiftRightU32(offset, Const(2));
+            Operand elemIndex = context.BitwiseAnd(offset, Const(3));
+
+            if (slot.Type == OperandType.Constant)
+            {
+                int binding = context.Config.ResourceManager.GetConstantBufferBinding(slot.Value);
+                return context.Load(StorageKind.ConstantBuffer, binding, Const(0), vecIndex, elemIndex);
+            }
+            else
+            {
+                Operand value = Const(0);
+
+                uint cbUseMask = context.Config.GpuAccessor.QueryConstantBufferUse();
+
+                while (cbUseMask != 0)
+                {
+                    int cbIndex = BitOperations.TrailingZeroCount(cbUseMask);
+                    int binding = context.Config.ResourceManager.GetConstantBufferBinding(cbIndex);
+
+                    Operand isCurrent = context.ICompareEqual(slot, Const(cbIndex));
+                    Operand currentValue = context.Load(StorageKind.ConstantBuffer, binding, Const(0), vecIndex, elemIndex);
+
+                    value = context.ConditionalSelect(isCurrent, currentValue, value);
+
+                    cbUseMask &= ~(1u << cbIndex);
+                }
+
+                return value;
+            }
+        }
+
         private static Operand EmitAtomicOp(
         private static Operand EmitAtomicOp(
             EmitterContext context,
             EmitterContext context,
             StorageKind storageKind,
             StorageKind storageKind,

+ 0 - 1
src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs

@@ -79,7 +79,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
         ImageAtomic,
         ImageAtomic,
         IsNan,
         IsNan,
         Load,
         Load,
-        LoadConstant,
         LoadGlobal,
         LoadGlobal,
         LoadLocal,
         LoadLocal,
         LoadShared,
         LoadShared,

+ 0 - 3
src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IoVariable.cs

@@ -15,7 +15,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
         FragmentCoord,
         FragmentCoord,
         FragmentOutputColor,
         FragmentOutputColor,
         FragmentOutputDepth,
         FragmentOutputDepth,
-        FragmentOutputIsBgra, // TODO: Remove and use constant buffer access.
         FrontColorDiffuse,
         FrontColorDiffuse,
         FrontColorSpecular,
         FrontColorSpecular,
         FrontFacing,
         FrontFacing,
@@ -34,8 +33,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
         SubgroupLaneId,
         SubgroupLaneId,
         SubgroupLeMask,
         SubgroupLeMask,
         SubgroupLtMask,
         SubgroupLtMask,
-        SupportBlockViewInverse, // TODO: Remove and use constant buffer access.
-        SupportBlockRenderScale, // TODO: Remove and use constant buffer access.
         TessellationCoord,
         TessellationCoord,
         TessellationLevelInner,
         TessellationLevelInner,
         TessellationLevelOuter,
         TessellationLevelOuter,

+ 1 - 13
src/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs

@@ -15,9 +15,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
 
         public int Value { get; }
         public int Value { get; }
 
 
-        public int CbufSlot   { get; }
-        public int CbufOffset { get; }
-
         private AstOperand()
         private AstOperand()
         {
         {
             Defs = new HashSet<IAstNode>();
             Defs = new HashSet<IAstNode>();
@@ -29,16 +26,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
         public AstOperand(Operand operand) : this()
         public AstOperand(Operand operand) : this()
         {
         {
             Type = operand.Type;
             Type = operand.Type;
-
-            if (Type == OperandType.ConstantBuffer)
-            {
-                CbufSlot   = operand.GetCbufSlot();
-                CbufOffset = operand.GetCbufOffset();
-            }
-            else
-            {
-                Value = operand.Value;
-            }
+            Value = operand.Value;
         }
         }
 
 
         public AstOperand(OperandType type, int value = 0)  : this()
         public AstOperand(OperandType type, int value = 0)  : this()

+ 20 - 0
src/Ryujinx.Graphics.Shader/StructuredIr/BufferDefinition.cs

@@ -0,0 +1,20 @@
+namespace Ryujinx.Graphics.Shader.StructuredIr
+{
+    readonly struct BufferDefinition
+    {
+        public BufferLayout Layout { get; }
+        public int Set { get; }
+        public int Binding { get; }
+        public string Name { get; }
+        public StructureType Type { get; }
+
+        public BufferDefinition(BufferLayout layout, int set, int binding, string name, StructureType type)
+        {
+            Layout = layout;
+            Set = set;
+            Binding = binding;
+            Name = name;
+            Type = type;
+        }
+    }
+}

+ 8 - 0
src/Ryujinx.Graphics.Shader/StructuredIr/BufferLayout.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Graphics.Shader.StructuredIr
+{
+    enum BufferLayout
+    {
+        Std140,
+        Std430
+    }
+}

+ 0 - 1
src/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs

@@ -90,7 +90,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             Add(Instruction.ImageAtomic,              AggregateType.S32);
             Add(Instruction.ImageAtomic,              AggregateType.S32);
             Add(Instruction.IsNan,                    AggregateType.Bool,   AggregateType.Scalar);
             Add(Instruction.IsNan,                    AggregateType.Bool,   AggregateType.Scalar);
             Add(Instruction.Load,                     AggregateType.FP32);
             Add(Instruction.Load,                     AggregateType.FP32);
-            Add(Instruction.LoadConstant,             AggregateType.FP32,   AggregateType.S32,     AggregateType.S32);
             Add(Instruction.LoadGlobal,               AggregateType.U32,    AggregateType.S32,     AggregateType.S32);
             Add(Instruction.LoadGlobal,               AggregateType.U32,    AggregateType.S32,     AggregateType.S32);
             Add(Instruction.LoadLocal,                AggregateType.U32,    AggregateType.S32);
             Add(Instruction.LoadLocal,                AggregateType.U32,    AggregateType.S32);
             Add(Instruction.LoadShared,               AggregateType.U32,    AggregateType.S32);
             Add(Instruction.LoadShared,               AggregateType.U32,    AggregateType.S32);

+ 0 - 1
src/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs

@@ -24,7 +24,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             {
             {
                 OperandType.Argument => AggregateType.S32,
                 OperandType.Argument => AggregateType.S32,
                 OperandType.Constant => AggregateType.S32,
                 OperandType.Constant => AggregateType.S32,
-                OperandType.ConstantBuffer => AggregateType.FP32,
                 OperandType.Undefined => AggregateType.S32,
                 OperandType.Undefined => AggregateType.S32,
                 _ => throw new ArgumentException($"Invalid operand type \"{type}\".")
                 _ => throw new ArgumentException($"Invalid operand type \"{type}\".")
             };
             };

+ 21 - 0
src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs

@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.StructuredIr
+{
+    class ShaderProperties
+    {
+        private readonly Dictionary<int, BufferDefinition> _constantBuffers;
+
+        public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
+
+        public ShaderProperties()
+        {
+            _constantBuffers = new Dictionary<int, BufferDefinition>();
+        }
+
+        public void AddConstantBuffer(int binding, BufferDefinition definition)
+        {
+            _constantBuffers[binding] = definition;
+        }
+    }
+}

+ 28 - 0
src/Ryujinx.Graphics.Shader/StructuredIr/StructureType.cs

@@ -0,0 +1,28 @@
+using Ryujinx.Graphics.Shader.Translation;
+
+namespace Ryujinx.Graphics.Shader.StructuredIr
+{
+    struct StructureField
+    {
+        public AggregateType Type { get; }
+        public string Name { get; }
+        public int ArrayLength { get; }
+
+        public StructureField(AggregateType type, string name, int arrayLength = 1)
+        {
+            Type = type;
+            Name = name;
+            ArrayLength = arrayLength;
+        }
+    }
+
+    class StructureType
+    {
+        public StructureField[] Fields { get; }
+
+        public StructureType(StructureField[] fields)
+        {
+            Fields = fields;
+        }
+    }
+}

+ 23 - 16
src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs

@@ -73,27 +73,34 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             Instruction inst = operation.Inst;
             Instruction inst = operation.Inst;
             StorageKind storageKind = operation.StorageKind;
             StorageKind storageKind = operation.StorageKind;
 
 
-            if ((inst == Instruction.Load || inst == Instruction.Store) && storageKind.IsInputOrOutput())
+            if (inst == Instruction.Load || inst == Instruction.Store)
             {
             {
-                IoVariable ioVariable = (IoVariable)operation.GetSource(0).Value;
-                bool isOutput = storageKind.IsOutput();
-                bool perPatch = storageKind.IsPerPatch();
-                int location = 0;
-                int component = 0;
-
-                if (context.Config.HasPerLocationInputOrOutput(ioVariable, isOutput))
+                if (storageKind.IsInputOrOutput())
                 {
                 {
-                    location = operation.GetSource(1).Value;
+                    IoVariable ioVariable = (IoVariable)operation.GetSource(0).Value;
+                    bool isOutput = storageKind.IsOutput();
+                    bool perPatch = storageKind.IsPerPatch();
+                    int location = 0;
+                    int component = 0;
 
 
-                    if (operation.SourcesCount > 2 &&
-                        operation.GetSource(2).Type == OperandType.Constant &&
-                        context.Config.HasPerLocationInputOrOutputComponent(ioVariable, location, operation.GetSource(2).Value, isOutput))
+                    if (context.Config.HasPerLocationInputOrOutput(ioVariable, isOutput))
                     {
                     {
-                        component = operation.GetSource(2).Value;
+                        location = operation.GetSource(1).Value;
+
+                        if (operation.SourcesCount > 2 &&
+                            operation.GetSource(2).Type == OperandType.Constant &&
+                            context.Config.HasPerLocationInputOrOutputComponent(ioVariable, location, operation.GetSource(2).Value, isOutput))
+                        {
+                            component = operation.GetSource(2).Value;
+                        }
                     }
                     }
-                }
 
 
-                context.Info.IoDefinitions.Add(new IoDefinition(storageKind, ioVariable, location, component));
+                    context.Info.IoDefinitions.Add(new IoDefinition(storageKind, ioVariable, location, component));
+                }
+                else if (storageKind == StorageKind.ConstantBuffer && operation.GetSource(0).Type == OperandType.Constant)
+                {
+                    context.Config.ResourceManager.SetUsedConstantBufferBinding(operation.GetSource(0).Value);
+                }
             }
             }
 
 
             bool vectorDest = IsVectorDestInst(inst);
             bool vectorDest = IsVectorDestInst(inst);
@@ -105,7 +112,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
 
             for (int index = 0; index < operation.SourcesCount; index++)
             for (int index = 0; index < operation.SourcesCount; index++)
             {
             {
-                sources[index] = context.GetOperand(operation.GetSource(index));
+                sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index));
             }
             }
 
 
             for (int index = 0; index < outDestsCount; index++)
             for (int index = 0; index < outDestsCount; index++)

+ 27 - 5
src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs

@@ -298,6 +298,33 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             return newTemp;
             return newTemp;
         }
         }
 
 
+        public IAstNode GetOperandOrCbLoad(Operand operand)
+        {
+            if (operand.Type == OperandType.ConstantBuffer)
+            {
+                int cbufSlot = operand.GetCbufSlot();
+                int cbufOffset = operand.GetCbufOffset();
+
+                int binding = Config.ResourceManager.GetConstantBufferBinding(cbufSlot);
+                int vecIndex = cbufOffset >> 2;
+                int elemIndex = cbufOffset & 3;
+
+                Config.ResourceManager.SetUsedConstantBufferBinding(binding);
+
+                IAstNode[] sources = new IAstNode[]
+                {
+                    new AstOperand(OperandType.Constant, binding),
+                    new AstOperand(OperandType.Constant, 0),
+                    new AstOperand(OperandType.Constant, vecIndex),
+                    new AstOperand(OperandType.Constant, elemIndex)
+                };
+
+                return new AstOperation(Instruction.Load, StorageKind.ConstantBuffer, sources, sources.Length);
+            }
+
+            return GetOperand(operand);
+        }
+
         public AstOperand GetOperand(Operand operand)
         public AstOperand GetOperand(Operand operand)
         {
         {
             if (operand == null)
             if (operand == null)
@@ -307,11 +334,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
 
             if (operand.Type != OperandType.LocalVariable)
             if (operand.Type != OperandType.LocalVariable)
             {
             {
-                if (operand.Type == OperandType.ConstantBuffer)
-                {
-                    Config.SetUsedConstantBuffer(operand.GetCbufSlot());
-                }
-
                 return new AstOperand(operand);
                 return new AstOperand(operand);
             }
             }
 
 

+ 26 - 0
src/Ryujinx.Graphics.Shader/SupportBuffer.cs

@@ -1,4 +1,6 @@
 using Ryujinx.Common.Memory;
 using Ryujinx.Common.Memory;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using Ryujinx.Graphics.Shader.Translation;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 
 
 namespace Ryujinx.Graphics.Shader
 namespace Ryujinx.Graphics.Shader
@@ -11,8 +13,20 @@ namespace Ryujinx.Graphics.Shader
         public T W;
         public T W;
     }
     }
 
 
+    enum SupportBufferField
+    {
+        // Must match the order of the fields on the struct.
+        FragmentAlphaTest,
+        FragmentIsBgra,
+        ViewportInverse,
+        FragmentRenderScaleCount,
+        RenderScale
+    }
+
     public struct SupportBuffer
     public struct SupportBuffer
     {
     {
+        internal const int Binding = 0;
+
         public static int FieldSize;
         public static int FieldSize;
         public static int RequiredSize;
         public static int RequiredSize;
 
 
@@ -47,6 +61,18 @@ namespace Ryujinx.Graphics.Shader
             ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
             ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
         }
         }
 
 
+        internal static StructureType GetStructureType()
+        {
+            return new StructureType(new[]
+            {
+                new StructureField(AggregateType.U32, "s_alpha_test"),
+                new StructureField(AggregateType.Array | AggregateType.U32, "s_is_bgra", FragmentIsBgraCount),
+                new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_inverse"),
+                new StructureField(AggregateType.S32, "s_frag_scale_count"),
+                new StructureField(AggregateType.Array | AggregateType.FP32, "s_render_scale", RenderScaleMaxCount)
+            });
+        }
+
         public Vector4<int> FragmentAlphaTest;
         public Vector4<int> FragmentAlphaTest;
         public Array8<Vector4<int>> FragmentIsBgra;
         public Array8<Vector4<int>> FragmentIsBgra;
         public Vector4<float> ViewportInverse;
         public Vector4<float> ViewportInverse;

+ 31 - 0
src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs

@@ -22,4 +22,35 @@
 
 
         Array  = 1 << 10
         Array  = 1 << 10
     }
     }
+
+    static class AggregateTypeExtensions
+    {
+        public static int GetSizeInBytes(this AggregateType type)
+        {
+            int elementSize = (type & AggregateType.ElementTypeMask) switch
+            {
+                AggregateType.Bool or
+                AggregateType.FP32 or
+                AggregateType.S32 or
+                AggregateType.U32 => 4,
+                AggregateType.FP64 => 8,
+                _ => 0
+            };
+
+            switch (type & AggregateType.ElementCountMask)
+            {
+                case AggregateType.Vector2:
+                    elementSize *= 2;
+                    break;
+                case AggregateType.Vector3:
+                    elementSize *= 3;
+                    break;
+                case AggregateType.Vector4:
+                    elementSize *= 4;
+                    break;
+            }
+
+            return elementSize;
+        }
+    }
 }
 }

+ 3 - 3
src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs

@@ -234,8 +234,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             {
             {
                 Operand x = this.Load(StorageKind.Output, IoVariable.Position, null, Const(0));
                 Operand x = this.Load(StorageKind.Output, IoVariable.Position, null, Const(0));
                 Operand y = this.Load(StorageKind.Output, IoVariable.Position, null, Const(1));
                 Operand y = this.Load(StorageKind.Output, IoVariable.Position, null, Const(1));
-                Operand xScale = this.Load(StorageKind.Input, IoVariable.SupportBlockViewInverse, null, Const(0));
-                Operand yScale = this.Load(StorageKind.Input, IoVariable.SupportBlockViewInverse, null, Const(1));
+                Operand xScale = this.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.ViewportInverse), Const(0));
+                Operand yScale = this.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.ViewportInverse), Const(1));
                 Operand negativeOne = ConstF(-1.0f);
                 Operand negativeOne = ConstF(-1.0f);
 
 
                 this.Store(StorageKind.Output, IoVariable.Position, null, Const(0), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
                 this.Store(StorageKind.Output, IoVariable.Position, null, Const(0), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
@@ -420,7 +420,7 @@ namespace Ryujinx.Graphics.Shader.Translation
                         // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
                         // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
                         if (!supportsBgra && (component == 0 || component == 2))
                         if (!supportsBgra && (component == 0 || component == 2))
                         {
                         {
-                            Operand isBgra = this.Load(StorageKind.Input, IoVariable.FragmentOutputIsBgra, null, Const(rtIndex));
+                            Operand isBgra = this.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.FragmentIsBgra), Const(rtIndex));
 
 
                             Operand lblIsBgra = Label();
                             Operand lblIsBgra = Label();
                             Operand lblEnd = Label();
                             Operand lblEnd = Label();

+ 26 - 20
src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs

@@ -549,11 +549,31 @@ namespace Ryujinx.Graphics.Shader.Translation
             return context.Add(fpType | Instruction.IsNan, Local(), a);
             return context.Add(fpType | Instruction.IsNan, Local(), a);
         }
         }
 
 
+        public static Operand Load(this EmitterContext context, StorageKind storageKind, int binding)
+        {
+            return context.Add(Instruction.Load, storageKind, Local(), Const(binding));
+        }
+
+        public static Operand Load(this EmitterContext context, StorageKind storageKind, int binding, Operand e0)
+        {
+            return context.Add(Instruction.Load, storageKind, Local(), Const(binding), e0);
+        }
+
+        public static Operand Load(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1)
+        {
+            return context.Add(Instruction.Load, storageKind, Local(), Const(binding), e0, e1);
+        }
+
+        public static Operand Load(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1, Operand e2)
+        {
+            return context.Add(Instruction.Load, storageKind, Local(), Const(binding), e0, e1, e2);
+        }
+
         public static Operand Load(this EmitterContext context, StorageKind storageKind, IoVariable ioVariable, Operand primVertex = null)
         public static Operand Load(this EmitterContext context, StorageKind storageKind, IoVariable ioVariable, Operand primVertex = null)
         {
         {
             return primVertex != null
             return primVertex != null
-                ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex)
-                : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable));
+                ? context.Load(storageKind, (int)ioVariable, primVertex)
+                : context.Load(storageKind, (int)ioVariable);
         }
         }
 
 
         public static Operand Load(
         public static Operand Load(
@@ -564,8 +584,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             Operand elemIndex)
             Operand elemIndex)
         {
         {
             return primVertex != null
             return primVertex != null
-                ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex, elemIndex)
-                : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), elemIndex);
+                ? context.Load(storageKind, (int)ioVariable, primVertex, elemIndex)
+                : context.Load(storageKind, (int)ioVariable, elemIndex);
         }
         }
 
 
         public static Operand Load(
         public static Operand Load(
@@ -577,22 +597,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             Operand elemIndex)
             Operand elemIndex)
         {
         {
             return primVertex != null
             return primVertex != null
-                ? context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), primVertex, arrayIndex, elemIndex)
-                : context.Add(Instruction.Load, storageKind, Local(), Const((int)ioVariable), arrayIndex, elemIndex);
-        }
-
-        public static Operand LoadConstant(this EmitterContext context, Operand a, Operand b)
-        {
-            if (a.Type == OperandType.Constant)
-            {
-                context.Config.SetUsedConstantBuffer(a.Value);
-            }
-            else
-            {
-                context.Config.SetUsedFeature(FeatureFlags.CbIndexing);
-            }
-
-            return context.Add(Instruction.LoadConstant, Local(), a, b);
+                ? context.Load(storageKind, (int)ioVariable, primVertex, arrayIndex, elemIndex)
+                : context.Load(storageKind, (int)ioVariable, arrayIndex, elemIndex);
         }
         }
 
 
         public static Operand LoadGlobal(this EmitterContext context, Operand a, Operand b)
         public static Operand LoadGlobal(this EmitterContext context, Operand a, Operand b)

+ 0 - 1
src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs

@@ -19,7 +19,6 @@ namespace Ryujinx.Graphics.Shader.Translation
         InstanceId = 1 << 3,
         InstanceId = 1 << 3,
         DrawParameters = 1 << 4,
         DrawParameters = 1 << 4,
         RtLayer = 1 << 5,
         RtLayer = 1 << 5,
-        CbIndexing = 1 << 6,
         IaIndexing = 1 << 7,
         IaIndexing = 1 << 7,
         OaIndexing = 1 << 8,
         OaIndexing = 1 << 8,
         FixedFuncAttr = 1 << 9
         FixedFuncAttr = 1 << 9

+ 28 - 4
src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs

@@ -32,25 +32,49 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     continue;
                     continue;
                 }
                 }
 
 
-                if (handleAsgOp.Inst != Instruction.LoadConstant)
+                if (handleAsgOp.Inst != Instruction.Load ||
+                    handleAsgOp.StorageKind != StorageKind.ConstantBuffer ||
+                    handleAsgOp.SourcesCount != 4)
                 {
                 {
                     continue;
                     continue;
                 }
                 }
 
 
                 Operand ldcSrc0 = handleAsgOp.GetSource(0);
                 Operand ldcSrc0 = handleAsgOp.GetSource(0);
+
+                if (ldcSrc0.Type != OperandType.Constant ||
+                    !config.ResourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) ||
+                    src0CbufSlot != 2)
+                {
+                    continue;
+                }
+
                 Operand ldcSrc1 = handleAsgOp.GetSource(1);
                 Operand ldcSrc1 = handleAsgOp.GetSource(1);
 
 
-                if (ldcSrc0.Type != OperandType.Constant || ldcSrc0.Value != 2)
+                // We expect field index 0 to be accessed.
+                if (ldcSrc1.Type != OperandType.Constant || ldcSrc1.Value != 0)
+                {
+                    continue;
+                }
+
+                Operand ldcSrc2 = handleAsgOp.GetSource(2);
+
+                // FIXME: This is missing some checks, for example, a check to ensure that the shift value is 2.
+                // Might be not worth fixing since if that doesn't kick in, the result will be no texture
+                // to access anyway which is also wrong.
+                // Plus this whole transform is fundamentally flawed as-is since we have no way to know the array size.
+                // Eventually, this should be entirely removed in favor of a implementation that supports true bindless
+                // texture access.
+                if (!(ldcSrc2.AsgOp is Operation shrOp) || shrOp.Inst != Instruction.ShiftRightU32)
                 {
                 {
                     continue;
                     continue;
                 }
                 }
 
 
-                if (!(ldcSrc1.AsgOp is Operation shrOp) || shrOp.Inst != Instruction.ShiftRightU32)
+                if (!(shrOp.GetSource(0).AsgOp is Operation shrOp2) || shrOp2.Inst != Instruction.ShiftRightU32)
                 {
                 {
                     continue;
                     continue;
                 }
                 }
 
 
-                if (!(shrOp.GetSource(0).AsgOp is Operation addOp) || addOp.Inst != Instruction.Add)
+                if (!(shrOp2.GetSource(0).AsgOp is Operation addOp) || addOp.Inst != Instruction.Add)
                 {
                 {
                     continue;
                     continue;
                 }
                 }

+ 16 - 3
src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 {
 {
     static class ConstantFolding
     static class ConstantFolding
     {
     {
-        public static void RunPass(Operation operation)
+        public static void RunPass(ShaderConfig config, Operation operation)
         {
         {
             if (!AreAllSourcesConstant(operation))
             if (!AreAllSourcesConstant(operation))
             {
             {
@@ -153,8 +153,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     EvaluateFPUnary(operation, (x) => float.IsNaN(x));
                     EvaluateFPUnary(operation, (x) => float.IsNaN(x));
                     break;
                     break;
 
 
-                case Instruction.LoadConstant:
-                    operation.TurnIntoCopy(Cbuf(operation.GetSource(0).Value, operation.GetSource(1).Value));
+                case Instruction.Load:
+                    if (operation.StorageKind == StorageKind.ConstantBuffer && operation.SourcesCount == 4)
+                    {
+                        int binding = operation.GetSource(0).Value;
+                        int fieldIndex = operation.GetSource(1).Value;
+
+                        if (config.ResourceManager.TryGetConstantBufferSlot(binding, out int cbufSlot) && fieldIndex == 0)
+                        {
+                            int vecIndex = operation.GetSource(2).Value;
+                            int elemIndex = operation.GetSource(3).Value;
+                            int cbufOffset = vecIndex * 4 + elemIndex;
+
+                            operation.TurnIntoCopy(Cbuf(cbufSlot, cbufOffset));
+                        }
+                    }
                     break;
                     break;
 
 
                 case Instruction.Maximum:
                 case Instruction.Maximum:

+ 12 - 10
src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs

@@ -347,21 +347,23 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                 return wordOffset;
                 return wordOffset;
             }
             }
 
 
-            Operand[] sources = new Operand[operation.SourcesCount];
+            Operand cbufOffset = GetCbufOffset();
+            Operand vecIndex = Local();
+            Operand elemIndex = Local();
 
 
-            int cbSlot = UbeFirstCbuf + storageIndex;
+            node.List.AddBefore(node, new Operation(Instruction.ShiftRightU32, 0, vecIndex, cbufOffset, Const(2)));
+            node.List.AddBefore(node, new Operation(Instruction.BitwiseAnd, 0, elemIndex, cbufOffset, Const(3)));
 
 
-            sources[0] = Const(cbSlot);
-            sources[1] = GetCbufOffset();
+            Operand[] sources = new Operand[4];
 
 
-            config.SetUsedConstantBuffer(cbSlot);
+            int cbSlot = UbeFirstCbuf + storageIndex;
 
 
-            for (int index = 2; index < operation.SourcesCount; index++)
-            {
-                sources[index] = operation.GetSource(index);
-            }
+            sources[0] = Const(config.ResourceManager.GetConstantBufferBinding(cbSlot));
+            sources[1] = Const(0);
+            sources[2] = vecIndex;
+            sources[3] = elemIndex;
 
 
-            Operation ldcOp = new Operation(Instruction.LoadConstant, operation.Dest, sources);
+            Operation ldcOp = new Operation(Instruction.Load, StorageKind.ConstantBuffer, operation.Dest, sources);
 
 
             for (int index = 0; index < operation.SourcesCount; index++)
             for (int index = 0; index < operation.SourcesCount; index++)
             {
             {

+ 4 - 4
src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs

@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
     {
     {
         public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
         public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
         {
         {
-            RunOptimizationPasses(blocks);
+            RunOptimizationPasses(blocks, config);
 
 
             int sbUseMask = 0;
             int sbUseMask = 0;
             int ubeUseMask = 0;
             int ubeUseMask = 0;
@@ -31,10 +31,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
             config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
             config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
 
 
             // Run optimizations one last time to remove any code that is now optimizable after above passes.
             // Run optimizations one last time to remove any code that is now optimizable after above passes.
-            RunOptimizationPasses(blocks);
+            RunOptimizationPasses(blocks, config);
         }
         }
 
 
-        private static void RunOptimizationPasses(BasicBlock[] blocks)
+        private static void RunOptimizationPasses(BasicBlock[] blocks, ShaderConfig config)
         {
         {
             bool modified;
             bool modified;
 
 
@@ -73,7 +73,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             continue;
                             continue;
                         }
                         }
 
 
-                        ConstantFolding.RunPass(operation);
+                        ConstantFolding.RunPass(config, operation);
                         Simplification.RunPass(operation);
                         Simplification.RunPass(operation);
 
 
                         if (DestIsLocalVar(operation))
                         if (DestIsLocalVar(operation))

+ 126 - 0
src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs

@@ -0,0 +1,126 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Ryujinx.Graphics.Shader.Translation
+{
+    class ResourceManager
+    {
+        private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
+
+        private readonly IGpuAccessor _gpuAccessor;
+        private readonly ShaderProperties _properties;
+        private readonly string _stagePrefix;
+
+        private readonly int[] _cbSlotToBindingMap;
+
+        private readonly HashSet<int> _usedConstantBufferBindings;
+
+        public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties)
+        {
+            _gpuAccessor = gpuAccessor;
+            _properties = properties;
+            _stagePrefix = GetShaderStagePrefix(stage);
+
+            _cbSlotToBindingMap = new int[18];
+            _cbSlotToBindingMap.AsSpan().Fill(-1);
+
+            _usedConstantBufferBindings = new HashSet<int>();
+
+            properties.AddConstantBuffer(0, new BufferDefinition(BufferLayout.Std140, 0, 0, "support_buffer", SupportBuffer.GetStructureType()));
+        }
+
+        public int GetConstantBufferBinding(int slot)
+        {
+            int binding = _cbSlotToBindingMap[slot];
+            if (binding < 0)
+            {
+                binding = _gpuAccessor.QueryBindingConstantBuffer(slot);
+                _cbSlotToBindingMap[slot] = binding;
+                string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
+                AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
+            }
+
+            return binding;
+        }
+
+        public bool TryGetConstantBufferSlot(int binding, out int slot)
+        {
+            for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
+            {
+                if (_cbSlotToBindingMap[slot] == binding)
+                {
+                    return true;
+                }
+            }
+
+            slot = 0;
+            return false;
+        }
+
+        public void SetUsedConstantBufferBinding(int binding)
+        {
+            _usedConstantBufferBindings.Add(binding);
+        }
+
+        public BufferDescriptor[] GetConstantBufferDescriptors()
+        {
+            var descriptors = new BufferDescriptor[_usedConstantBufferBindings.Count];
+
+            int descriptorIndex = 0;
+
+            for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
+            {
+                int binding = _cbSlotToBindingMap[slot];
+
+                if (binding >= 0 && _usedConstantBufferBindings.Contains(binding))
+                {
+                    descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot);
+                }
+            }
+
+            if (descriptors.Length != descriptorIndex)
+            {
+                Array.Resize(ref descriptors, descriptorIndex);
+            }
+
+            return descriptors;
+        }
+
+        private void AddNewConstantBuffer(int binding, string name)
+        {
+            StructureType type = new StructureType(new[]
+            {
+                new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16)
+            });
+
+            _properties.AddConstantBuffer(binding, new BufferDefinition(BufferLayout.Std140, 0, binding, name, type));
+        }
+
+        public void InheritFrom(ResourceManager other)
+        {
+            for (int i = 0; i < other._cbSlotToBindingMap.Length; i++)
+            {
+                int binding = other._cbSlotToBindingMap[i];
+
+                if (binding >= 0)
+                {
+                    _cbSlotToBindingMap[i] = binding;
+                }
+            }
+        }
+
+        public static string GetShaderStagePrefix(ShaderStage stage)
+        {
+            uint index = (uint)stage;
+
+            if (index >= _stagePrefixes.Length)
+            {
+                return "invalid";
+            }
+
+            return _stagePrefixes[index];
+        }
+    }
+}

+ 102 - 13
src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs

@@ -1,7 +1,6 @@
-using Ryujinx.Graphics.Shader.Decoders;
 using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Numerics;
 using System.Numerics;
 
 
@@ -16,6 +15,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         {
         {
             bool isVertexShader = config.Stage == ShaderStage.Vertex;
             bool isVertexShader = config.Stage == ShaderStage.Vertex;
             bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters();
             bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters();
+            bool hasVectorIndexingBug = config.GpuAccessor.QueryHostHasVectorIndexingBug();
             bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat();
             bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat();
 
 
             for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
             for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
@@ -45,6 +45,11 @@ namespace Ryujinx.Graphics.Shader.Translation
                         }
                         }
                     }
                     }
 
 
+                    if (hasVectorIndexingBug)
+                    {
+                        InsertVectorComponentSelect(node, config);
+                    }
+
                     LinkedListNode<INode> nextNode = node.Next;
                     LinkedListNode<INode> nextNode = node.Next;
 
 
                     if (operation is TextureOperation texOp)
                     if (operation is TextureOperation texOp)
@@ -71,6 +76,84 @@ namespace Ryujinx.Graphics.Shader.Translation
             }
             }
         }
         }
 
 
+        private static void InsertVectorComponentSelect(LinkedListNode<INode> node, ShaderConfig config)
+        {
+            Operation operation = (Operation)node.Value;
+
+            if (operation.Inst != Instruction.Load ||
+                operation.StorageKind != StorageKind.ConstantBuffer ||
+                operation.SourcesCount < 3)
+            {
+                return;
+            }
+
+            Operand bindingIndex = operation.GetSource(0);
+            Operand fieldIndex = operation.GetSource(1);
+            Operand elemIndex = operation.GetSource(operation.SourcesCount - 1);
+
+            if (bindingIndex.Type != OperandType.Constant ||
+                fieldIndex.Type != OperandType.Constant ||
+                elemIndex.Type == OperandType.Constant)
+            {
+                return;
+            }
+
+            BufferDefinition buffer = config.Properties.ConstantBuffers[bindingIndex.Value];
+            StructureField field = buffer.Type.Fields[fieldIndex.Value];
+
+            int elemCount = (field.Type & AggregateType.ElementCountMask) switch
+            {
+                AggregateType.Vector2 => 2,
+                AggregateType.Vector3 => 3,
+                AggregateType.Vector4 => 4,
+                _ => 1
+            };
+
+            if (elemCount == 1)
+            {
+                return;
+            }
+
+            Operand result = null;
+
+            for (int i = 0; i < elemCount; i++)
+            {
+                Operand value = Local();
+                Operand[] inputs = new Operand[operation.SourcesCount];
+
+                for (int srcIndex = 0; srcIndex < inputs.Length - 1; srcIndex++)
+                {
+                    inputs[srcIndex] = operation.GetSource(srcIndex);
+                }
+
+                inputs[inputs.Length - 1] = Const(i);
+
+                Operation loadOp = new Operation(Instruction.Load, StorageKind.ConstantBuffer, value, inputs);
+
+                node.List.AddBefore(node, loadOp);
+
+                if (i == 0)
+                {
+                    result = value;
+                }
+                else
+                {
+                    Operand isCurrentIndex = Local();
+                    Operand selection = Local();
+
+                    Operation compareOp = new Operation(Instruction.CompareEqual, isCurrentIndex, new Operand[] { elemIndex, Const(i) });
+                    Operation selectOp = new Operation(Instruction.ConditionalSelect, selection, new Operand[] { isCurrentIndex, value, result });
+
+                    node.List.AddBefore(node, compareOp);
+                    node.List.AddBefore(node, selectOp);
+
+                    result = selection;
+                }
+            }
+
+            operation.TurnIntoCopy(result);
+        }
+
         private static LinkedListNode<INode> RewriteGlobalAccess(LinkedListNode<INode> node, ShaderConfig config)
         private static LinkedListNode<INode> RewriteGlobalAccess(LinkedListNode<INode> node, ShaderConfig config)
         {
         {
             Operation operation = (Operation)node.Value;
             Operation operation = (Operation)node.Value;
@@ -90,6 +173,15 @@ namespace Ryujinx.Graphics.Shader.Translation
                 return local;
                 return local;
             }
             }
 
 
+            Operand PrependStorageOperation(Instruction inst, StorageKind storageKind, params Operand[] sources)
+            {
+                Operand local = Local();
+
+                node.List.AddBefore(node, new Operation(inst, storageKind, local, sources));
+
+                return local;
+            }
+
             Operand PrependExistingOperation(Operation operation)
             Operand PrependExistingOperation(Operation operation)
             {
             {
                 Operand local = Local();
                 Operand local = Local();
@@ -204,8 +296,6 @@ namespace Ryujinx.Graphics.Shader.Translation
 
 
                     cbeUseMask &= ~(1 << slot);
                     cbeUseMask &= ~(1 << slot);
 
 
-                    config.SetUsedConstantBuffer(cbSlot);
-
                     Operand previousResult = PrependExistingOperation(storageOp);
                     Operand previousResult = PrependExistingOperation(storageOp);
 
 
                     int cbOffset = GetConstantUbeOffset(slot);
                     int cbOffset = GetConstantUbeOffset(slot);
@@ -216,18 +306,17 @@ namespace Ryujinx.Graphics.Shader.Translation
                     Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst);
                     Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst);
 
 
                     Operand cbIndex = PrependOperation(Instruction.ShiftRightU32, byteOffsetConst, Const(2));
                     Operand cbIndex = PrependOperation(Instruction.ShiftRightU32, byteOffsetConst, Const(2));
+                    Operand vecIndex = PrependOperation(Instruction.ShiftRightU32, cbIndex, Const(2));
+                    Operand elemIndex = PrependOperation(Instruction.BitwiseAnd, cbIndex, Const(3));
 
 
-                    Operand[] sourcesCb = new Operand[operation.SourcesCount];
+                    Operand[] sourcesCb = new Operand[4];
 
 
-                    sourcesCb[0] = Const(cbSlot);
-                    sourcesCb[1] = cbIndex;
-
-                    for (int index = 2; index < operation.SourcesCount; index++)
-                    {
-                        sourcesCb[index] = operation.GetSource(index);
-                    }
+                    sourcesCb[0] = Const(config.ResourceManager.GetConstantBufferBinding(cbSlot));
+                    sourcesCb[1] = Const(0);
+                    sourcesCb[2] = vecIndex;
+                    sourcesCb[3] = elemIndex;
 
 
-                    Operand ldcResult = PrependOperation(Instruction.LoadConstant, sourcesCb);
+                    Operand ldcResult = PrependStorageOperation(Instruction.Load, StorageKind.ConstantBuffer, sourcesCb);
 
 
                     storageOp = new Operation(Instruction.ConditionalSelect, operation.Dest, inRange, ldcResult, previousResult);
                     storageOp = new Operation(Instruction.ConditionalSelect, operation.Dest, inRange, ldcResult, previousResult);
                 }
                 }

+ 14 - 79
src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs

@@ -39,6 +39,10 @@ namespace Ryujinx.Graphics.Shader.Translation
 
 
         public TranslationOptions Options { get; }
         public TranslationOptions Options { get; }
 
 
+        public ShaderProperties Properties { get; }
+
+        public ResourceManager ResourceManager { get; }
+
         public bool TransformFeedbackEnabled { get; }
         public bool TransformFeedbackEnabled { get; }
 
 
         private TransformFeedbackOutput[] _transformFeedbackOutputs;
         private TransformFeedbackOutput[] _transformFeedbackOutputs;
@@ -109,7 +113,6 @@ namespace Ryujinx.Graphics.Shader.Translation
         public int AccessibleStorageBuffersMask { get; private set; }
         public int AccessibleStorageBuffersMask { get; private set; }
         public int AccessibleConstantBuffersMask { get; private set; }
         public int AccessibleConstantBuffersMask { get; private set; }
 
 
-        private int _usedConstantBuffers;
         private int _usedStorageBuffers;
         private int _usedStorageBuffers;
         private int _usedStorageBuffersWrite;
         private int _usedStorageBuffersWrite;
 
 
@@ -128,20 +131,17 @@ namespace Ryujinx.Graphics.Shader.Translation
         private readonly Dictionary<int, int> _sbSlots;
         private readonly Dictionary<int, int> _sbSlots;
         private readonly Dictionary<int, int> _sbSlotsReverse;
         private readonly Dictionary<int, int> _sbSlotsReverse;
 
 
-        private BufferDescriptor[] _cachedConstantBufferDescriptors;
         private BufferDescriptor[] _cachedStorageBufferDescriptors;
         private BufferDescriptor[] _cachedStorageBufferDescriptors;
         private TextureDescriptor[] _cachedTextureDescriptors;
         private TextureDescriptor[] _cachedTextureDescriptors;
         private TextureDescriptor[] _cachedImageDescriptors;
         private TextureDescriptor[] _cachedImageDescriptors;
 
 
-        private int _firstConstantBufferBinding;
         private int _firstStorageBufferBinding;
         private int _firstStorageBufferBinding;
 
 
-        public int FirstConstantBufferBinding => _firstConstantBufferBinding;
         public int FirstStorageBufferBinding => _firstStorageBufferBinding;
         public int FirstStorageBufferBinding => _firstStorageBufferBinding;
 
 
-        public ShaderConfig(IGpuAccessor gpuAccessor, TranslationOptions options)
+        public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options)
         {
         {
-            Stage       = ShaderStage.Compute;
+            Stage       = stage;
             GpuAccessor = gpuAccessor;
             GpuAccessor = gpuAccessor;
             Options     = options;
             Options     = options;
 
 
@@ -158,6 +158,9 @@ namespace Ryujinx.Graphics.Shader.Translation
 
 
             _sbSlots        = new Dictionary<int, int>();
             _sbSlots        = new Dictionary<int, int>();
             _sbSlotsReverse = new Dictionary<int, int>();
             _sbSlotsReverse = new Dictionary<int, int>();
+
+            Properties = new ShaderProperties();
+            ResourceManager = new ResourceManager(stage, gpuAccessor, Properties);
         }
         }
 
 
         public ShaderConfig(
         public ShaderConfig(
@@ -165,9 +168,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             OutputTopology outputTopology,
             OutputTopology outputTopology,
             int maxOutputVertices,
             int maxOutputVertices,
             IGpuAccessor gpuAccessor,
             IGpuAccessor gpuAccessor,
-            TranslationOptions options) : this(gpuAccessor, options)
+            TranslationOptions options) : this(stage, gpuAccessor, options)
         {
         {
-            Stage                    = stage;
             ThreadsPerInputPrimitive = 1;
             ThreadsPerInputPrimitive = 1;
             OutputTopology           = outputTopology;
             OutputTopology           = outputTopology;
             MaxOutputVertices        = maxOutputVertices;
             MaxOutputVertices        = maxOutputVertices;
@@ -179,9 +181,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             }
             }
         }
         }
 
 
-        public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
+        public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(header.Stage, gpuAccessor, options)
         {
         {
-            Stage                    = header.Stage;
             GpPassthrough            = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
             GpPassthrough            = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
             ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
             ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
             OutputTopology           = header.OutputTopology;
             OutputTopology           = header.OutputTopology;
@@ -428,12 +429,13 @@ namespace Ryujinx.Graphics.Shader.Translation
 
 
         public void InheritFrom(ShaderConfig other)
         public void InheritFrom(ShaderConfig other)
         {
         {
+            ResourceManager.InheritFrom(other.ResourceManager);
+
             ClipDistancesWritten |= other.ClipDistancesWritten;
             ClipDistancesWritten |= other.ClipDistancesWritten;
             UsedFeatures |= other.UsedFeatures;
             UsedFeatures |= other.UsedFeatures;
 
 
             UsedInputAttributes |= other.UsedInputAttributes;
             UsedInputAttributes |= other.UsedInputAttributes;
             UsedOutputAttributes |= other.UsedOutputAttributes;
             UsedOutputAttributes |= other.UsedOutputAttributes;
-            _usedConstantBuffers |= other._usedConstantBuffers;
             _usedStorageBuffers |= other._usedStorageBuffers;
             _usedStorageBuffers |= other._usedStorageBuffers;
             _usedStorageBuffersWrite |= other._usedStorageBuffersWrite;
             _usedStorageBuffersWrite |= other._usedStorageBuffersWrite;
 
 
@@ -641,11 +643,6 @@ namespace Ryujinx.Graphics.Shader.Translation
             AccessibleConstantBuffersMask = ubeMask;
             AccessibleConstantBuffersMask = ubeMask;
         }
         }
 
 
-        public void SetUsedConstantBuffer(int slot)
-        {
-            _usedConstantBuffers |= 1 << slot;
-        }
-
         public void SetUsedStorageBuffer(int slot, bool write)
         public void SetUsedStorageBuffer(int slot, bool write)
         {
         {
             int mask = 1 << slot;
             int mask = 1 << slot;
@@ -762,27 +759,6 @@ namespace Ryujinx.Graphics.Shader.Translation
             return meta;
             return meta;
         }
         }
 
 
-        public BufferDescriptor[] GetConstantBufferDescriptors()
-        {
-            if (_cachedConstantBufferDescriptors != null)
-            {
-                return _cachedConstantBufferDescriptors;
-            }
-
-            int usedMask = _usedConstantBuffers;
-
-            if (UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
-            {
-                usedMask |= (int)GpuAccessor.QueryConstantBufferUse();
-            }
-
-            return _cachedConstantBufferDescriptors = GetUniformBufferDescriptors(
-                usedMask,
-                UsedFeatures.HasFlag(FeatureFlags.CbIndexing),
-                out _firstConstantBufferBinding,
-                GpuAccessor.QueryBindingConstantBuffer);
-        }
-
         public BufferDescriptor[] GetStorageBufferDescriptors()
         public BufferDescriptor[] GetStorageBufferDescriptors()
         {
         {
             if (_cachedStorageBufferDescriptors != null)
             if (_cachedStorageBufferDescriptors != null)
@@ -798,47 +774,6 @@ namespace Ryujinx.Graphics.Shader.Translation
                 GpuAccessor.QueryBindingStorageBuffer);
                 GpuAccessor.QueryBindingStorageBuffer);
         }
         }
 
 
-        private static BufferDescriptor[] GetUniformBufferDescriptors(int usedMask, bool isArray, out int firstBinding, Func<int, int> getBindingCallback)
-        {
-            firstBinding = 0;
-            int lastSlot = -1;
-            bool hasFirstBinding = false;
-            var descriptors = new BufferDescriptor[BitOperations.PopCount((uint)usedMask)];
-
-            for (int i = 0; i < descriptors.Length; i++)
-            {
-                int slot = BitOperations.TrailingZeroCount(usedMask);
-
-                if (isArray)
-                {
-                    // The next array entries also consumes bindings, even if they are unused.
-                    for (int j = lastSlot + 1; j < slot; j++)
-                    {
-                        int binding = getBindingCallback(j);
-
-                        if (!hasFirstBinding)
-                        {
-                            firstBinding = binding;
-                            hasFirstBinding = true;
-                        }
-                    }
-                }
-
-                lastSlot = slot;
-                descriptors[i] = new BufferDescriptor(getBindingCallback(slot), slot);
-
-                if (!hasFirstBinding)
-                {
-                    firstBinding = descriptors[i].Binding;
-                    hasFirstBinding = true;
-                }
-
-                usedMask &= ~(1 << slot);
-            }
-
-            return descriptors;
-        }
-
         private BufferDescriptor[] GetStorageBufferDescriptors(
         private BufferDescriptor[] GetStorageBufferDescriptors(
             int usedMask,
             int usedMask,
             int writtenMask,
             int writtenMask,
@@ -1009,7 +944,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
         public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
         {
         {
             return new ShaderProgramInfo(
             return new ShaderProgramInfo(
-                GetConstantBufferDescriptors(),
+                ResourceManager.GetConstantBufferDescriptors(),
                 GetStorageBufferDescriptors(),
                 GetStorageBufferDescriptors(),
                 GetTextureDescriptors(),
                 GetTextureDescriptors(),
                 GetImageDescriptors(),
                 GetImageDescriptors(),

+ 1 - 1
src/Ryujinx.Graphics.Shader/Translation/Translator.cs

@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 
 
             if (options.Flags.HasFlag(TranslationFlags.Compute))
             if (options.Flags.HasFlag(TranslationFlags.Compute))
             {
             {
-                config = new ShaderConfig(gpuAccessor, options);
+                config = new ShaderConfig(ShaderStage.Compute, gpuAccessor, options);
 
 
                 program = Decoder.Decode(config, address);
                 program = Decoder.Decode(config, address);
             }
             }