aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs115
1 files changed, 102 insertions, 13 deletions
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);
}