public static void Dump(IGalMemory memory, long position, GalShaderType type, string extSuffix = "") { if (!IsDumpEnabled()) { return; } string fileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(type) + extSuffix + ".bin"; string fullPath = Path.Combine(FullDir(), fileName); string codePath = Path.Combine(CodeDir(), fileName); DumpIndex++; using (FileStream fullFile = File.Create(fullPath)) using (FileStream codeFile = File.Create(codePath)) { BinaryWriter fullWriter = new BinaryWriter(fullFile); BinaryWriter codeWriter = new BinaryWriter(codeFile); for (long i = 0; i < 0x50; i += 4) { fullWriter.Write(memory.ReadInt32(position + i)); } long offset = 0; ulong instruction = 0; //Dump until a NOP instruction is found while ((instruction >> 48 & 0xfff8) != 0x50b0) { uint word0 = (uint)memory.ReadInt32(position + 0x50 + offset + 0); uint word1 = (uint)memory.ReadInt32(position + 0x50 + offset + 4); instruction = word0 | (ulong)word1 << 32; //Zero instructions (other kind of NOP) stop immediatly, //this is to avoid two rows of zeroes if (instruction == 0) { break; } fullWriter.Write(instruction); codeWriter.Write(instruction); offset += 8; } //Align to meet nvdisasm requeriments while (offset % 0x20 != 0) { fullWriter.Write(0); codeWriter.Write(0); offset += 4; } } }
private ShaderStage ShaderStageFactory( IGalMemory Memory, long Position, long PositionB, bool IsDualVp, GalShaderType Type) { GlslProgram Program; GlslDecompiler Decompiler = new GlslDecompiler(); if (IsDualVp) { ShaderDumper.Dump(Memory, Position, Type, "a"); ShaderDumper.Dump(Memory, PositionB, Type, "b"); Program = Decompiler.Decompile( Memory, Position, PositionB, Type); } else { ShaderDumper.Dump(Memory, Position, Type); Program = Decompiler.Decompile(Memory, Position, Type); } return(new ShaderStage( Type, Program.Code, Program.Textures, Program.Uniforms)); }
public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType) { Blocks = ShaderDecoder.Decode(Memory, Position); Decl = new GlslDecl(Blocks, ShaderType); SB = new StringBuilder(); SB.AppendLine("#version 410 core"); PrintDeclTextures(); PrintDeclUniforms(); PrintDeclInAttributes(); PrintDeclOutAttributes(); PrintDeclGprs(); PrintDeclPreds(); PrintBlockScope(Blocks[0], null, null, "void main()", IdentationStr); string GlslCode = SB.ToString(); return(new GlslProgram( GlslCode, Decl.Textures.Values, Decl.Uniforms.Values)); }
public ShaderHeader(IGalMemory Memory, long Position) { uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0); uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4); uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8); uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12); uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16); SphType = ReadBits(CommonWord0, 0, 5); Version = ReadBits(CommonWord0, 5, 5); ShaderType = ReadBits(CommonWord0, 10, 4); MrtEnable = ReadBits(CommonWord0, 14, 1) != 0; KillsPixels = ReadBits(CommonWord0, 15, 1) != 0; DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0; SassVersion = ReadBits(CommonWord0, 17, 4); DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0; DoesFp64 = ReadBits(CommonWord0, 27, 1) != 0; StreamOutMask = ReadBits(CommonWord0, 28, 4); ShaderLocalMemoryLowSize = ReadBits(CommonWord1, 0, 24); PerPatchAttributeCount = ReadBits(CommonWord1, 24, 8); ShaderLocalMemoryHighSize = ReadBits(CommonWord2, 0, 24); ThreadsPerInputPrimitive = ReadBits(CommonWord2, 24, 8); ShaderLocalMemoryCrsSize = ReadBits(CommonWord3, 0, 24); OutputTopology = ReadBits(CommonWord3, 24, 4); MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12); StoreReqStart = ReadBits(CommonWord4, 12, 8); StoreReqEnd = ReadBits(CommonWord4, 24, 8); }
public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "") { if (!IsDumpEnabled()) { return; } string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin"; string FullPath = Path.Combine(FullDir(), FileName); string CodePath = Path.Combine(CodeDir(), FileName); DumpIndex++; using (FileStream FullFile = File.Create(FullPath)) using (FileStream CodeFile = File.Create(CodePath)) { BinaryWriter FullWriter = new BinaryWriter(FullFile); BinaryWriter CodeWriter = new BinaryWriter(CodeFile); for (long i = 0; i < 0x50; i += 4) { FullWriter.Write(Memory.ReadInt32(Position + i)); } long Offset = 0; ulong Instruction = 0; //Dump until a NOP instruction is found while ((Instruction >> 48 & 0xfff8) != 0x50b0) { uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0); uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4); Instruction = Word0 | (ulong)Word1 << 32; //Zero instructions (other kind of NOP) stop immediatly, //this is to avoid two rows of zeroes if (Instruction == 0) { break; } FullWriter.Write(Instruction); CodeWriter.Write(Instruction); Offset += 8; } //Align to meet nvdisasm requeriments while (Offset % 0x20 != 0) { FullWriter.Write(0); CodeWriter.Write(0); Offset += 4; } } }
public void CreateShader(IGalMemory Memory, long Tag, GalShaderType Type) { if (Memory == null) { throw new ArgumentNullException(nameof(Memory)); } Shader.Create(Memory, Tag, Type); }
public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType) { Blocks = ShaderDecoder.Decode(Memory, Position); BlocksB = null; Decl = new GlslDecl(Blocks, ShaderType); return(Decompile()); }
private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type) { GlslProgram Program = GetGlslProgram(Memory, Position, Type); return(new ShaderStage( Type, Program.Code, Program.Textures, Program.Uniforms)); }
public ShaderHeader(IGalMemory Memory, long Position) { uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0); uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4); uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8); uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12); uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16); SphType = ReadBits(CommonWord0, 0, 5); Version = ReadBits(CommonWord0, 5, 5); ShaderType = ReadBits(CommonWord0, 10, 4); MrtEnable = ReadBits(CommonWord0, 14, 1) != 0; KillsPixels = ReadBits(CommonWord0, 15, 1) != 0; DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0; SassVersion = ReadBits(CommonWord0, 17, 4); DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0; DoesFp64 = ReadBits(CommonWord0, 27, 1) != 0; StreamOutMask = ReadBits(CommonWord0, 28, 4); ShaderLocalMemoryLowSize = ReadBits(CommonWord1, 0, 24); PerPatchAttributeCount = ReadBits(CommonWord1, 24, 8); ShaderLocalMemoryHighSize = ReadBits(CommonWord2, 0, 24); ThreadsPerInputPrimitive = ReadBits(CommonWord2, 24, 8); ShaderLocalMemoryCrsSize = ReadBits(CommonWord3, 0, 24); OutputTopology = ReadBits(CommonWord3, 24, 4); MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12); StoreReqStart = ReadBits(CommonWord4, 12, 8); StoreReqEnd = ReadBits(CommonWord4, 24, 8); //Type 2 (fragment?) reading uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72); uint Type2Omap = (uint)Memory.ReadInt32(Position + 76); OmapTargets = new OmapTarget[8]; for (int i = 0; i < OmapTargets.Length; i++) { int Offset = i * 4; OmapTargets[i] = new OmapTarget { Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0, Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0, Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0, Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0 }; } OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0; OmapDepth = ReadBits(Type2Omap, 1, 1) != 0; }
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning) { long Position = Block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. if (((Position - Beginning) & 0x1f) == 0) { Position += 8; continue; } uint Word0 = (uint)Memory.ReadInt32(Position + 0); uint Word1 = (uint)Memory.ReadInt32(Position + 4); Position += 8; long OpCode = Word0 | (long)Word1 << 32; ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode); if (AddDbgComments) { string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} "; DbgOpCode += (Decode?.Method.Name ?? "???"); if (Decode == ShaderDecode.Bra) { 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); }while (!IsFlowChange(Block.GetLastNode())); Block.EndPosition = Position; }
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 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(); }
public GlslProgram Decompile( IGalMemory Memory, long VpAPosition, long VpBPosition, GalShaderType ShaderType) { Blocks = ShaderDecoder.Decode(Memory, VpAPosition); BlocksB = ShaderDecoder.Decode(Memory, VpBPosition); GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType); GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType); Decl = GlslDecl.Merge(DeclVpA, DeclVpB); return(Decompile()); }
private OglShaderStage ShaderStageFactory( IGalMemory memory, long position, long positionB, bool isDualVp, GalShaderType type) { GlslProgram program; GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver); int shaderDumpIndex = ShaderDumper.DumpIndex; if (isDualVp) { ShaderDumper.Dump(memory, position, type, "a"); ShaderDumper.Dump(memory, positionB, type, "b"); program = decompiler.Decompile(memory, position, positionB, type); } else { ShaderDumper.Dump(memory, position, type); program = decompiler.Decompile(memory, position, type); } string code = program.Code; if (ShaderDumper.IsDumpEnabled()) { code = "//Shader " + shaderDumpIndex + Environment.NewLine + code; } return(new OglShaderStage(type, code, program.Uniforms, program.Textures)); }
private OglShaderStage ShaderStageFactory( IGalMemory memory, long position, long positionB, bool isDualVp, GalShaderType type) { ShaderConfig config = new ShaderConfig(type, OglLimit.MaxUboSize); ShaderProgram program; if (isDualVp) { ShaderDumper.Dump(memory, position, type, "a"); ShaderDumper.Dump(memory, positionB, type, "b"); program = Translator.Translate(memory, (ulong)position, (ulong)positionB, config); } else { ShaderDumper.Dump(memory, position, type); program = Translator.Translate(memory, (ulong)position, config); } string code = program.Code; if (ShaderDumper.IsDumpEnabled()) { int shaderDumpIndex = ShaderDumper.DumpIndex; code = "//Shader " + shaderDumpIndex + Environment.NewLine + code; } return(new OglShaderStage(type, code, program.Info.CBuffers, program.Info.Textures)); }
private OGLShaderStage ShaderStageFactory( IGalMemory Memory, long Position, long PositionB, bool IsDualVp, GalShaderType Type) { GlslProgram Program; GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize); int ShaderDumpIndex = ShaderDumper.DumpIndex; if (IsDualVp) { ShaderDumper.Dump(Memory, Position, Type, "a"); ShaderDumper.Dump(Memory, PositionB, Type, "b"); Program = Decompiler.Decompile(Memory, Position, PositionB, Type); } else { ShaderDumper.Dump(Memory, Position, Type); Program = Decompiler.Decompile(Memory, Position, Type); } string Code = Program.Code; if (ShaderDumper.IsDumpEnabled()) { Code = "//Shader " + ShaderDumpIndex + Environment.NewLine + Code; } return(new OGLShaderStage(Type, Code, Program.Uniforms, Program.Textures)); }
public static ShaderProgram Translate( IGalMemory memory, ulong address, ulong addressB, ShaderConfig config) { Operation[] shaderOps = DecodeShader(memory, address, config.Type); if (addressB != 0) { // Dual vertex shader. Operation[] shaderOpsB = DecodeShader(memory, addressB, config.Type); shaderOps = Combine(shaderOps, shaderOpsB); } BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(shaderOps); Dominance.FindDominators(irBlocks[0], irBlocks.Length); Dominance.FindDominanceFrontiers(irBlocks); Ssa.Rename(irBlocks); Optimizer.Optimize(irBlocks); StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks); GlslProgram program = GlslGenerator.Generate(sInfo, config); ShaderProgramInfo spInfo = new ShaderProgramInfo( program.CBufferDescriptors, program.TextureDescriptors); return(new ShaderProgram(spInfo, program.Code)); }
private GlslProgram GetGlslProgram(IGalMemory Memory, long Position, GalShaderType Type) { GlslDecompiler Decompiler = new GlslDecompiler(); return(Decompiler.Decompile(Memory, Position + 0x50, Type)); }
public void Create(IGalMemory memory, long key, GalShaderType type) { _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, key, 0, false, type)); }
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start) { Dictionary <long, ShaderIrBlock> Visited = new Dictionary <long, ShaderIrBlock>(); Dictionary <long, ShaderIrBlock> VisitedEnd = new Dictionary <long, ShaderIrBlock>(); Queue <ShaderIrBlock> Blocks = new Queue <ShaderIrBlock>(); ShaderIrBlock Enqueue(long 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(Start + HeaderSize); while (Blocks.Count > 0) { ShaderIrBlock Current = Blocks.Dequeue(); FillBlock(Memory, Current, Start + HeaderSize); //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 Op = GetInnermostOp(LastNode); if (Op?.Inst == ShaderIrInst.Bra) { int Offset = ((ShaderIrOperImm)Op.OperandA).Value; long Target = Current.EndPosition + Offset; Current.Branch = 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) { ulong FirstPos = ulong.MaxValue; foreach (ShaderIrBlock Block in Visited.Values) { if (FirstPos > (ulong)Block.Position) { FirstPos = (ulong)Block.Position; } } ShaderIrBlock Current = Visited[(long)FirstPos]; do { Graph[Graph.Length - Visited.Count] = Current; Visited.Remove(Current.Position); Current = Current.Next; }while (Current != null); } return(Graph); }
public void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type) { _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, vpAPos, key, true, type)); }
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()); }
public void Create(IGalMemory Memory, long Tag, GalShaderType Type) { Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Memory, Tag, Type)); }
public void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type) { Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type)); }
public void Create(IGalMemory Memory, long Key, GalShaderType Type) { Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, 0, false, Type)); }
private static Operation[] DecodeShader(IGalMemory memory, ulong address, GalShaderType shaderType) { ShaderHeader header = new ShaderHeader(memory, address); Block[] cfg = Decoder.Decode(memory, address); EmitterContext context = new EmitterContext(shaderType, header); for (int blkIndex = 0; blkIndex < cfg.Length; blkIndex++) { Block block = cfg[blkIndex]; context.CurrBlock = block; context.MarkLabel(context.GetLabel(block.Address)); for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++) { OpCode op = block.OpCodes[opIndex]; if (op.NeverExecute) { continue; } Operand predSkipLbl = null; bool skipPredicateCheck = op.Emitter == InstEmit.Bra; if (op is OpCodeSync opSync) { // If the instruction is a SYNC instruction with only one // possible target address, then the instruction is basically // just a simple branch, we can generate code similar to branch // instructions, with the condition check on the branch itself. skipPredicateCheck |= opSync.Targets.Count < 2; } if (!(op.Predicate.IsPT || skipPredicateCheck)) { Operand label; if (opIndex == block.OpCodes.Count - 1 && block.Next != null) { label = context.GetLabel(block.Next.Address); } else { label = Label(); predSkipLbl = label; } Operand pred = Register(op.Predicate); if (op.InvertPredicate) { context.BranchIfTrue(label, pred); } else { context.BranchIfFalse(label, pred); } } context.CurrOp = op; op.Emitter(context); if (predSkipLbl != null) { context.MarkLabel(predSkipLbl); } } } return(context.GetOperations()); }
public static ShaderProgram Translate(IGalMemory memory, ulong address, ShaderConfig config) { return(Translate(memory, address, 0, config)); }
public ShaderHeader(IGalMemory memory, ulong address) { int commonWord0 = memory.ReadInt32((long)address + 0); int commonWord1 = memory.ReadInt32((long)address + 4); int commonWord2 = memory.ReadInt32((long)address + 8); int commonWord3 = memory.ReadInt32((long)address + 12); int commonWord4 = memory.ReadInt32((long)address + 16); SphType = commonWord0.Extract(0, 5); Version = commonWord0.Extract(5, 5); ShaderType = commonWord0.Extract(10, 4); MrtEnable = commonWord0.Extract(14); KillsPixels = commonWord0.Extract(15); DoesGlobalStore = commonWord0.Extract(16); SassVersion = commonWord0.Extract(17, 4); DoesLoadOrStore = commonWord0.Extract(26); DoesFp64 = commonWord0.Extract(27); StreamOutMask = commonWord0.Extract(28, 4); ShaderLocalMemoryLowSize = commonWord1.Extract(0, 24); PerPatchAttributeCount = commonWord1.Extract(24, 8); ShaderLocalMemoryHighSize = commonWord2.Extract(0, 24); ThreadsPerInputPrimitive = commonWord2.Extract(24, 8); ShaderLocalMemoryCrsSize = commonWord3.Extract(0, 24); OutputTopology = commonWord3.Extract(24, 4); MaxOutputVertexCount = commonWord4.Extract(0, 12); StoreReqStart = commonWord4.Extract(12, 8); StoreReqEnd = commonWord4.Extract(24, 8); int type2OmapTarget = memory.ReadInt32((long)address + 72); int type2Omap = memory.ReadInt32((long)address + 76); OmapTargets = new OutputMapTarget[8]; for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4) { OmapTargets[offset >> 2] = new OutputMapTarget( type2OmapTarget.Extract(offset + 0), type2OmapTarget.Extract(offset + 1), type2OmapTarget.Extract(offset + 2), type2OmapTarget.Extract(offset + 3)); } OmapSampleMask = type2Omap.Extract(0); OmapDepth = type2Omap.Extract(1); }
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); }