aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs31
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs6
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs46
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs1
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs32
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs19
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs22
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs8
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs126
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs115
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs93
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Translator.cs2
12 files changed, 363 insertions, 138 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs b/src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
index 24993e00..b1b40f65 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
@@ -22,4 +22,35 @@
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;
+ }
+ }
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 112baccf..0c51b16f 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/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 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);
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).
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 lblEnd = Label();
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index 93748249..e41a28f1 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -549,11 +549,31 @@ namespace Ryujinx.Graphics.Shader.Translation
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)
{
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(
@@ -564,8 +584,8 @@ namespace Ryujinx.Graphics.Shader.Translation
Operand elemIndex)
{
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(
@@ -577,22 +597,8 @@ namespace Ryujinx.Graphics.Shader.Translation
Operand elemIndex)
{
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)
diff --git a/src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs b/src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
index c035f212..e55ed13d 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/FeatureFlags.cs
@@ -19,7 +19,6 @@ namespace Ryujinx.Graphics.Shader.Translation
InstanceId = 1 << 3,
DrawParameters = 1 << 4,
RtLayer = 1 << 5,
- CbIndexing = 1 << 6,
IaIndexing = 1 << 7,
OaIndexing = 1 << 8,
FixedFuncAttr = 1 << 9
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
index ca46a1f5..9a3ae1b8 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs
@@ -32,25 +32,49 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- if (handleAsgOp.Inst != Instruction.LoadConstant)
+ if (handleAsgOp.Inst != Instruction.Load ||
+ handleAsgOp.StorageKind != StorageKind.ConstantBuffer ||
+ handleAsgOp.SourcesCount != 4)
{
continue;
}
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);
- 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;
}
- if (!(ldcSrc1.AsgOp is Operation shrOp) || shrOp.Inst != Instruction.ShiftRightU32)
+ if (!(shrOp.GetSource(0).AsgOp is Operation shrOp2) || shrOp2.Inst != Instruction.ShiftRightU32)
{
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;
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
index 6729f077..4caadb73 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{
static class ConstantFolding
{
- public static void RunPass(Operation operation)
+ public static void RunPass(ShaderConfig config, Operation operation)
{
if (!AreAllSourcesConstant(operation))
{
@@ -153,8 +153,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
EvaluateFPUnary(operation, (x) => float.IsNaN(x));
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;
case Instruction.Maximum:
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
index 774d3e36..7758b4c6 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
@@ -347,21 +347,23 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
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++)
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index b41e47e4..b126e2c4 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/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)
{
- RunOptimizationPasses(blocks);
+ RunOptimizationPasses(blocks, config);
int sbUseMask = 0;
int ubeUseMask = 0;
@@ -31,10 +31,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
// 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;
@@ -73,7 +73,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- ConstantFolding.RunPass(operation);
+ ConstantFolding.RunPass(config, operation);
Simplification.RunPass(operation);
if (DestIsLocalVar(operation))
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
new file mode 100644
index 00000000..b31790d3
--- /dev/null
+++ b/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];
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
index 8167efc1..711661c9 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
+++ b/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.StructuredIr;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Linq;
using System.Numerics;
@@ -16,6 +15,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
bool isVertexShader = config.Stage == ShaderStage.Vertex;
bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters();
+ bool hasVectorIndexingBug = config.GpuAccessor.QueryHostHasVectorIndexingBug();
bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat();
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;
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)
{
Operation operation = (Operation)node.Value;
@@ -90,6 +173,15 @@ namespace Ryujinx.Graphics.Shader.Translation
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 local = Local();
@@ -204,8 +296,6 @@ namespace Ryujinx.Graphics.Shader.Translation
cbeUseMask &= ~(1 << slot);
- config.SetUsedConstantBuffer(cbSlot);
-
Operand previousResult = PrependExistingOperation(storageOp);
int cbOffset = GetConstantUbeOffset(slot);
@@ -216,18 +306,17 @@ namespace Ryujinx.Graphics.Shader.Translation
Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst);
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);
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index ae60bcc6..77560797 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -39,6 +39,10 @@ namespace Ryujinx.Graphics.Shader.Translation
public TranslationOptions Options { get; }
+ public ShaderProperties Properties { get; }
+
+ public ResourceManager ResourceManager { get; }
+
public bool TransformFeedbackEnabled { get; }
private TransformFeedbackOutput[] _transformFeedbackOutputs;
@@ -109,7 +113,6 @@ namespace Ryujinx.Graphics.Shader.Translation
public int AccessibleStorageBuffersMask { get; private set; }
public int AccessibleConstantBuffersMask { get; private set; }
- private int _usedConstantBuffers;
private int _usedStorageBuffers;
private int _usedStorageBuffersWrite;
@@ -128,20 +131,17 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly Dictionary<int, int> _sbSlots;
private readonly Dictionary<int, int> _sbSlotsReverse;
- private BufferDescriptor[] _cachedConstantBufferDescriptors;
private BufferDescriptor[] _cachedStorageBufferDescriptors;
private TextureDescriptor[] _cachedTextureDescriptors;
private TextureDescriptor[] _cachedImageDescriptors;
- private int _firstConstantBufferBinding;
private int _firstStorageBufferBinding;
- public int FirstConstantBufferBinding => _firstConstantBufferBinding;
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;
Options = options;
@@ -158,6 +158,9 @@ namespace Ryujinx.Graphics.Shader.Translation
_sbSlots = new Dictionary<int, int>();
_sbSlotsReverse = new Dictionary<int, int>();
+
+ Properties = new ShaderProperties();
+ ResourceManager = new ResourceManager(stage, gpuAccessor, Properties);
}
public ShaderConfig(
@@ -165,9 +168,8 @@ namespace Ryujinx.Graphics.Shader.Translation
OutputTopology outputTopology,
int maxOutputVertices,
IGpuAccessor gpuAccessor,
- TranslationOptions options) : this(gpuAccessor, options)
+ TranslationOptions options) : this(stage, gpuAccessor, options)
{
- Stage = stage;
ThreadsPerInputPrimitive = 1;
OutputTopology = outputTopology;
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;
ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
OutputTopology = header.OutputTopology;
@@ -428,12 +429,13 @@ namespace Ryujinx.Graphics.Shader.Translation
public void InheritFrom(ShaderConfig other)
{
+ ResourceManager.InheritFrom(other.ResourceManager);
+
ClipDistancesWritten |= other.ClipDistancesWritten;
UsedFeatures |= other.UsedFeatures;
UsedInputAttributes |= other.UsedInputAttributes;
UsedOutputAttributes |= other.UsedOutputAttributes;
- _usedConstantBuffers |= other._usedConstantBuffers;
_usedStorageBuffers |= other._usedStorageBuffers;
_usedStorageBuffersWrite |= other._usedStorageBuffersWrite;
@@ -641,11 +643,6 @@ namespace Ryujinx.Graphics.Shader.Translation
AccessibleConstantBuffersMask = ubeMask;
}
- public void SetUsedConstantBuffer(int slot)
- {
- _usedConstantBuffers |= 1 << slot;
- }
-
public void SetUsedStorageBuffer(int slot, bool write)
{
int mask = 1 << slot;
@@ -762,27 +759,6 @@ namespace Ryujinx.Graphics.Shader.Translation
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()
{
if (_cachedStorageBufferDescriptors != null)
@@ -798,47 +774,6 @@ namespace Ryujinx.Graphics.Shader.Translation
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(
int usedMask,
int writtenMask,
@@ -1009,7 +944,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
{
return new ShaderProgramInfo(
- GetConstantBufferDescriptors(),
+ ResourceManager.GetConstantBufferDescriptors(),
GetStorageBufferDescriptors(),
GetTextureDescriptors(),
GetImageDescriptors(),
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 77d3b568..87d97e52 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (options.Flags.HasFlag(TranslationFlags.Compute))
{
- config = new ShaderConfig(gpuAccessor, options);
+ config = new ShaderConfig(ShaderStage.Compute, gpuAccessor, options);
program = Decoder.Decode(config, address);
}