diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-04-17 20:57:08 -0300 |
|---|---|---|
| committer | jduncanator <1518948+jduncanator@users.noreply.github.com> | 2019-04-18 09:57:08 +1000 |
| commit | 6b23a2c125b9c48b5ebea92716004ef68698bb0f (patch) | |
| tree | 69332df6fbbd8e2bddc522ba682fcc5c7a69e101 /Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | |
| parent | b2e88b04a85b41cc60af3485d88c90429e84a218 (diff) | |
New shader translator implementation (#654)
* Start implementing a new shader translator
* Fix shift instructions and a typo
* Small refactoring on StructuredProgram, move RemovePhis method to a separate class
* Initial geometry shader support
* Implement TLD4
* Fix -- There's no negation on FMUL32I
* Add constant folding and algebraic simplification optimizations, nits
* Some leftovers from constant folding
* Avoid cast for constant assignments
* Add a branch elimination pass, and misc small fixes
* Remove redundant branches, add expression propagation and other improvements on the code
* Small leftovers -- add missing break and continue, remove unused properties, other improvements
* Add null check to handle empty block cases on block visitor
* Add HADD2 and HMUL2 half float shader instructions
* Optimize pack/unpack sequences, some fixes related to half float instructions
* Add TXQ, TLD, TLDS and TLD4S shader texture instructions, and some support for bindless textures, some refactoring on codegen
* Fix copy paste mistake that caused RZ to be ignored on the AST instruction
* Add workaround for conditional exit, and fix half float instruction with constant buffer
* Add missing 0.0 source for TLDS.LZ variants
* Simplify the switch for TLDS.LZ
* Texture instructions related fixes
* Implement the HFMA instruction, and some misc. fixes
* Enable constant folding on UnpackHalf2x16 instructions
* Refactor HFMA to use OpCode* for opcode decoding rather than on the helper methods
* Remove the old shader translator
* Remove ShaderDeclInfo and other unused things
* Add dual vertex shader support
* Add ShaderConfig, used to pass shader type and maximum cbuffer size
* Move and rename some instruction enums
* Move texture instructions into a separate file
* Move operand GetExpression and locals management to OperandManager
* Optimize opcode decoding using a simple list and binary search
* Add missing condition for do-while on goto elimination
* Misc. fixes on texture instructions
* Simplify TLDS switch
* Address PR feedback, and a nit
Diffstat (limited to 'Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs')
| -rw-r--r-- | Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | 218 |
1 files changed, 0 insertions, 218 deletions
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs deleted file mode 100644 index 4b23f8d0..00000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static class ShaderDecoder - { - private const long HeaderSize = 0x50; - - private const bool AddDbgComments = true; - - public static ShaderIrBlock[] Decode(IGalMemory memory, long start) - { - Dictionary<int, ShaderIrBlock> visited = new Dictionary<int, ShaderIrBlock>(); - Dictionary<int, ShaderIrBlock> visitedEnd = new Dictionary<int, ShaderIrBlock>(); - - Queue<ShaderIrBlock> blocks = new Queue<ShaderIrBlock>(); - - long beginning = start + HeaderSize; - - ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null) - { - if (!visited.TryGetValue(position, out ShaderIrBlock output)) - { - output = new ShaderIrBlock(position); - - blocks.Enqueue(output); - - visited.Add(position, output); - } - - if (source != null) - { - output.Sources.Add(source); - } - - return output; - } - - ShaderIrBlock entry = Enqueue(0); - - while (blocks.Count > 0) - { - ShaderIrBlock current = blocks.Dequeue(); - - FillBlock(memory, current, beginning); - - //Set child blocks. "Branch" is the block the branch instruction - //points to (when taken), "Next" is the block at the next address, - //executed when the branch is not taken. For Unconditional Branches - //or end of shader, Next is null. - if (current.Nodes.Count > 0) - { - ShaderIrNode lastNode = current.GetLastNode(); - - ShaderIrOp innerOp = GetInnermostOp(lastNode); - - if (innerOp?.Inst == ShaderIrInst.Bra) - { - int target = ((ShaderIrOperImm)innerOp.OperandA).Value; - - current.Branch = Enqueue(target, current); - } - - foreach (ShaderIrNode node in current.Nodes) - { - innerOp = GetInnermostOp(node); - - if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy) - { - int target = ((ShaderIrOperImm)currOp.OperandA).Value; - - Enqueue(target, current); - } - } - - if (NodeHasNext(lastNode)) - { - current.Next = Enqueue(current.EndPosition); - } - } - - //If we have on the graph two blocks with the same end position, - //then we need to split the bigger block and have two small blocks, - //the end position of the bigger "Current" block should then be == to - //the position of the "Smaller" block. - while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller)) - { - if (current.Position > smaller.Position) - { - ShaderIrBlock temp = smaller; - - smaller = current; - current = temp; - } - - current.EndPosition = smaller.Position; - current.Next = smaller; - current.Branch = null; - - current.Nodes.RemoveRange( - current.Nodes.Count - smaller.Nodes.Count, - smaller.Nodes.Count); - - visitedEnd[smaller.EndPosition] = smaller; - } - - visitedEnd.Add(current.EndPosition, current); - } - - //Make and sort Graph blocks array by position. - ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count]; - - while (visited.Count > 0) - { - uint firstPos = uint.MaxValue; - - foreach (ShaderIrBlock block in visited.Values) - { - if (firstPos > (uint)block.Position) - firstPos = (uint)block.Position; - } - - ShaderIrBlock current = visited[(int)firstPos]; - - do - { - graph[graph.Length - visited.Count] = current; - - visited.Remove(current.Position); - - current = current.Next; - } - while (current != null); - } - - return graph; - } - - private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning) - { - int position = block.Position; - - do - { - //Ignore scheduling instructions, which are written every 32 bytes. - if ((position & 0x1f) == 0) - { - position += 8; - - continue; - } - - uint word0 = (uint)memory.ReadInt32(position + beginning + 0); - uint word1 = (uint)memory.ReadInt32(position + beginning + 4); - - position += 8; - - long opCode = word0 | (long)word1 << 32; - - ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode); - - if (AddDbgComments) - { - string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} "; - - dbgOpCode += (decode?.Method.Name ?? "???"); - - if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy) - { - int offset = ((int)(opCode >> 20) << 8) >> 8; - - long target = position + offset; - - dbgOpCode += " (0x" + target.ToString("x16") + ")"; - } - - block.AddNode(new ShaderIrCmnt(dbgOpCode)); - } - - if (decode == null) - { - continue; - } - - decode(block, opCode, position); - } - while (!IsFlowChange(block.GetLastNode())); - - block.EndPosition = position; - } - - private static bool IsFlowChange(ShaderIrNode node) - { - return !NodeHasNext(GetInnermostOp(node)); - } - - private static ShaderIrOp GetInnermostOp(ShaderIrNode node) - { - if (node is ShaderIrCond cond) - { - node = cond.Child; - } - - return node is ShaderIrOp op ? op : null; - } - - private static bool NodeHasNext(ShaderIrNode node) - { - if (!(node is ShaderIrOp op)) - { - return true; - } - - return op.Inst != ShaderIrInst.Exit && - op.Inst != ShaderIrInst.Bra; - } - } -}
\ No newline at end of file |
