aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation/Lowering.cs
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-11-30 23:53:09 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit6a98c643cabeea25dc42e19fe475a687a034a532 (patch)
treeccb1ecbfc5b79852be8a1f52e241015142a8a7a9 /Ryujinx.Graphics.Shader/Translation/Lowering.cs
parent396768f3b4494c7dcb0c03942eeb50ef4d47adde (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.cs121
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