diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Shader/Translation/Rewriter.cs | 115 |
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); } |