diff options
| author | gdk <gab.dark.100@gmail.com> | 2019-10-13 03:02:07 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | 1876b346fea647e8284a66bb6d62c38801035cff (patch) | |
| tree | 6eeff094298cda84d1613dc5ec0691e51d7b35f1 /Ryujinx.Graphics/Shader/Decoders/Decoder.cs | |
| parent | f617fb542a0e3d36012d77a4b5acbde7b08902f2 (diff) | |
Initial work
Diffstat (limited to 'Ryujinx.Graphics/Shader/Decoders/Decoder.cs')
| -rw-r--r-- | Ryujinx.Graphics/Shader/Decoders/Decoder.cs | 406 |
1 files changed, 0 insertions, 406 deletions
diff --git a/Ryujinx.Graphics/Shader/Decoders/Decoder.cs b/Ryujinx.Graphics/Shader/Decoders/Decoder.cs deleted file mode 100644 index 754e0388..00000000 --- a/Ryujinx.Graphics/Shader/Decoders/Decoder.cs +++ /dev/null @@ -1,406 +0,0 @@ -using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Shader.Instructions; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Emit; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; - -namespace Ryujinx.Graphics.Shader.Decoders -{ - static class Decoder - { - private const long HeaderSize = 0x50; - - private delegate object OpActivator(InstEmitter emitter, ulong address, long opCode); - - private static ConcurrentDictionary<Type, OpActivator> _opActivators; - - static Decoder() - { - _opActivators = new ConcurrentDictionary<Type, OpActivator>(); - } - - public static Block[] Decode(IGalMemory memory, ulong address) - { - List<Block> blocks = new List<Block>(); - - Queue<Block> workQueue = new Queue<Block>(); - - Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>(); - - Block GetBlock(ulong blkAddress) - { - if (!visited.TryGetValue(blkAddress, out Block block)) - { - block = new Block(blkAddress); - - workQueue.Enqueue(block); - - visited.Add(blkAddress, block); - } - - return block; - } - - ulong startAddress = address + HeaderSize; - - GetBlock(startAddress); - - while (workQueue.TryDequeue(out Block currBlock)) - { - // Check if the current block is inside another block. - if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex)) - { - Block nBlock = blocks[nBlkIndex]; - - if (nBlock.Address == currBlock.Address) - { - throw new InvalidOperationException("Found duplicate block address on the list."); - } - - nBlock.Split(currBlock); - - blocks.Insert(nBlkIndex + 1, currBlock); - - continue; - } - - // If we have a block after the current one, set the limit address. - ulong limitAddress = ulong.MaxValue; - - if (nBlkIndex != blocks.Count) - { - Block nBlock = blocks[nBlkIndex]; - - int nextIndex = nBlkIndex + 1; - - if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) - { - limitAddress = blocks[nextIndex].Address; - } - else if (nBlock.Address > currBlock.Address) - { - limitAddress = blocks[nBlkIndex].Address; - } - } - - FillBlock(memory, currBlock, limitAddress, startAddress); - - if (currBlock.OpCodes.Count != 0) - { - foreach (OpCodeSsy ssyOp in currBlock.SsyOpCodes) - { - GetBlock(ssyOp.GetAbsoluteAddress()); - } - - // 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 program, Next is null. - OpCode lastOp = currBlock.GetLastOp(); - - if (lastOp is OpCodeBranch op) - { - currBlock.Branch = GetBlock(op.GetAbsoluteAddress()); - } - - if (!IsUnconditionalBranch(lastOp)) - { - currBlock.Next = GetBlock(currBlock.EndAddress); - } - } - - // Insert the new block on the list (sorted by address). - if (blocks.Count != 0) - { - Block nBlock = blocks[nBlkIndex]; - - blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock); - } - else - { - blocks.Add(currBlock); - } - } - - foreach (Block ssyBlock in blocks.Where(x => x.SsyOpCodes.Count != 0)) - { - for (int ssyIndex = 0; ssyIndex < ssyBlock.SsyOpCodes.Count; ssyIndex++) - { - PropagateSsy(visited, ssyBlock, ssyIndex); - } - } - - return blocks.ToArray(); - } - - private static bool BinarySearch(List<Block> blocks, ulong address, out int index) - { - index = 0; - - int left = 0; - int right = blocks.Count - 1; - - while (left <= right) - { - int size = right - left; - - int middle = left + (size >> 1); - - Block block = blocks[middle]; - - index = middle; - - if (address >= block.Address && address < block.EndAddress) - { - return true; - } - - if (address < block.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return false; - } - - private static void FillBlock( - IGalMemory memory, - Block block, - ulong limitAddress, - ulong startAddress) - { - ulong address = block.Address; - - do - { - if (address >= limitAddress) - { - break; - } - - // Ignore scheduling instructions, which are written every 32 bytes. - if (((address - startAddress) & 0x1f) == 0) - { - address += 8; - - continue; - } - - uint word0 = (uint)memory.ReadInt32((long)(address + 0)); - uint word1 = (uint)memory.ReadInt32((long)(address + 4)); - - ulong opAddress = address; - - address += 8; - - long opCode = word0 | (long)word1 << 32; - - (InstEmitter emitter, Type opCodeType) = OpCodeTable.GetEmitter(opCode); - - if (emitter == null) - { - // TODO: Warning, illegal encoding. - continue; - } - - OpCode op = MakeOpCode(opCodeType, emitter, opAddress, opCode); - - block.OpCodes.Add(op); - } - while (!IsBranch(block.GetLastOp())); - - block.EndAddress = address; - - block.UpdateSsyOpCodes(); - } - - private static bool IsUnconditionalBranch(OpCode opCode) - { - return IsUnconditional(opCode) && IsBranch(opCode); - } - - private static bool IsUnconditional(OpCode opCode) - { - if (opCode is OpCodeExit op && op.Condition != Condition.Always) - { - return false; - } - - return opCode.Predicate.Index == RegisterConsts.PredicateTrueIndex && !opCode.InvertPredicate; - } - - private static bool IsBranch(OpCode opCode) - { - return (opCode is OpCodeBranch && opCode.Emitter != InstEmit.Ssy) || - opCode is OpCodeSync || - opCode is OpCodeExit; - } - - private static OpCode MakeOpCode(Type type, InstEmitter emitter, ulong address, long opCode) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator); - - return (OpCode)createInstance(emitter, address, opCode); - } - - private static OpActivator CacheOpActivator(Type type) - { - Type[] argTypes = new Type[] { typeof(InstEmitter), typeof(ulong), typeof(long) }; - - DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes); - - ILGenerator generator = mthd.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes)); - generator.Emit(OpCodes.Ret); - - return (OpActivator)mthd.CreateDelegate(typeof(OpActivator)); - } - - private struct PathBlockState - { - public Block Block { get; } - - private enum RestoreType - { - None, - PopSsy, - PushSync - } - - private RestoreType _restoreType; - - private ulong _restoreValue; - - public bool ReturningFromVisit => _restoreType != RestoreType.None; - - public PathBlockState(Block block) - { - Block = block; - _restoreType = RestoreType.None; - _restoreValue = 0; - } - - public PathBlockState(int oldSsyStackSize) - { - Block = null; - _restoreType = RestoreType.PopSsy; - _restoreValue = (ulong)oldSsyStackSize; - } - - public PathBlockState(ulong syncAddress) - { - Block = null; - _restoreType = RestoreType.PushSync; - _restoreValue = syncAddress; - } - - public void RestoreStackState(Stack<ulong> ssyStack) - { - if (_restoreType == RestoreType.PushSync) - { - ssyStack.Push(_restoreValue); - } - else if (_restoreType == RestoreType.PopSsy) - { - while (ssyStack.Count > (uint)_restoreValue) - { - ssyStack.Pop(); - } - } - } - } - - private static void PropagateSsy(Dictionary<ulong, Block> blocks, Block ssyBlock, int ssyIndex) - { - OpCodeSsy ssyOp = ssyBlock.SsyOpCodes[ssyIndex]; - - Stack<PathBlockState> workQueue = new Stack<PathBlockState>(); - - HashSet<Block> visited = new HashSet<Block>(); - - Stack<ulong> ssyStack = new Stack<ulong>(); - - void Push(PathBlockState pbs) - { - if (pbs.Block == null || visited.Add(pbs.Block)) - { - workQueue.Push(pbs); - } - } - - Push(new PathBlockState(ssyBlock)); - - while (workQueue.TryPop(out PathBlockState pbs)) - { - if (pbs.ReturningFromVisit) - { - pbs.RestoreStackState(ssyStack); - - continue; - } - - Block current = pbs.Block; - - int ssyOpCodesCount = current.SsyOpCodes.Count; - - if (ssyOpCodesCount != 0) - { - Push(new PathBlockState(ssyStack.Count)); - - for (int index = ssyIndex; index < ssyOpCodesCount; index++) - { - ssyStack.Push(current.SsyOpCodes[index].GetAbsoluteAddress()); - } - } - - ssyIndex = 0; - - if (current.Next != null) - { - Push(new PathBlockState(current.Next)); - } - - if (current.Branch != null) - { - Push(new PathBlockState(current.Branch)); - } - else if (current.GetLastOp() is OpCodeSync op) - { - ulong syncAddress = ssyStack.Pop(); - - if (ssyStack.Count == 0) - { - ssyStack.Push(syncAddress); - - op.Targets.Add(ssyOp, op.Targets.Count); - - ssyOp.Syncs.TryAdd(op, Local()); - } - else - { - Push(new PathBlockState(syncAddress)); - Push(new PathBlockState(blocks[syncAddress])); - } - } - } - } - } -}
\ No newline at end of file |
