diff options
| author | gdk <gab.dark.100@gmail.com> | 2019-11-30 23:53:09 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | 6a98c643cabeea25dc42e19fe475a687a034a532 (patch) | |
| tree | ccb1ecbfc5b79852be8a1f52e241015142a8a7a9 /Ryujinx.Graphics.Shader/Translation/Lowering.cs | |
| parent | 396768f3b4494c7dcb0c03942eeb50ef4d47adde (diff) | |
Add a pass to turn global memory access into storage access, and do all storage related transformations on IR
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/Lowering.cs')
| -rw-r--r-- | Ryujinx.Graphics.Shader/Translation/Lowering.cs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Lowering.cs b/Ryujinx.Graphics.Shader/Translation/Lowering.cs new file mode 100644 index 00000000..9a17dd83 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Translation/Lowering.cs @@ -0,0 +1,121 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; +using static Ryujinx.Graphics.Shader.Translation.GlobalMemory; + +namespace Ryujinx.Graphics.Shader.Translation +{ + static class Lowering + { + public static void RunPass(BasicBlock[] blocks, ShaderConfig config) + { + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + BasicBlock block = blocks[blkIndex]; + + for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next) + { + if (!(node.Value is Operation operation)) + { + continue; + } + + if (UsesGlobalMemory(operation.Inst)) + { + node = LowerGlobal(node, config); + } + } + } + } + + private static LinkedListNode<INode> LowerGlobal(LinkedListNode<INode> node, ShaderConfig config) + { + Operation operation = (Operation)node.Value; + + Operation storageOp; + + Operand PrependOperation(Instruction inst, params Operand[] sources) + { + Operand local = Local(); + + node.List.AddBefore(node, new Operation(inst, local, sources)); + + return local; + } + + Operand addrLow = operation.GetSource(0); + Operand addrHigh = operation.GetSource(1); + + Operand sbBaseAddrLow = Const(0); + Operand sbSlot = Const(0); + + for (int slot = 0; slot < StorageMaxCount; slot++) + { + int cbOffset = GetStorageCbOffset(config.Stage, slot); + + Operand baseAddrLow = Cbuf(0, cbOffset); + Operand baseAddrHigh = Cbuf(0, cbOffset + 1); + Operand size = Cbuf(0, cbOffset + 2); + + Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow); + Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow); + + Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size); + + Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow); + + Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh); + + Operand inRange = PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh); + + sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow); + sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot); + } + + Operand alignMask = Const(-config.Capabilities.StorageBufferOffsetAlignment); + + Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, Const(-64)); + Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc); + Operand wordOffset = PrependOperation(Instruction.ShiftRightU32, byteOffset, Const(2)); + + Operand[] sources = new Operand[operation.SourcesCount]; + + sources[0] = sbSlot; + sources[1] = wordOffset; + + for (int index = 2; index < operation.SourcesCount; index++) + { + sources[index] = operation.GetSource(index); + } + + if (operation.Inst.IsAtomic()) + { + Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage; + + storageOp = new Operation(inst, operation.Dest, sources); + } + else if (operation.Inst == Instruction.LoadGlobal) + { + storageOp = new Operation(Instruction.LoadStorage, operation.Dest, sources); + } + else + { + storageOp = new Operation(Instruction.StoreStorage, null, sources); + } + + for (int index = 0; index < operation.SourcesCount; index++) + { + operation.SetSource(index, null); + } + + LinkedListNode<INode> oldNode = node; + + node = node.List.AddBefore(node, storageOp); + + node.List.Remove(oldNode); + + return node; + } + } +}
\ No newline at end of file |
