/* * * if (last.Output._PacketType.Type == GPUPacketType.PM4_DRAW_INDX_2) * { * var dword0 = last.Raw.Words[0]; * var indexCount = dword0 >> 16; * var primitiveType = (GPUPrimitiveType)(dword0 & 0x3F); * * ret += "Draw2 " + Enum.GetName(typeof(GPUPrimitiveType), primitiveType) + " (Count: " + indexCount.ToString() + ")"; * } * else if (last._PacketType.Type == GPUPacketType.PM4_DRAW_INDX) * { * var dword0 = last.Raw.Words[0]; * var dword1 = last.Raw.Words[1]; * * var indexCount = dword1 >> 16; * var primitiveType = (GPUPrimitiveType)(dword1 & 0x3F); * var source = (dword1 >> 6) & 0x3; * * if (source == 0x0) * { * bool is32Bit = 0 != ((dword1 >> 11) & 0x1); * ret += (is32Bit ? "DrawIndexed32 " : "DrawIndexed16 ") + Enum.GetName(typeof(GPUPrimitiveType), primitiveType) + " (Count: " + indexCount.ToString() + ")"; * } * else if (source == 0x2) * { * ret += "Draw " + Enum.GetName(typeof(GPUPrimitiveType), primitiveType) + " (Count: " + indexCount.ToString() + ")"; * } * } * else if (last.Type == GPUPacketType.PM4_HACK_SWAP) * { * return "SWAP"; * } */ private GPUExecutorResult ExecutePacketType0(RawPacket _packet, GPUCommandOutput _out) { var packetData = _packet.Data; var regCount = ((packetData >> 16) & 0x3FFF) + 1; var baseIndex = (packetData & 0x7FFF); var writeOneReg = 0 != ((packetData >> 15) & 0x1); for (UInt32 i = 0; i < regCount; i++) { UInt32 regData = _packet.Words[i]; UInt32 regIndex = writeOneReg ? baseIndex : baseIndex + i; WriteRegister(regIndex, regData, _out); } if (_out != null) { if (writeOneReg) { _out._Desc = String.Format("SetRegs [Start: {0}, Count: {1}]", baseIndex, regCount); } else { _out._Desc = String.Format("SetRegs [At: {0}, Times: {1}]", baseIndex, regCount); } _out._PacketType = GPUPacketType.PM1_REGS; } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType2(RawPacket _packet, GPUCommandOutput _out) { if (_out != null) { _out._PacketType = GPUPacketType.PM3_NOP; } return(GPUExecutorResult.Skipped); }
private void WriteRegister(UInt32 _regIndex, UInt32 _value, GPUCommandOutput _out) { _State.RegValues[_regIndex] = _value; if (_out != null) { _out.Log(String.Format("Register {0} ({1}) written with {2} ({3})", Enum.GetName(typeof(GPURegisterName), _regIndex), _regIndex, _value, ToFloat(_value))); } }
// advance the GPU state by executing the packet - NOTE, some packets don't change the regs public GPUExecutorResult ExecutePacket(RawPacket _packet, GPUCommandOutput _out) { var packetType = _packet.Data >> 30; switch (packetType) { case 0x00: return(ExecutePacketType0(_packet, _out)); case 0x01: return(ExecutePacketType1(_packet, _out)); case 0x02: return(ExecutePacketType2(_packet, _out)); case 0x03: return(ExecutePacketType3(_packet, _out)); } return(GPUExecutorResult.Invalid); }
private GPUExecutorResult ExecutePacketType1(RawPacket _packet, GPUCommandOutput _out) { var packetData = _packet.Data; var regIndexA = packetData & 0x7FF; var regIndexB = (packetData >> 11) & 0x7FF; var regDataA = _packet.Words[0]; var regDataB = _packet.Words[1]; WriteRegister(regIndexA, regDataA, _out); WriteRegister(regIndexB, regDataB, _out); if (_out != null) { _out._Desc = String.Format("SetReg2 [RegA: {0}, RegB: {1}]", regIndexA, regIndexB); _out._PacketType = GPUPacketType.PM2_REGS; } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_EVENT_WRITE_EXT(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_DRAW_INDX_2(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { // draw using supplied indices in packet var dword0 = _packet.Words[0]; var indexCount = dword0 >> 16; var primitiveType = (GPUPrimitiveType)(dword0 & 0x3F); if (_out != null) { _out._Desc = String.Format("Draw: Indexed2 {0} {1}", Enum.GetName(typeof(GPUPrimitiveType), primitiveType), indexCount); _out._DumpInDrawCall = true; _out.Log("Draw: Indexed2"); } var source = (dword0 >> 6) & 0x3; if (source == 2) { DrawInfo ds = new DrawInfo(); ds.IndexCount = indexCount; ds.PrimitiveType = primitiveType; ds.IndexData = 0; ds.IndexFormat = GPUIndexFormat.Index16; ds.IndexEndianess = GPUEndianFormat.FormatUnspecified; ds.BaseVertexIndex = 0; IssueDraw(_packet, ds, _out); } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_EVENT_WRITE(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var initiator = _packet.Words[0]; WriteRegister(GPURegisterName.VGT_EVENT_INITIATOR, initiator & 0x3F, _out); return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_REG_RMW(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var rmwSetup = _packet.Words[0]; var andMask = _packet.Words[0]; var orMask = _packet.Words[0]; // read value var regIndex = (rmwSetup & 0x1FFF); if (_out != null) { _out.Log(String.Format("Register: {0} ({1})", Enum.GetName(typeof(GPURegisterName), regIndex), regIndex)); } var value = _State.RegValues[regIndex]; if (_out != null) { _out.Log(String.Format("Incoming value: 0x{0:X}", value)); } var oldValue = value; // OR value (with reg or immediate value) if (0 != ((rmwSetup >> 30) & 0x1)) { // | reg if (_out != null) { _out.Log(String.Format("Or Mask Register: {0} ({1})", Enum.GetName(typeof(GPURegisterName), orMask & 0x1FFF), orMask & 0x1FFF)); } var orValue = _State.RegValues[orMask & 0x1FFF]; if (_out != null) { _out.Log(String.Format("Or Mask Value: 0x{0:X}", orValue)); } value |= orValue; } else { // | imm if (_out != null) { _out.Log(String.Format("Or Mask Value: 0x{0:X}", orMask)); } value |= orMask; } // AND value (with reg or immediate value) if (0 != ((rmwSetup >> 31) & 0x1)) { // & reg if (_out != null) { _out.Log(String.Format("And Mask Register: {0} ({1})", Enum.GetName(typeof(GPURegisterName), andMask & 0x1FFF), andMask & 0x1FFF)); } var andValue = _State.RegValues[andMask & 0x1FFF]; if (_out != null) { _out.Log(String.Format("And Mask Value: 0x{0:X}", andValue)); } value &= andValue; } else { // & imm value &= andMask; if (_out != null) { _out.Log(String.Format("And Mask Value: 0x{0:X}", andMask)); } } // write new value if (_out != null) { _out.Log(String.Format("Final Value: 0x{0:X}", value)); } WriteRegister(regIndex, value, _out); // executed return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_COND_WRITE(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { // conditional write to memory or register var waitInfo = _packet.Words[0]; var pollRegAddr = _packet.Words[1]; var refValue = _packet.Words[2]; var mask = _packet.Words[3]; var writeRegAddr = _packet.Words[4]; var writeData = _packet.Words[5]; // read input value UInt32 value = 0; if (0 != (waitInfo & 0x10)) { // get swap format (swap) var readFormat = (pollRegAddr & 3); var readAddress = (pollRegAddr & ~3); if (_out != null) { _out.Log(String.Format("Read Address: 0x{0:X}", readAddress)); } if (_out != null) { _out.Log(String.Format("Read Mode: {0}", readFormat)); } // load the value var memBlock = _packet.FindMemoryReadBlock((UInt32)readAddress); if (memBlock != null) { value = GPUSwap32((UInt32)memBlock.LoadUint32At(0), readFormat); } } else { if (_out != null) { _out.Log(String.Format("Read Register: {0} ({1})", Enum.GetName(typeof(GPURegisterName), pollRegAddr), pollRegAddr)); } value = _State.RegValues[pollRegAddr]; } if (_out != null) { _out.Log(String.Format("Incoming Value: 0x{0:X}", value)); _out.Log(String.Format("Incoming Mask: 0x{0:X}", mask)); _out.Log(String.Format("Masked Value: 0x{0:X}", mask & value)); if ((waitInfo & 7) > 0 && ((waitInfo & 7) < 7)) { _out.Log(String.Format("Reference Value: 0x{0:X}", refValue)); } } // compare bool matched = false; switch (waitInfo & 0x7) { case 0x0: matched = false; if (_out != null) { _out.Log("Condition: Never"); } break; case 0x1: // Less than reference. matched = (value & mask) < refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} < 0x{1:X}", (value & mask), refValue)); } break; case 0x2: // Less than or equal to reference. matched = (value & mask) <= refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} <= 0x{1:X}", (value & mask), refValue)); } break; case 0x3: // Equal to reference. matched = (value & mask) == refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} == 0x{1:X}", (value & mask), refValue)); } break; case 0x4: // Not equal to reference. matched = (value & mask) != refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} != 0x{1:X}", (value & mask), refValue)); } break; case 0x5: // Greater than or equal to reference. matched = (value & mask) >= refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} >= 0x{1:X}", (value & mask), refValue)); } break; case 0x6: // Greater than reference. matched = (value & mask) > refValue; if (_out != null) { _out.Log(String.Format("Condition: 0x{0:X} > 0x{1:X}", (value & mask), refValue)); } break; case 0x7: // Always matched = true; if (_out != null) { _out.Log("Condition: Always"); } break; } // write result _out.Log(matched ? "Matched: YES" : "Matched: NO"); if (matched) { if (_out != null) { _out.Log(String.Format("Write Data: 0x{0:X}", writeData)); } // Write. if (0 != (waitInfo & 0x100)) { var writeFormat = (writeRegAddr & 3); var writeAddress = (writeRegAddr & ~3); if (_out != null) { _out.Log(String.Format("Write Address: 0x{0:X}", writeAddress)); } if (_out != null) { _out.Log(String.Format("Write Mode: {0}", writeFormat)); } } else { WriteRegister(writeRegAddr, writeData, _out); } } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_HACK_SWAP(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { // nothing happens in the replay return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_WAIT_REG_MEM(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { if (_out == null) { return(GPUExecutorResult.Executed); } var waitInfo = _packet.Words[0]; var pollRegAddr = _packet.Words[1]; var refValue = _packet.Words[2]; var mask = _packet.Words[3]; var wait = _packet.Words[4]; UInt32 incomingValue = 0; if (0 != (waitInfo & 0x10)) { var memoryAddress = pollRegAddr & ~0x3; var memoryMode = pollRegAddr & 3; _out.Log(String.Format("Memory address: 0x{0:X}", memoryAddress)); _out.Log(String.Format("Memory mode: {0}", memoryMode)); var memBlock = _packet.FindMemoryReadBlock((UInt32)memoryAddress); if (memBlock != null) { incomingValue = memBlock.LoadUint32AtBE(0); } } else { _out.Log(String.Format("Read register: {0}", Enum.GetName(typeof(GPURegisterName), pollRegAddr))); incomingValue = _State.RegValues[pollRegAddr]; } _out.Log(String.Format("Incoming value: 0x{0:X}", incomingValue)); _out.Log(String.Format("Incoming mask: 0x{0:X}", mask)); _out.Log(String.Format("Masked value: 0x{0:X}", incomingValue & mask)); switch (waitInfo & 0x7) { case 0x0: _out.Log("Condition: Never"); break; case 0x1: _out.Log(String.Format("Condition: 0x{0:X} < 0x{1:X}", incomingValue & mask, refValue)); break; case 0x2: _out.Log(String.Format("Condition: 0x{0:X} <= 0x{1:X}", incomingValue & mask, refValue)); break; case 0x3: _out.Log(String.Format("Condition: 0x{0:X} == 0x{1:X}", incomingValue & mask, refValue)); break; case 0x4: _out.Log(String.Format("Condition: 0x{0:X} != 0x{1:X}", incomingValue & mask, refValue)); break; case 0x5: _out.Log(String.Format("Condition: 0x{0:X} >= 0x{1:X}", incomingValue & mask, refValue)); break; case 0x6: _out.Log(String.Format("Condition: 0x{0:X} > 0x{1:X}", incomingValue & mask, refValue)); break; case 0x7: _out.Log("Condition: Always"); break; } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_SET_CONSTANT(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var offsetType = _packet.Words[0]; var index = offsetType & 0x7FF; var type = (offsetType >> 16) & 0xFF; var baseIndex = index; switch (type) { case 0: // ALU if (_out != null) { _out.Log("Block: ALU"); } baseIndex += 0x4000; break; case 1: // FETCH if (_out != null) { _out.Log("Block: FETCH"); } baseIndex += 0x4800; break; case 2: // BOOL if (_out != null) { _out.Log("Block: BOOL"); } baseIndex += 0x4900; break; case 3: // LOOP if (_out != null) { _out.Log("Block: LOOP"); } baseIndex += 0x4908; break; case 4: // REGISTERS if (_out != null) { _out.Log("Block: REGISTERS"); } baseIndex += 0x2000; break; default: return(GPUExecutorResult.Invalid); } // set data for (UInt32 n = 0; n < (count - 1); n++) { UInt32 data = _packet.Words[n + 1]; WriteRegister(index + n, data, _out); } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3(RawPacket _packet, GPUCommandOutput _out) { var packetData = _packet.Data; var opcode = (packetData >> 8) & 0x7F; var count = ((packetData >> 16) & 0x3FFF) + 1; if (_out != null) { _out._PacketType = (GPUPacketType)opcode; _out._Desc = Enum.GetName(typeof(GPUPacketType), opcode); } // in predicated mode we may need to skip this command if the tile mask does not match tile selector if ((packetData & 1) != 0) { // skip if we are NOT the target bool shouldSkip = (_TileMask & _TileSelector) == 0; if (shouldSkip) { return(GPUExecutorResult.Skipped); } } // process opcode switch ((GPUPacketType)opcode) { case GPUPacketType.PM4_ME_INIT: return(ExecutePacketType3_ME_INIT(_packet, packetData, count, _out)); case GPUPacketType.PM4_NOP: return(ExecutePacketType3_NOP(_packet, packetData, count, _out)); case GPUPacketType.PM4_INTERRUPT: return(ExecutePacketType3_INTERRUPT(_packet, packetData, count, _out)); case GPUPacketType.PM4_HACK_SWAP: return(ExecutePacketType3_HACK_SWAP(_packet, packetData, count, _out)); case GPUPacketType.PM4_WAIT_REG_MEM: return(ExecutePacketType3_WAIT_REG_MEM(_packet, packetData, count, _out)); case GPUPacketType.PM4_REG_RMW: return(ExecutePacketType3_REG_RMW(_packet, packetData, count, _out)); case GPUPacketType.PM4_COND_WRITE: return(ExecutePacketType3_COND_WRITE(_packet, packetData, count, _out)); case GPUPacketType.PM4_EVENT_WRITE: return(ExecutePacketType3_EVENT_WRITE(_packet, packetData, count, _out)); case GPUPacketType.PM4_EVENT_WRITE_SHD: return(ExecutePacketType3_EVENT_WRITE_SHD(_packet, packetData, count, _out)); case GPUPacketType.PM4_EVENT_WRITE_EXT: return(ExecutePacketType3_EVENT_WRITE_EXT(_packet, packetData, count, _out)); case GPUPacketType.PM4_DRAW_INDX: return(ExecutePacketType3_DRAW_INDX(_packet, packetData, count, _out)); case GPUPacketType.PM4_DRAW_INDX_2: return(ExecutePacketType3_DRAW_INDX_2(_packet, packetData, count, _out)); case GPUPacketType.PM4_SET_CONSTANT: return(ExecutePacketType3_SET_CONSTANT(_packet, packetData, count, _out)); case GPUPacketType.PM4_SET_CONSTANT2: return(ExecutePacketType3_SET_CONSTANT2(_packet, packetData, count, _out)); case GPUPacketType.PM4_LOAD_ALU_CONSTANT: return(ExecutePacketType3_LOAD_ALU_CONSTANT(_packet, packetData, count, _out)); case GPUPacketType.PM4_SET_SHADER_CONSTANTS: return(ExecutePacketType3_SET_SHADER_CONSTANTS(_packet, packetData, count, _out)); case GPUPacketType.PM4_IM_LOAD: return(ExecutePacketType3_IM_LOAD(_packet, packetData, count, _out)); case GPUPacketType.PM4_IM_LOAD_IMMEDIATE: return(ExecutePacketType3_IM_LOAD_IMMEDIATE(_packet, packetData, count, _out)); case GPUPacketType.PM4_INVALIDATE_STATE: return(ExecutePacketType3_INVALIDATE_STATE(_packet, packetData, count, _out)); // tiled rendering bit mask case GPUPacketType.PM4_SET_BIN_MASK_LO: { var loMask = _packet.Words[0]; _TileMask = (_TileMask & 0xFFFFFFFF00000000UL) | ((UInt64)loMask); _out.Log(String.Format("LoMask = {0:X}", loMask)); return(GPUExecutorResult.Executed); } case GPUPacketType.PM4_SET_BIN_MASK_HI: { var hiMask = _packet.Words[0]; _TileMask = (_TileMask & 0xFFFFFFFFUL) | (((UInt64)hiMask) << 32); _out.Log(String.Format("HiMask = {0:X}", hiMask)); return(GPUExecutorResult.Executed); } case GPUPacketType.PM4_SET_BIN_SELECT_LO: { var loSelect = _packet.Words[0]; _TileSelector = (_TileSelector & 0xFFFFFFFF00000000UL) | ((UInt64)loSelect); _out.Log(String.Format("LoSelector = {0:X}", loSelect)); return(GPUExecutorResult.Executed); } case GPUPacketType.PM4_SET_BIN_SELECT_HI: { var hiSelect = _packet.Words[0]; _TileSelector = (_TileSelector & 0xFFFFFFFFUL) | (((UInt64)hiSelect) << 32); _out.Log(String.Format("HiSelector = {0:X}", hiSelect)); return(GPUExecutorResult.Executed); } // Ignored packets - useful if breaking on the default handler below. case (GPUPacketType)0x50: // 0xC0015000 usually 2 words, 0xFFFFFFFF / 0x00000000 case (GPUPacketType)0x51: // 0xC0015100 usually 2 words, 0xFFFFFFFF / 0xFFFFFFFF { return(GPUExecutorResult.Skipped); } } // invalid packet encountered return(GPUExecutorResult.Invalid); }
private void IssueDraw(RawPacket _packet, DrawInfo ds, GPUCommandOutput _out) { if (_out == null) { return; } if (ds.IndexData != 0) { var indexSize = ((ds.IndexFormat == GPUIndexFormat.Index16) ? 2U : 4U); _out.Log(String.Format("Index Data Endianess: {0}", Enum.GetName(typeof(GPUEndianFormat), ds.IndexEndianess))); _out.Log(String.Format("Index Data Address: {0}", MakeMemoryAddr(_packet, ds.IndexData, indexSize, ds.IndexEndianess, ds.IndexFormat))); } _out.Log(String.Format("Index Count: {0}", ds.IndexCount)); _out.Log(String.Format("Base Vertex: {0}", ds.BaseVertexIndex)); _out.Log(String.Format("Primitive Type: {0}", Enum.GetName(typeof(GPUPrimitiveType), ds.PrimitiveType))); // raw shaders foreach (var memoryRef in _packet.Memory) { if (memoryRef.Tag == "PSSourceCode") { _out.Log(String.Format("Pixel shader HLSL: <a href=\"hlsl,{0}\">0x{1:X6}</a>", memoryRef.Block.LocalIndex, memoryRef.Block.Adress)); } else if (memoryRef.Tag == "VSSourceCode") { _out.Log(String.Format("Vertex shader HLSL: <a href=\"hlsl,{0}\">0x{1:X6}</a>", memoryRef.Block.LocalIndex, memoryRef.Block.Adress)); } } if (_State.VertexShader != null) { VFetchMerger vfetchMerger = new VFetchMerger(); // output fetch parameters, merge streams var fetches = _State.VertexShader.VertexFetches; foreach (var vfetch in fetches) { UInt32 regIndex = ((UInt32)GPURegisterName.SHADER_CONSTANT_FETCH_00_0) + (vfetch.slot * 2); GPUVertexFetchData fetchReg = new GPUVertexFetchData(_State.RegValues[regIndex + 0], _State.RegValues[regIndex + 1]); var fetchAddress = (fetchReg.address << 2); _out.Log(String.Format("VFetch: Address=0x{0:X6} Slot={1} Offset={2} Stride={3} Format={4} DataType={5}", fetchAddress, vfetch.slot, vfetch.offset, vfetch.stride, Enum.GetName(typeof(GPUFetchFormat), vfetch.format), Enum.GetName(typeof(GPUFetchDataType), vfetch.dataType))); var block = _packet.FindMemoryReadBlock(fetchAddress); if (block != null) { vfetchMerger.AddVFetch(block, vfetch); } } // create vertex data references foreach (var stream in vfetchMerger.Streams) { _out.Log(String.Format("Stream: <a href=\"{0}\">0x{1:X6}, {2} element(s)</a>", stream.MakeLink(), stream.Block.Adress, stream.Elements.Count)); } } if (_State.PixelShader != null) { var tfetches = _State.PixelShader.TextureFetches; foreach (var tfetch in tfetches) { _out.Log(String.Format("<h2>Pixel Shader Texture {0}</h2>", tfetch.slot)); { string tfetchText = ""; tfetch.Descibe(ref tfetchText); _out.Log("<h4>Shader texture:</h4>" + tfetchText); } { var fetchReg = (UInt32)GPURegisterName.SHADER_CONSTANT_FETCH_00_0 + (tfetch.slot * 6); var data0 = _State.RegValues[fetchReg + 0]; var data1 = _State.RegValues[fetchReg + 1]; var data2 = _State.RegValues[fetchReg + 2]; var data3 = _State.RegValues[fetchReg + 3]; var data4 = _State.RegValues[fetchReg + 4]; var data5 = _State.RegValues[fetchReg + 5]; var boundedTex = new GPUTextureFetchData(data0, data1, data2, data3, data4, data5); _out._Textures.Add(boundedTex); string boundexText = ""; boundedTex.Describe(ref boundexText); _out.Log("<h4>Bounded texture:</h4>" + boundexText); } _out.Log("<hr/>"); } } }
public static ParsedPacket Parse(RawPacket raw, int packetIndex, ParsedDrawCall drawcall, GPUCommandOutput commandOutput) { ParsedPacket ret = new ParsedPacket(); ret._Raw = raw; ret._Index = packetIndex; ret._DrawCall = drawcall; ret._CmdOutput = commandOutput; if (drawcall != null) { drawcall.Linkup(ret); } return(ret); }
private GPUExecutorResult ExecutePacketType3_LOAD_ALU_CONSTANT(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var address = _packet.Words[0] & 0x3FFFFFFF; var offset_type = _packet.Words[1]; var index = offset_type & 0x7FF; var baseIndex = index; var size_dwords = _packet.Words[2] & 0xFFF; var type = (offset_type >> 16) & 0xFF; switch (type) { case 0: // ALU index += 0x4000; break; case 1: // FETCH index += 0x4800; break; case 2: // BOOL index += 0x4900; break; case 3: // LOOP index += 0x4908; break; case 4: // REGISTERS index += 0x2000; break; } if (_out != null) { _out.Log(String.Format("ALU First Register: {0}", baseIndex)); _out.Log(String.Format("ALU Actual Register: {0}", Enum.GetName(typeof(GPURegisterName), index))); _out.Log(String.Format("ALU Num Registers: {0}", size_dwords / 4)); _out.Log(String.Format("ALU Data Address: {0}", MakeMemoryAddrALUConst(_packet, address))); } var block = _packet.FindMemoryReadBlock(address); if (block != null) { var data = block.LoadAllDataAs32BE(); for (int i = 0; i < (int)size_dwords; ++i) { WriteRegister((UInt32)(index + i), data[i], _out); } } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_INVALIDATE_STATE(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_IM_LOAD_IMMEDIATE(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { // load sequencer instruction memory (code embedded in packet) var dword0 = _packet.Words[0]; var dword1 = _packet.Words[1]; var shaderType = (GPUShaderType)(dword0 & 0x3); var startSize = dword1; var start = startSize >> 16; var sizeDwords = startSize & 0xFFFF; // dwords if (_packet.Memory.Length == 1) { var block = _packet.Memory[0].Block; var pixel = (shaderType == GPUShaderType.ShaderPixel); if (_out != null) { _out.Log("Shader type: " + ((shaderType == GPUShaderType.ShaderPixel) ? "Pixel" : "Vertex")); _out.Log("Shader words: " + sizeDwords.ToString()); _out.Log(String.Format("Shader data: {0}", MakeShaderAddr(block, pixel))); _out._DumpInDrawCall = true; } if (block != null) { if (pixel) { _out._Desc = "LoadPixelShaderIM"; _State.SetPixelShader(block); } else { _out._Desc = "LoadVertexShaderIM"; _State.SetVertexShader(block); } } } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_IM_LOAD(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { // load sequencer instruction memory (pointer-based) var addrType = _packet.Words[0]; var shaderType = (GPUShaderType)(addrType & 0x3); var addr = addrType & ~0x3; var startSize = _packet.Words[1]; var start = startSize >> 16; var sizeDwords = startSize & 0xFFFF; // dwords var block = _packet.FindMemoryReadBlock((UInt32)addr); var pixel = (shaderType == GPUShaderType.ShaderPixel); if (_out != null) { _out.Log("Shader type: " + ((shaderType == GPUShaderType.ShaderPixel) ? "Pixel" : "Vertex")); _out.Log("Shader words: " + sizeDwords.ToString()); _out.Log(String.Format("Shader data: {0}", MakeShaderAddr(block, pixel))); _out._DumpInDrawCall = true; } if (block != null) { if (pixel) { _out._Desc = "LoadPixelShader"; _State.SetPixelShader(block); } else { _out._Desc = "LoadVertexShader"; _State.SetVertexShader(block); } } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_SET_SHADER_CONSTANTS(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var offsetType = _packet.Words[0]; var index = offsetType & 0xFFFF; for (UInt32 n = 0; n < count - 1; n++) { var data = _packet.Words[1 + n]; WriteRegister(index + n, data, _out); } return(GPUExecutorResult.Executed); }
private GPUExecutorResult ExecutePacketType3_DRAW_INDX(RawPacket _packet, UInt32 packetData, UInt32 count, GPUCommandOutput _out) { var dword0 = _packet.Words[0]; var dword1 = _packet.Words[1]; var indexCount = dword1 >> 16; var primitiveType = (GPUPrimitiveType)(dword1 & 0x3F); var source = (dword1 >> 6) & 0x3; if (source == 0x0) { if (_out != null) { _out._Desc = String.Format("Draw: Indexed {0} {1}", Enum.GetName(typeof(GPUPrimitiveType), primitiveType), indexCount); _out._DumpInDrawCall = true; _out.Log("Draw: Indexed"); } // extract information bool is32Bit = 0 != ((dword1 >> 11) & 0x1); var indexAddr = _packet.Words[2]; var indexSize = _packet.Words[3]; // setup index state var indexFormat = is32Bit ? GPUIndexFormat.Index32 : GPUIndexFormat.Index16; var indexEndianess = (GPUEndianFormat)(indexSize >> 30); // setup draw state DrawInfo ds = new DrawInfo(); ds.IndexData = indexAddr; ds.IndexFormat = indexFormat; ds.IndexEndianess = indexEndianess; ds.IndexCount = indexCount; ds.BaseVertexIndex = _State.RegValues[(int)GPURegisterName.VGT_INDX_OFFSET]; ds.PrimitiveType = primitiveType; IssueDraw(_packet, ds, _out); } else if (source == 0x2) { if (_out != null) { _out._Desc = String.Format("Draw: {0} {1}", Enum.GetName(typeof(GPUPrimitiveType), primitiveType), indexCount); _out._DumpInDrawCall = true; _out.Log("Draw: Not Indexed"); } DrawInfo ds = new DrawInfo(); ds.IndexData = 0; ds.IndexFormat = GPUIndexFormat.Index16; ds.IndexEndianess = GPUEndianFormat.FormatUnspecified; ds.IndexCount = indexCount; ds.BaseVertexIndex = 0; //_State.RegValues[ GPURegisterName.VGT_INDX_OFFSET ]; ds.PrimitiveType = primitiveType; IssueDraw(_packet, ds, _out); } return(GPUExecutorResult.Executed); }
static public ParsedData Parse(RawDumpData raw) { ParsedData ret = new ParsedData(); var packetsMap = new Dictionary <RawPacket, ParsedPacket>(); // create drawcall list ret._ShaderCache = new GPUShaderCache(); ret._DrawCalls = new List <ParsedDrawCall>(); ret._DrawGroups = new List <ParsedDrawGroup>(); // prepare GPU state for the duration of parsing GPUState parseState = new GPUState(ret._ShaderCache); GPUExecutor parseExec = new GPUExecutor(parseState); // parse all packets int packedIndex = 1; int drawCallIndex = 1; int drawGroupIndex = 1; ParsedDrawCall drawCall = null; ParsedDrawGroup drawGroup = null; foreach (var rawPacket in raw.Packets) { // start new drawcall if (drawCall == null) { drawCall = new ParsedDrawCall(drawCallIndex); ret._DrawCalls.Add(drawCall); drawCallIndex += 1; } // execute packet GPUCommandOutput executeOutput = new GPUCommandOutput(); var executionResult = parseExec.ExecutePacket(rawPacket, executeOutput); if (executionResult != GPUExecutorResult.Invalid) { // add data packetsMap[rawPacket] = ParsedPacket.Parse(rawPacket, packedIndex, drawCall, executeOutput); ++packedIndex; } // restart after each drawcall if (packetsMap[rawPacket].Output.IsDraw()) { // capture final state at each drawcall if (drawCall != null) { drawCall.CapturedState = new GPUStateCapture(parseState); // extract the viewport/render target settings for the draw call - required to match it to the draw group var stateRenderTargets = new GPUStateRenderTargets(drawCall.CapturedState); var stateViewport = new GPUStateCaptureViewport(drawCall.CapturedState); // determine if we should add this draw call to current draw group if ((drawGroup != null) && drawGroup.Compatible(stateViewport, stateRenderTargets)) { drawGroup.AddDrawCall(drawCall); } else { drawGroup = new ParsedDrawGroup(drawGroupIndex++, stateViewport, stateRenderTargets); drawGroup.AddDrawCall(drawCall); ret._DrawGroups.Add(drawGroup); } } // reset drawCall = null; } } return(ret); }