From e84f356a29b3d232c7b0c59a4771ea83ab31de98 Mon Sep 17 00:00:00 2001 From: O1L Date: Sun, 22 Feb 2015 18:47:12 +0400 Subject: [PATCH 1/3] Implemented binary fragment program disassembler --- rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp | 477 ++++++++++++++++++++++ rpcs3/Emu/RSX/CgBinaryProgram.h | 367 +++++++++++++++++ rpcs3/Emu/RSX/GL/GLFragmentProgram.h | 112 ----- rpcs3/Emu/RSX/GL/GLVertexProgram.h | 176 -------- rpcs3/Emu/RSX/RSXFragmentProgram.h | 133 ++++++ rpcs3/Emu/RSX/RSXVertexProgram.h | 190 +++++++++ rpcs3/Gui/CgDisasm.cpp | 58 +++ rpcs3/Gui/CgDisasm.h | 22 + rpcs3/Gui/MainFrame.cpp | 11 +- rpcs3/Gui/MainFrame.h | 2 +- rpcs3/emucore.vcxproj | 2 + rpcs3/emucore.vcxproj.filters | 6 + rpcs3/rpcs3.cpp | 160 -------- rpcs3/rpcs3.vcxproj | 2 + rpcs3/rpcs3.vcxproj.filters | 7 +- 15 files changed, 1273 insertions(+), 452 deletions(-) create mode 100644 rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp create mode 100644 rpcs3/Emu/RSX/CgBinaryProgram.h create mode 100644 rpcs3/Gui/CgDisasm.cpp create mode 100644 rpcs3/Gui/CgDisasm.h diff --git a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp new file mode 100644 index 0000000000..2729d1758f --- /dev/null +++ b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp @@ -0,0 +1,477 @@ +#include "stdafx.h" + +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "CgBinaryProgram.h" +#include "Emu/RSX/RSXFragmentProgram.h" + +void CgBinaryDisasm::AddCodeAsm(const std::string& code) +{ + std::string op_name = ""; + + if (dst.dest_reg == 63) + { + m_dst_reg_name = fmt::format("RC%s, ", GetMask().c_str()); + op_name = rsx_fp_op_names[m_opcode] + "XC"; + } + + else + { + m_dst_reg_name = fmt::format("%s%d%s, ", dst.fp16 ? "H" : "R", dst.dest_reg, GetMask().c_str()); + op_name = rsx_fp_op_names[m_opcode] + std::string(dst.fp16 ? "H" : "R"); + } + + switch (m_opcode) + { + case RSX_FP_OPCODE_BRK: + case RSX_FP_OPCODE_CAL: + case RSX_FP_OPCODE_FENCT: + case RSX_FP_OPCODE_FENCB: + case RSX_FP_OPCODE_IFE: + case RSX_FP_OPCODE_KIL: + case RSX_FP_OPCODE_LOOP: + case RSX_FP_OPCODE_NOP: + case RSX_FP_OPCODE_REP: + case RSX_FP_OPCODE_RET: m_dst_reg_name = ""; break; + + default: break; + } + + m_arb_shader += (op_name + " " + m_dst_reg_name + FormatDisAsm(code) + ";" + "\n"); +} + +std::string CgBinaryDisasm::GetMask() +{ + std::string ret; + + static const char dst_mask[4] = + { + 'x', 'y', 'z', 'w' + }; + + if (dst.mask_x) ret += dst_mask[0]; + if (dst.mask_y) ret += dst_mask[1]; + if (dst.mask_z) ret += dst_mask[2]; + if (dst.mask_w) ret += dst_mask[3]; + + return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret); +} + +std::string CgBinaryDisasm::AddRegDisAsm(u32 index, int fp16) +{ + return std::string(fp16 ? "H" : "R") + std::to_string(index); +} + +std::string CgBinaryDisasm::AddConstDisAsm() +{ + u32* data = (u32*)&m_buffer[m_offset + m_size + 4 * sizeof(u32)]; + + m_step = 2 * 4 * sizeof(u32); + const u32 x = GetData(data[0]); + const u32 y = GetData(data[1]); + const u32 z = GetData(data[2]); + const u32 w = GetData(data[3]); + + char buf[1024]; + sprintf(buf, "{0x%08x(%g), 0x%08x(%g), 0x%08x(%g), 0x%08x(%g)}", x, (float&)x, y, (float&)y, z, (float&)z, w, (float&)w); + + return fmt::format(buf); +} + +std::string CgBinaryDisasm::AddTexDisAsm() +{ + return (std::string("TEX") + std::to_string(dst.tex_num)); +} + +std::string CgBinaryDisasm::GetCondDisAsm() +{ + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle, cond; + swizzle += f[src0.cond_swizzle_x]; + swizzle += f[src0.cond_swizzle_y]; + swizzle += f[src0.cond_swizzle_z]; + swizzle += f[src0.cond_swizzle_w]; + + if (swizzle == "xxxx") swizzle = "x"; + if (swizzle == "yyyy") swizzle = "y"; + if (swizzle == "zzzz") swizzle = "z"; + if (swizzle == "wwww") swizzle = "w"; + + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + if (src0.exec_if_gr && src0.exec_if_eq) + { + cond = "GE"; + } + else if (src0.exec_if_lt && src0.exec_if_eq) + { + cond = "LE"; + } + else if (src0.exec_if_gr && src0.exec_if_lt) + { + cond = "NE"; + } + else if (src0.exec_if_gr) + { + cond = "GT"; + } + else if (src0.exec_if_lt) + { + cond = "LT"; + } + else if (src0.exec_if_eq) + { + cond = "FL"; + } + + else + { + cond = "TR"; + } + + return cond + swizzle; +} + +std::string CgBinaryDisasm::FormatDisAsm(const std::string& code) +{ + const std::pair> repl_list[] = + { + { "$$", []() -> std::string { return "$"; } }, + { "$0", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm), this, src0) }, + { "$1", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm), this, src1) }, + { "$2", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm), this, src2) }, + { "$t", std::bind(std::mem_fn(&CgBinaryDisasm::AddTexDisAsm), this) }, + { "$m", std::bind(std::mem_fn(&CgBinaryDisasm::GetMask), this) }, + { "$cond", std::bind(std::mem_fn(&CgBinaryDisasm::GetCondDisAsm), this) }, + { "$c", std::bind(std::mem_fn(&CgBinaryDisasm::AddConstDisAsm), this) } + }; + + return fmt::replace_all(code, repl_list); +} + +template std::string CgBinaryDisasm::GetSrcDisAsm(T src) +{ + std::string ret; + + switch (src.reg_type) + { + case 0: //tmp + ret += AddRegDisAsm(src.tmp_reg_index, src.fp16); + break; + + case 1: //input + { + static const std::string reg_table[] = + { + "WPOS", "COL0", "COL1", "FOGC", "TEX0", + "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", + "TEX6", "TEX7", "TEX8", "TEX9", "SSA" + }; + + const std::string perspective_correction = src2.perspective_corr ? "g" : "f"; + const std::string input_attr_reg = reg_table[dst.src_attr_reg_num]; + + switch (dst.src_attr_reg_num) + { + case 0x00: ret += reg_table[0]; break; + default: + if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0])) + { + ret += fmt::format("%s[%s]", perspective_correction.c_str(), input_attr_reg.c_str()); + } + else + { + LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num)); + } + break; + } + } + break; + + case 2: //const + ret += AddConstDisAsm(); + break; + + default: + LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type)); + break; + } + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle = ""; + swizzle += f[src.swizzle_x]; + swizzle += f[src.swizzle_y]; + swizzle += f[src.swizzle_z]; + swizzle += f[src.swizzle_w]; + + if (swizzle == "xxxx") swizzle = "x"; + if (swizzle == "yyyy") swizzle = "y"; + if (swizzle == "zzzz") swizzle = "z"; + if (swizzle == "wwww") swizzle = "w"; + + if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; + + if (src.neg) ret = "-" + ret; + + return ret; +} + +void CgBinaryDisasm::TaskFP() +{ + m_size = 0; + u32* data = (u32*)&m_buffer[m_offset]; + assert((m_buffer_size - m_offset) % sizeof(u32) == 0); + for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) + { + data[i] = re32(data[i]); + } + + enum + { + FORCE_NONE, + FORCE_SCT, + FORCE_SCB + }; + + int forced_unit = FORCE_NONE; + + while (true) + { + for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); + finded != m_end_offsets.end(); + finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size)) + { + m_end_offsets.erase(finded); + m_arb_shader += "ENDIF;\n"; + } + + for (auto finded = std::find(m_loop_end_offsets.begin(), m_loop_end_offsets.end(), m_size); + finded != m_loop_end_offsets.end(); + finded = std::find(m_loop_end_offsets.begin(), m_loop_end_offsets.end(), m_size)) + { + m_loop_end_offsets.erase(finded); + m_arb_shader += "ENDLOOP;\n"; + } + + for (auto finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size); + finded != m_else_offsets.end(); + finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size)) + { + m_else_offsets.erase(finded); + m_arb_shader += "ELSE;\n"; + } + + dst.HEX = GetData(data[0]); + src0.HEX = GetData(data[1]); + src1.HEX = GetData(data[2]); + src2.HEX = GetData(data[3]); + + m_step = 4 * sizeof(u32); + m_opcode = dst.opcode | (src1.opcode_is_branch << 6); + + auto SCT = [&]() + { + switch (m_opcode) + { + case RSX_FP_OPCODE_ADD: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DIV: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DIVSQ: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP2: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP3: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP4: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP2A: AddCodeAsm("$0, $1, $2"); break; + case RSX_FP_OPCODE_MAD: AddCodeAsm("$0, $1, $2"); break; + case RSX_FP_OPCODE_MAX: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_MIN: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_MOV: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_MUL: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_RCP: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_RSQ: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_SEQ: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SFL: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SGE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SGT: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SLE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SLT: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SNE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_STR: AddCodeAsm("$0, $1"); break; + + default: + return false; + } + + return true; + }; + + auto SCB = [&]() + { + switch (m_opcode) + { + case RSX_FP_OPCODE_ADD: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_COS: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_DP2: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP3: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP4: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_DP2A: AddCodeAsm("$0, $1, $2"); break; + case RSX_FP_OPCODE_DST: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_REFL: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_EX2: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_FLR: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_FRC: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_LIT: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_LIF: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_LRP: AddCodeAsm("# WARNING"); break; + case RSX_FP_OPCODE_LG2: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_MAD: AddCodeAsm("$0, $1, $2"); break; + case RSX_FP_OPCODE_MAX: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_MIN: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_MOV: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_MUL: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_PK2: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_PK4: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_PK16: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_PKB: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_PKG: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_SEQ: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SFL: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SGE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SGT: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SIN: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_SLE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SLT: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_SNE: AddCodeAsm("$0, $1"); break; + case RSX_FP_OPCODE_STR: AddCodeAsm("$0, $1"); break; + + default: + return false; + } + + return true; + }; + + auto TEX_SRB = [&]() + { + switch (m_opcode) + { + case RSX_FP_OPCODE_DDX: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_DDY: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_NRM: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_BEM: AddCodeAsm("# WARNING"); break; + case RSX_FP_OPCODE_TEX: AddCodeAsm("$0, $t"); break; + case RSX_FP_OPCODE_TEXBEM: AddCodeAsm("# WARNING"); break; + case RSX_FP_OPCODE_TXP: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_TXPBEM: AddCodeAsm("# WARNING"); break; + case RSX_FP_OPCODE_TXD: AddCodeAsm("$0, $1, $t"); break; + case RSX_FP_OPCODE_TXB: AddCodeAsm("$0, $t"); break; + case RSX_FP_OPCODE_TXL: AddCodeAsm("$0, $t"); break; + case RSX_FP_OPCODE_UP2: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_UP4: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_UP16: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_UPB: AddCodeAsm("$0"); break; + case RSX_FP_OPCODE_UPG: AddCodeAsm("$0"); break; + + default: + return false; + } + + return true; + }; + + auto SIP = [&]() + { + switch (m_opcode) + { + case RSX_FP_OPCODE_BRK: AddCodeAsm("$cond"); break; + case RSX_FP_OPCODE_CAL: AddCodeAsm("$cond"); break; + case RSX_FP_OPCODE_FENCT: AddCodeAsm(""); break; + case RSX_FP_OPCODE_FENCB: AddCodeAsm(""); break; + + case RSX_FP_OPCODE_IFE: + { + m_else_offsets.push_back(src1.else_offset << 2); + m_end_offsets.push_back(src2.end_offset << 2); + AddCodeAsm("($cond)"); + } + break; + + case RSX_FP_OPCODE_LOOP: + { + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCodeAsm(fmt::Format("{ %u, %u, %u }", src1.end_counter, src1.init_counter, src1.increment)); + } + else + { + m_loop_end_offsets.push_back(src2.end_offset << 2); + AddCodeAsm(fmt::Format("{ %u, %u, %u }", src1.end_counter, src1.init_counter, src1.increment)); + } + } + break; + + case RSX_FP_OPCODE_REP: + { + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + m_arb_shader += "# RSX_FP_OPCODE_REP_1\n"; + } + else + { + m_end_offsets.push_back(src2.end_offset << 2); + m_arb_shader += "# RSX_FP_OPCODE_REP_2\n"; + } + } + break; + + case RSX_FP_OPCODE_RET: AddCodeAsm("$cond"); break; + + default: + return false; + } + + return true; + }; + + switch (m_opcode) + { + case RSX_FP_OPCODE_NOP: AddCodeAsm(""); break; + case RSX_FP_OPCODE_KIL: AddCodeAsm("$cond"); break; + + default: + if (forced_unit == FORCE_NONE) + { + if (SIP()) break; + if (SCT()) break; + if (TEX_SRB()) break; + if (SCB()) break; + } + else if (forced_unit == FORCE_SCT) + { + forced_unit = FORCE_NONE; + if (SCT()) break; + } + else if (forced_unit == FORCE_SCB) + { + forced_unit = FORCE_NONE; + if (SCB()) break; + } + + LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", m_opcode, forced_unit); + break; + } + + m_size += m_step; + + if (dst.end) + { + m_arb_shader.pop_back(); + m_arb_shader += " # last inctruction\nEND\n"; + break; + } + + assert(m_step % sizeof(u32) == 0); + data += m_step / sizeof(u32); + } +} \ No newline at end of file diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h new file mode 100644 index 0000000000..789019b1ab --- /dev/null +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -0,0 +1,367 @@ +#pragma once + +#include +#include "Utilities/rFile.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/RSX/GL/GLVertexProgram.h" +#include "Emu/RSX/GL/GLFragmentProgram.h" + +typedef be_t CGprofile; +typedef be_t CGbool; +typedef be_t CGresource; +typedef be_t CGenum; +typedef be_t CGtype; + +typedef be_t CgBinaryOffset; +typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset; +typedef CgBinaryOffset CgBinaryFloatOffset; +typedef CgBinaryOffset CgBinaryStringOffset; +typedef CgBinaryOffset CgBinaryParameterOffset; + +// a few typedefs +typedef struct CgBinaryParameter CgBinaryParameter; +typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant; +typedef struct CgBinaryVertexProgram CgBinaryVertexProgram; +typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram; +typedef struct CgBinaryProgram CgBinaryProgram; + +// fragment programs have their constants embedded in the microcode +struct CgBinaryEmbeddedConstant +{ + be_t ucodeCount; // occurances + be_t ucodeOffset[1]; // offsets that need to be patched follow +}; + +// describe a binary program parameter (CgParameter is opaque) +struct CgBinaryParameter +{ + CGtype type; // cgGetParameterType() + CGresource res; // cgGetParameterResource() + CGenum var; // cgGetParameterVariability() + be_t resIndex; // cgGetParameterResourceIndex() + CgBinaryStringOffset name; // cgGetParameterName() + CgBinaryFloatOffset defaultValue; // default constant value + CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information + CgBinaryStringOffset semantic; // cgGetParameterSemantic() + CGenum direction; // cgGetParameterDirection() + be_t paramno; // 0..n: cgGetParameterIndex() -1: globals + CGbool isReferenced; // cgIsParameterReferenced() + CGbool isShared; // cgIsParameterShared() +}; + +// attributes needed for vshaders +struct CgBinaryVertexProgram +{ + be_t instructionCount; // #instructions + be_t instructionSlot; // load address (indexed reads!) + be_t registerCount; // R registers count + be_t attributeInputMask; // attributes vs reads from + be_t attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL) +}; + +typedef enum +{ + CgBinaryPTTNone = 0, + CgBinaryPTT2x16 = 1, + CgBinaryPTT1x32 = 2 +} CgBinaryPartialTexType; + +// attributes needed for pshaders +struct CgBinaryFragmentProgram +{ + be_t instructionCount; // #instructions + be_t attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType + be_t texCoordsInputMask; // tex coords used by frag prog. (tex is bit n) + be_t texCoords2D; // tex coords that are 2d (tex is bit n) + be_t texCoordsCentroid; // tex coords that are centroid (tex is bit n) + u8 registerCount; // R registers count + u8 outputFromH0; // final color from R0 or H0 + u8 depthReplace; // fp generated z epth value + u8 pixelKill; // fp uses kill operations +}; + +struct CgBinaryProgram +{ + // vertex/pixel shader identification (BE/LE as well) + CGprofile profile; + + // binary revision (used to verify binary and driver structs match) + be_t binaryFormatRevision; + + // total size of this struct including profile and totalSize field + be_t totalSize; + + // parameter usually queried using cgGet[First/Next]LeafParameter + be_t parameterCount; + CgBinaryParameterOffset parameterArray; + + // depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct + CgBinaryOffset program; + + // raw ucode data + be_t ucodeSize; + CgBinaryOffset ucode; + + // variable length data follows + u8 data[1]; +}; + +class CgBinaryDisasm +{ +private: + std::string m_path; // used for FP decompiler thread, delete this later + + u8* m_buffer; + size_t m_buffer_size; + std::string m_arb_shader; + std::string m_glsl_shader; + std::string m_dst_reg_name; + + // FP members + u32 m_offset; + u32 m_opcode; + u32 m_step; + u32 m_size; + std::vector m_end_offsets; + std::vector m_else_offsets; + std::vector m_loop_end_offsets; + + // VP members + static const size_t m_max_instr_count = 512; + size_t m_instr_count; + std::vector m_data; + +public: + + std::string GetArbShader() const { return m_arb_shader; } + std::string GetGlslShader() const { return m_glsl_shader; } + + // FP functions + std::string GetMask(); + void AddCodeAsm(const std::string& code); + std::string AddRegDisAsm(u32 index, int fp16); + std::string AddConstDisAsm(); + std::string AddTexDisAsm(); + std::string FormatDisAsm(const std::string& code); + std::string GetCondDisAsm(); + template std::string GetSrcDisAsm(T src); + + CgBinaryDisasm(const std::string& path) + : m_path(path) + , m_buffer(nullptr) + , m_buffer_size(0) + , m_offset(0) + , m_opcode(0) + , m_step(0) + , m_size(0) + , m_arb_shader("") + , m_dst_reg_name("") + { + rFile f(path); + if (!f.IsOpened()) + return; + + m_buffer_size = f.Length(); + m_buffer = new u8[m_buffer_size]; + f.Read(m_buffer, m_buffer_size); + f.Close(); + m_arb_shader += fmt::format("Loading... [%s]\n", path.c_str()); + } + + ~CgBinaryDisasm() + { + delete[] m_buffer; + } + + std::string GetCgParamType(u32 type) const + { + switch (type) + { + case 1045: return "float"; + case 1046: + case 1047: + case 1048: return fmt::format("float%d", type - 1044); + case 1064: return "float4x4"; + case 1066: return "sampler2D"; + case 1069: return "samplerCUBE"; + + default: return fmt::format("!UnkCgType(%d)", type); + } + } + + std::string GetCgParamName(u32 offset) const + { + std::stringstream str_stream; + std::string name = ""; + while (m_buffer[offset] != 0) + { + str_stream << m_buffer[offset]; + offset++; + } + name += str_stream.str(); + return name; + } + + std::string GetCgParamRes(u32 offset) const + { + // LOG_WARNING(GENERAL, "GetCgParamRes offset 0x%x", offset); + // TODO + return ""; + } + + std::string GetCgParamSemantic(u32 offset) const + { + std::stringstream str_stream; + std::string semantic = ""; + while (m_buffer[offset] != 0) + { + str_stream << m_buffer[offset]; + offset++; + } + semantic += str_stream.str(); + return semantic; + } + + std::string GetCgParamValue(u32 offset, u32 end_offset) const + { + std::string offsets = "offsets:"; + + u32 num = 0; + offset += 6; + while (offset < end_offset) + { + offsets += fmt::format(" %d,", m_buffer[offset] << 8 | m_buffer[offset + 1]); + offset += 4; + num++; + } + + if (num > 4) + return ""; + + offsets.pop_back(); + return fmt::format("num %d ", num) + offsets; + } + + template + T& GetCgRef(const u32 offset) + { + return reinterpret_cast(m_buffer[offset]); + } + + void BuildShaderBody() + { + GLParamArray param_array; + + auto& prog = GetCgRef(0); + + if (prog.profile == 7004) + { + auto& fprog = GetCgRef(prog.program); + m_arb_shader += "\n"; + m_arb_shader += fmt::format("# binaryFormatRevision 0x%x\n", (u32)prog.binaryFormatRevision); + m_arb_shader += fmt::format("# profile sce_fp_rsx\n"); + m_arb_shader += fmt::format("# parameterCount %d\n", (u32)prog.parameterCount); + m_arb_shader += fmt::format("# instructionCount %d\n", (u32)fprog.instructionCount); + m_arb_shader += fmt::format("# attributeInputMask 0x%x\n", (u32)fprog.attributeInputMask); + m_arb_shader += fmt::format("# registerCount %d\n\n", (u32)fprog.registerCount); + + CgBinaryParameterOffset offset = prog.parameterArray; + for (u32 i = 0; i < (u32)prog.parameterCount; i++) + { + auto& fparam = GetCgRef(offset); + + std::string param_type = GetCgParamType(fparam.type) + " "; + std::string param_name = GetCgParamName(fparam.name) + " "; + std::string param_res = GetCgParamRes(fparam.res) + " "; + std::string param_semantic = GetCgParamSemantic(fparam.semantic) + " "; + std::string param_const = GetCgParamValue(fparam.embeddedConst, fparam.name); + + m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n"; + + offset += sizeof(CgBinaryParameter); + } + + m_arb_shader += "\n"; + m_offset = prog.ucode; + TaskFP(); + + // reload binary data in the virtual memory, temporary solution + { + u32 ptr; + { + rFile f(m_path); + + if (!f.IsOpened()) + return; + + size_t size = f.Length(); + vm::ps3::init(); + ptr = vm::alloc(size); + f.Read(vm::get_ptr(ptr), size); + f.Close(); + } + + auto& vmprog = vm::get_ref(ptr); + auto& vmfprog = vm::get_ref(ptr + vmprog.program); + u32 size; + u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0); + GLFragmentDecompilerThread(m_glsl_shader, param_array, ptr + vmprog.ucode, size, ctrl).Task(); + vm::close(); + } + } + + else + { + auto& vprog = GetCgRef(prog.program); + m_arb_shader += "\n"; + m_arb_shader += fmt::format("# binaryFormatRevision 0x%x\n", (u32)prog.binaryFormatRevision); + m_arb_shader += fmt::format("# profile sce_vp_rsx\n"); + m_arb_shader += fmt::format("# parameterCount %d\n", (u32)prog.parameterCount); + m_arb_shader += fmt::format("# instructionCount %d\n", (u32)vprog.instructionCount); + m_arb_shader += fmt::format("# registerCount %d\n", (u32)vprog.registerCount); + m_arb_shader += fmt::format("# attributeInputMask 0x%x\n", (u32)vprog.attributeInputMask); + m_arb_shader += fmt::format("# attributeOutputMask 0x%x\n\n", (u32)vprog.attributeOutputMask); + + CgBinaryParameterOffset offset = prog.parameterArray; + for (u32 i = 0; i < (u32)prog.parameterCount; i++) + { + auto& vparam = GetCgRef(offset); + + std::string param_type = GetCgParamType(vparam.type) + " "; + std::string param_name = GetCgParamName(vparam.name) + " "; + std::string param_res = GetCgParamRes(vparam.res) + " "; + std::string param_semantic = GetCgParamSemantic(vparam.semantic) + " "; + std::string param_const = GetCgParamValue(vparam.embeddedConst, vparam.name); + + m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n"; + + offset += sizeof(CgBinaryParameter); + } + + m_arb_shader += "\n"; + m_offset = prog.ucode; + + u32* vdata = (u32*)&m_buffer[m_offset]; + assert((m_buffer_size - m_offset) % sizeof(u32) == 0); + for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) + { + vdata[i] = re32(vdata[i]); + } + + for (u32 i = 0; i < prog.ucodeSize / sizeof(u32); i++) + { + m_data.push_back(vdata[i]); + } + + //TaskVP(); + GLVertexDecompilerThread(m_data, m_glsl_shader, param_array).Task(); + } + } + + u32 GetData(const u32 d) const { return d << 16 | d >> 16; } + void TaskFP(); + //void TaskVP(); // TODO +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index ce40e77041..aa7acdad9f 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -5,118 +5,6 @@ struct GLFragmentDecompilerThread : public ThreadBase { - union OPDEST - { - u32 HEX; - - struct - { - u32 end : 1; // Set to 1 if this is the last instruction - u32 dest_reg : 6; // Destination register index - u32 fp16 : 1; // Destination is a half register (H0 to H47) - u32 set_cond : 1; // Condition Code Registers (CC0 and CC1) are updated - u32 mask_x : 1; - u32 mask_y : 1; - u32 mask_z : 1; - u32 mask_w : 1; - u32 src_attr_reg_num : 4; - u32 tex_num : 4; - u32 exp_tex : 1; // _bx2 - u32 prec : 2; - u32 opcode : 6; - u32 no_dest : 1; - u32 saturate : 1; // _sat - }; - } dst; - - union SRC0 - { - u32 HEX; - - struct - { - u32 reg_type : 2; - u32 tmp_reg_index : 6; - u32 fp16 : 1; - u32 swizzle_x : 2; - u32 swizzle_y : 2; - u32 swizzle_z : 2; - u32 swizzle_w : 2; - u32 neg : 1; - u32 exec_if_lt : 1; - u32 exec_if_eq : 1; - u32 exec_if_gr : 1; - u32 cond_swizzle_x : 2; - u32 cond_swizzle_y : 2; - u32 cond_swizzle_z : 2; - u32 cond_swizzle_w : 2; - u32 abs : 1; - u32 cond_mod_reg_index : 1; - u32 cond_reg_index : 1; - }; - } src0; - - union SRC1 - { - u32 HEX; - - struct - { - u32 reg_type : 2; - u32 tmp_reg_index : 6; - u32 fp16 : 1; - u32 swizzle_x : 2; - u32 swizzle_y : 2; - u32 swizzle_z : 2; - u32 swizzle_w : 2; - u32 neg : 1; - u32 abs : 1; - u32 input_mod_src0 : 3; - u32 : 6; - u32 scale : 3; - u32 opcode_is_branch : 1; - }; - - struct - { - u32 else_offset : 31; - u32 : 1; - }; - - // LOOP, REP - struct - { - u32 : 2; - u32 end_counter : 8; // End counter value for LOOP or rep count for REP - u32 init_counter : 8; // Initial counter value for LOOP - u32 : 1; - u32 increment : 8; // Increment value for LOOP - }; - } src1; - - union SRC2 - { - u32 HEX; - - u32 end_offset; - - struct - { - u32 reg_type : 2; - u32 tmp_reg_index : 6; - u32 fp16 : 1; - u32 swizzle_x : 2; - u32 swizzle_y : 2; - u32 swizzle_z : 2; - u32 swizzle_w : 2; - u32 neg : 1; - u32 abs : 1; - u32 addr_reg : 11; - u32 use_index_reg : 1; - u32 perspective_corr : 1; - }; - } src2; - std::string main; std::string& m_shader; GLParamArray& m_parr; diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.h b/rpcs3/Emu/RSX/GL/GLVertexProgram.h index de4c3d07cd..70848d93bf 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.h +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.h @@ -4,184 +4,8 @@ #include "Utilities/Thread.h" #include -enum sca_opcode -{ - RSX_SCA_OPCODE_NOP = 0x00, - RSX_SCA_OPCODE_MOV = 0x01, - RSX_SCA_OPCODE_RCP = 0x02, - RSX_SCA_OPCODE_RCC = 0x03, - RSX_SCA_OPCODE_RSQ = 0x04, - RSX_SCA_OPCODE_EXP = 0x05, - RSX_SCA_OPCODE_LOG = 0x06, - RSX_SCA_OPCODE_LIT = 0x07, - RSX_SCA_OPCODE_BRA = 0x08, - RSX_SCA_OPCODE_BRI = 0x09, - RSX_SCA_OPCODE_CAL = 0x0a, - RSX_SCA_OPCODE_CLI = 0x0b, - RSX_SCA_OPCODE_RET = 0x0c, - RSX_SCA_OPCODE_LG2 = 0x0d, - RSX_SCA_OPCODE_EX2 = 0x0e, - RSX_SCA_OPCODE_SIN = 0x0f, - RSX_SCA_OPCODE_COS = 0x10, - RSX_SCA_OPCODE_BRB = 0x11, - RSX_SCA_OPCODE_CLB = 0x12, - RSX_SCA_OPCODE_PSH = 0x13, - RSX_SCA_OPCODE_POP = 0x14, -}; - -enum vec_opcode -{ - RSX_VEC_OPCODE_NOP = 0x00, - RSX_VEC_OPCODE_MOV = 0x01, - RSX_VEC_OPCODE_MUL = 0x02, - RSX_VEC_OPCODE_ADD = 0x03, - RSX_VEC_OPCODE_MAD = 0x04, - RSX_VEC_OPCODE_DP3 = 0x05, - RSX_VEC_OPCODE_DPH = 0x06, - RSX_VEC_OPCODE_DP4 = 0x07, - RSX_VEC_OPCODE_DST = 0x08, - RSX_VEC_OPCODE_MIN = 0x09, - RSX_VEC_OPCODE_MAX = 0x0a, - RSX_VEC_OPCODE_SLT = 0x0b, - RSX_VEC_OPCODE_SGE = 0x0c, - RSX_VEC_OPCODE_ARL = 0x0d, - RSX_VEC_OPCODE_FRC = 0x0e, - RSX_VEC_OPCODE_FLR = 0x0f, - RSX_VEC_OPCODE_SEQ = 0x10, - RSX_VEC_OPCODE_SFL = 0x11, - RSX_VEC_OPCODE_SGT = 0x12, - RSX_VEC_OPCODE_SLE = 0x13, - RSX_VEC_OPCODE_SNE = 0x14, - RSX_VEC_OPCODE_STR = 0x15, - RSX_VEC_OPCODE_SSG = 0x16, - RSX_VEC_OPCODE_TEX = 0x19, -}; - struct GLVertexDecompilerThread : public ThreadBase { - union D0 - { - u32 HEX; - - struct - { - u32 addr_swz : 2; - u32 mask_w : 2; - u32 mask_z : 2; - u32 mask_y : 2; - u32 mask_x : 2; - u32 cond : 3; - u32 cond_test_enable : 1; - u32 cond_update_enable_0 : 1; - u32 dst_tmp : 6; - u32 src0_abs : 1; - u32 src1_abs : 1; - u32 src2_abs : 1; - u32 addr_reg_sel_1 : 1; - u32 cond_reg_sel_1 : 1; - u32 staturate : 1; - u32 index_input : 1; - u32 : 1; - u32 cond_update_enable_1 : 1; - u32 vec_result : 1; - u32 : 1; - }; - } d0; - - union D1 - { - u32 HEX; - - struct - { - u32 src0h : 8; - u32 input_src : 4; - u32 const_src : 10; - u32 vec_opcode : 5; - u32 sca_opcode : 5; - }; - } d1; - - union D2 - { - u32 HEX; - - struct - { - u32 src2h : 6; - u32 src1 : 17; - u32 src0l : 9; - }; - struct - { - u32 iaddrh : 6; - u32 : 26; - }; - } d2; - - union D3 - { - u32 HEX; - - struct - { - u32 end : 1; - u32 index_const : 1; - u32 dst : 5; - u32 sca_dst_tmp : 6; - u32 vec_writemask_w : 1; - u32 vec_writemask_z : 1; - u32 vec_writemask_y : 1; - u32 vec_writemask_x : 1; - u32 sca_writemask_w : 1; - u32 sca_writemask_z : 1; - u32 sca_writemask_y : 1; - u32 sca_writemask_x : 1; - u32 src2l : 11; - }; - struct - { - u32 : 29; - u32 iaddrl : 3; - }; - } d3; - - union SRC - { - union - { - u32 HEX; - - struct - { - u32 src0l : 9; - u32 src0h : 8; - }; - - struct - { - u32 src1 : 17; - }; - - struct - { - u32 src2l : 11; - u32 src2h : 6; - }; - }; - - struct - { - u32 reg_type : 2; - u32 tmp_src : 6; - u32 swz_w : 2; - u32 swz_z : 2; - u32 swz_y : 2; - u32 swz_x : 2; - u32 neg : 1; - }; - } src[3]; - struct FuncInfo { u32 offset; diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 113d3d2aea..320c5e616a 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -71,6 +71,139 @@ enum RSX_FP_OPCODE_RET = 0x45, // Return }; +static union OPDEST +{ + u32 HEX; + + struct + { + u32 end : 1; // Set to 1 if this is the last instruction + u32 dest_reg : 6; // Destination register index + u32 fp16 : 1; // Destination is a half register (H0 to H47) + u32 set_cond : 1; // Condition Code Registers (CC0 and CC1) are updated + u32 mask_x : 1; + u32 mask_y : 1; + u32 mask_z : 1; + u32 mask_w : 1; + u32 src_attr_reg_num : 4; + u32 tex_num : 4; + u32 exp_tex : 1; // _bx2 + u32 prec : 2; + u32 opcode : 6; + u32 no_dest : 1; + u32 saturate : 1; // _sat + }; +} dst; + +static union SRC0 +{ + u32 HEX; + + struct + { + u32 reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 exec_if_lt : 1; + u32 exec_if_eq : 1; + u32 exec_if_gr : 1; + u32 cond_swizzle_x : 2; + u32 cond_swizzle_y : 2; + u32 cond_swizzle_z : 2; + u32 cond_swizzle_w : 2; + u32 abs : 1; + u32 cond_mod_reg_index : 1; + u32 cond_reg_index : 1; + }; +} src0; + +static union SRC1 +{ + u32 HEX; + + struct + { + u32 reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 abs : 1; + u32 input_mod_src0 : 3; + u32 : 6; + u32 scale : 3; + u32 opcode_is_branch : 1; + }; + + struct + { + u32 else_offset : 31; + u32 : 1; + }; + + // LOOP, REP + struct + { + u32 : 2; + u32 end_counter : 8; // End counter value for LOOP or rep count for REP + u32 init_counter : 8; // Initial counter value for LOOP + u32 : 1; + u32 increment : 8; // Increment value for LOOP + }; +} src1; + +static union SRC2 +{ + u32 HEX; + + u32 end_offset; + + struct + { + u32 reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 abs : 1; + u32 addr_reg : 11; + u32 use_index_reg : 1; + u32 perspective_corr : 1; + }; +} src2; + +static const char* rsx_fp_input_attr_regs[] = +{ + "WPOS", "COL0", "COL1", "FOGC", "TEX0", + "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", + "TEX6", "TEX7", "TEX8", "TEX9", "SSA" +}; + +static const std::string rsx_fp_op_names[] = +{ + "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DP4", + "DST", "MIN", "MAX", "SLT", "SGE", "SLE", "SGT", + "SNE", "SEQ", "FRC", "FLR", "KIL", "PK4", "UP4", + "DDX", "DDY", "TEX", "TXP", "TXD", "RCP", "RSQ", + "EX2", "LG2", "LIT", "LRP", "STR", "SFL", "COS", + "SIN", "PK2", "UP2", "POW", "PKB", "UPB", "PK16", + "UP16", "BEM", "PKG", "UPG", "DP2A", "TXL", "NULL", + "TXB", "NULL", "TEXBEM", "TXPBEM", "BEMLUM", "REFL", "TIMESWTEX", + "DP2", "NRM", "DIV", "DIVSQ", "LIF", "FENCT", "FENCB", + "NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET" +}; + struct RSXFragmentProgram { u32 size; diff --git a/rpcs3/Emu/RSX/RSXVertexProgram.h b/rpcs3/Emu/RSX/RSXVertexProgram.h index e7b103a688..328c617a30 100644 --- a/rpcs3/Emu/RSX/RSXVertexProgram.h +++ b/rpcs3/Emu/RSX/RSXVertexProgram.h @@ -1,5 +1,195 @@ #pragma once +enum sca_opcode +{ + RSX_SCA_OPCODE_NOP = 0x00, + RSX_SCA_OPCODE_MOV = 0x01, + RSX_SCA_OPCODE_RCP = 0x02, + RSX_SCA_OPCODE_RCC = 0x03, + RSX_SCA_OPCODE_RSQ = 0x04, + RSX_SCA_OPCODE_EXP = 0x05, + RSX_SCA_OPCODE_LOG = 0x06, + RSX_SCA_OPCODE_LIT = 0x07, + RSX_SCA_OPCODE_BRA = 0x08, + RSX_SCA_OPCODE_BRI = 0x09, + RSX_SCA_OPCODE_CAL = 0x0a, + RSX_SCA_OPCODE_CLI = 0x0b, + RSX_SCA_OPCODE_RET = 0x0c, + RSX_SCA_OPCODE_LG2 = 0x0d, + RSX_SCA_OPCODE_EX2 = 0x0e, + RSX_SCA_OPCODE_SIN = 0x0f, + RSX_SCA_OPCODE_COS = 0x10, + RSX_SCA_OPCODE_BRB = 0x11, + RSX_SCA_OPCODE_CLB = 0x12, + RSX_SCA_OPCODE_PSH = 0x13, + RSX_SCA_OPCODE_POP = 0x14 +}; + +enum vec_opcode +{ + RSX_VEC_OPCODE_NOP = 0x00, + RSX_VEC_OPCODE_MOV = 0x01, + RSX_VEC_OPCODE_MUL = 0x02, + RSX_VEC_OPCODE_ADD = 0x03, + RSX_VEC_OPCODE_MAD = 0x04, + RSX_VEC_OPCODE_DP3 = 0x05, + RSX_VEC_OPCODE_DPH = 0x06, + RSX_VEC_OPCODE_DP4 = 0x07, + RSX_VEC_OPCODE_DST = 0x08, + RSX_VEC_OPCODE_MIN = 0x09, + RSX_VEC_OPCODE_MAX = 0x0a, + RSX_VEC_OPCODE_SLT = 0x0b, + RSX_VEC_OPCODE_SGE = 0x0c, + RSX_VEC_OPCODE_ARL = 0x0d, + RSX_VEC_OPCODE_FRC = 0x0e, + RSX_VEC_OPCODE_FLR = 0x0f, + RSX_VEC_OPCODE_SEQ = 0x10, + RSX_VEC_OPCODE_SFL = 0x11, + RSX_VEC_OPCODE_SGT = 0x12, + RSX_VEC_OPCODE_SLE = 0x13, + RSX_VEC_OPCODE_SNE = 0x14, + RSX_VEC_OPCODE_STR = 0x15, + RSX_VEC_OPCODE_SSG = 0x16, + RSX_VEC_OPCODE_TEX = 0x19 +}; + +static union D0 +{ + u32 HEX; + + struct + { + u32 addr_swz : 2; + u32 mask_w : 2; + u32 mask_z : 2; + u32 mask_y : 2; + u32 mask_x : 2; + u32 cond : 3; + u32 cond_test_enable : 1; + u32 cond_update_enable_0 : 1; + u32 dst_tmp : 6; + u32 src0_abs : 1; + u32 src1_abs : 1; + u32 src2_abs : 1; + u32 addr_reg_sel_1 : 1; + u32 cond_reg_sel_1 : 1; + u32 staturate : 1; + u32 index_input : 1; + u32 : 1; + u32 cond_update_enable_1 : 1; + u32 vec_result : 1; + u32 : 1; + }; +} d0; + +static union D1 +{ + u32 HEX; + + struct + { + u32 src0h : 8; + u32 input_src : 4; + u32 const_src : 10; + u32 vec_opcode : 5; + u32 sca_opcode : 5; + }; +} d1; + +static union D2 +{ + u32 HEX; + + struct + { + u32 src2h : 6; + u32 src1 : 17; + u32 src0l : 9; + }; + struct + { + u32 iaddrh : 6; + u32 : 26; + }; +} d2; + +static union D3 +{ + u32 HEX; + + struct + { + u32 end : 1; + u32 index_const : 1; + u32 dst : 5; + u32 sca_dst_tmp : 6; + u32 vec_writemask_w : 1; + u32 vec_writemask_z : 1; + u32 vec_writemask_y : 1; + u32 vec_writemask_x : 1; + u32 sca_writemask_w : 1; + u32 sca_writemask_z : 1; + u32 sca_writemask_y : 1; + u32 sca_writemask_x : 1; + u32 src2l : 11; + }; + struct + { + u32 : 29; + u32 iaddrl : 3; + }; +} d3; + +static union SRC +{ + union + { + u32 HEX; + + struct + { + u32 src0l : 9; + u32 src0h : 8; + }; + + struct + { + u32 src1 : 17; + }; + + struct + { + u32 src2l : 11; + u32 src2h : 6; + }; + }; + + struct + { + u32 reg_type : 2; + u32 tmp_src : 6; + u32 swz_w : 2; + u32 swz_z : 2; + u32 swz_y : 2; + u32 swz_x : 2; + u32 neg : 1; + }; +} src[3]; + +static const std::string rsx_vp_sca_op_names[] = +{ + "NOP", "MOV", "RCP", "RCC", "RSQ", "EXP", "LOG", + "LIT", "BRA", "BRI", "CAL", "CLI", "RET", "LG2", + "EX2", "SIN", "COS", "BRB", "CLB", "PSH", "POP" +}; + +static const std::string rsx_vp_vec_op_names[] = +{ + "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DPH", "DP4", + "DST", "MIN", "MAX", "SLT", "SGE", "ARL", "FRC", "FLR", + "SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", "TEX" +}; + struct RSXVertexProgram { std::vector data; diff --git a/rpcs3/Gui/CgDisasm.cpp b/rpcs3/Gui/CgDisasm.cpp new file mode 100644 index 0000000000..c56da842e8 --- /dev/null +++ b/rpcs3/Gui/CgDisasm.cpp @@ -0,0 +1,58 @@ +#include "stdafx_gui.h" + +#include "CgDisasm.h" +#include "Emu/System.h" +#include "Emu/RSX/CgBinaryProgram.h" + +BEGIN_EVENT_TABLE(CgDisasm, wxFrame) + EVT_SIZE(CgDisasm::OnSize) +END_EVENT_TABLE() + +CgDisasm::CgDisasm(wxWindow* parent) + : wxFrame(parent, wxID_ANY, "Cg Disasm", wxDefaultPosition, wxSize(640, 480)) +{ + wxMenuBar* menubar = new wxMenuBar(); + + wxMenu* menu_general = new wxMenu(); + menubar->Append(menu_general, "&Open"); + menu_general->Append(id_open_file, "Open &Cg binary program"); + + wxNotebook* nb_cg = new wxNotebook(this, wxID_ANY); + wxPanel* p_cg_disasm = new wxPanel(nb_cg, wxID_ANY); + wxPanel* p_glsl_shader = new wxPanel(nb_cg, wxID_ANY); + + nb_cg->AddPage(p_cg_disasm, wxT("ASM")); + nb_cg->AddPage(p_glsl_shader, wxT("GLSL")); + + m_disasm_text = new wxTextCtrl(p_cg_disasm, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(620, 395), wxTE_MULTILINE | wxNO_BORDER | wxTE_READONLY | wxTE_RICH2); + m_glsl_text = new wxTextCtrl(p_glsl_shader, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(620, 395), wxTE_MULTILINE | wxNO_BORDER | wxTE_READONLY | wxTE_RICH2); + + SetMenuBar(menubar); + + Bind(wxEVT_MENU, &CgDisasm::OpenCg, this, id_open_file); +} + +void CgDisasm::OpenCg(wxCommandEvent& event) +{ + wxFileDialog ctrl(this, L"Select Cg program object", wxEmptyString, wxEmptyString, + "Cg program objects (*.fpo;*.vpo)|*.fpo;*.vpo" + "|All files (*.*)|*.*", + wxFD_OPEN | wxFD_FILE_MUST_EXIST); + + if (ctrl.ShowModal() == wxID_CANCEL) + { + return; + } + + CgBinaryDisasm disasm(fmt::ToUTF8(ctrl.GetPath())); + disasm.BuildShaderBody(); + *m_disasm_text << disasm.GetArbShader(); + *m_glsl_text << disasm.GetGlslShader(); +} + +void CgDisasm::OnSize(wxSizeEvent& event) +{ + m_disasm_text->SetSize(GetSize().x - 20, GetSize().y - 85); + m_glsl_text->SetSize(GetSize().x - 20, GetSize().y - 85); + event.Skip(); +} diff --git a/rpcs3/Gui/CgDisasm.h b/rpcs3/Gui/CgDisasm.h new file mode 100644 index 0000000000..85f7f92dce --- /dev/null +++ b/rpcs3/Gui/CgDisasm.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +enum CgDisasmIds +{ + id_open_file +}; + +class CgDisasm : public wxFrame +{ +private: + wxTextCtrl* m_disasm_text; + wxTextCtrl* m_glsl_text; + DECLARE_EVENT_TABLE(); + +public: + CgDisasm(wxWindow* parent); + + void OpenCg(wxCommandEvent& event); + virtual void OnSize(wxSizeEvent& event); +}; \ No newline at end of file diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 21de6c9d81..6ba54a475e 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -22,6 +22,7 @@ #include "Gui/RSXDebugger.h" #include "Gui/MemoryStringSearcher.h" #include "Gui/LLEModulesManager.h" +#include "Gui/CgDisasm.h" #include @@ -53,8 +54,9 @@ enum IDs id_tools_memory_viewer, id_tools_rsx_debugger, id_tools_string_search, + id_tools_cg_disasm, id_help_about, - id_update_dbg, + id_update_dbg }; wxString GetPaneName() @@ -111,6 +113,7 @@ MainFrame::MainFrame() menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false); menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false); menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false); + menu_tools->Append(id_tools_cg_disasm, "&Cg Disasm")->Enable(); wxMenu* menu_help = new wxMenu(); menubar->Append(menu_help, "&Help"); @@ -151,6 +154,7 @@ MainFrame::MainFrame() Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer); Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger); Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search); + Bind(wxEVT_MENU, &MainFrame::OpenCgDisasm, this, id_tools_cg_disasm); Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about); @@ -722,6 +726,11 @@ void MainFrame::OpenStringSearch(wxCommandEvent& WXUNUSED(event)) (new MemoryStringSearcher(this)) -> Show(); } +void MainFrame::OpenCgDisasm(wxCommandEvent& WXUNUSED(event)) +{ + (new CgDisasm(this))->Show(); +} + void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event)) { AboutDialog(this).ShowModal(); diff --git a/rpcs3/Gui/MainFrame.h b/rpcs3/Gui/MainFrame.h index 3de2d38e6a..9477e082a2 100644 --- a/rpcs3/Gui/MainFrame.h +++ b/rpcs3/Gui/MainFrame.h @@ -46,7 +46,7 @@ private: void OpenMemoryViewer(wxCommandEvent& evt); void OpenRSXDebugger(wxCommandEvent& evt); void OpenStringSearch(wxCommandEvent& evt); - void OpenFnIdGenerator(wxCommandEvent& evt); + void OpenCgDisasm(wxCommandEvent& evt); void AboutDialogHandler(wxCommandEvent& event); void UpdateUI(wxCommandEvent& event); void OnKeyDown(wxKeyEvent& event); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 48916379d3..eb0c24f4e0 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -37,6 +37,7 @@ + @@ -409,6 +410,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 3c7c2797cc..90c6dd6572 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -854,6 +854,9 @@ Emu\CPU\ARMv7\Objects + + Emu\GPU\RSX + @@ -1519,5 +1522,8 @@ Emu\CPU\ARMv7\Objects + + Emu\GPU\RSX + \ No newline at end of file diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 4f2bc92078..c13b8465e1 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -43,163 +43,6 @@ Rpcs3App* TheApp; std::string simplify_path(const std::string& path, bool is_dir); -typedef be_t CGprofile; -typedef int CGbool; -typedef be_t CGresource; -typedef be_t CGenum; -typedef be_t CGtype; - -typedef be_t CgBinaryOffset; -typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset; -typedef CgBinaryOffset CgBinaryFloatOffset; -typedef CgBinaryOffset CgBinaryStringOffset; -typedef CgBinaryOffset CgBinaryParameterOffset; - -// a few typedefs -typedef struct CgBinaryParameter CgBinaryParameter; -typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant; -typedef struct CgBinaryVertexProgram CgBinaryVertexProgram; -typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram; -typedef struct CgBinaryProgram CgBinaryProgram; - -// fragment programs have their constants embedded in the microcode -struct CgBinaryEmbeddedConstant -{ - be_t ucodeCount; // occurances - be_t ucodeOffset[1]; // offsets that need to be patched follow -}; - -// describe a binary program parameter (CgParameter is opaque) -struct CgBinaryParameter -{ - CGtype type; // cgGetParameterType() - CGresource res; // cgGetParameterResource() - CGenum var; // cgGetParameterVariability() - be_t resIndex; // cgGetParameterResourceIndex() - CgBinaryStringOffset name; // cgGetParameterName() - CgBinaryFloatOffset defaultValue; // default constant value - CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information - CgBinaryStringOffset semantic; // cgGetParameterSemantic() - CGenum direction; // cgGetParameterDirection() - be_t paramno; // 0..n: cgGetParameterIndex() -1: globals - CGbool isReferenced; // cgIsParameterReferenced() - CGbool isShared; // cgIsParameterShared() -}; - -// attributes needed for vshaders -struct CgBinaryVertexProgram -{ - be_t instructionCount; // #instructions - be_t instructionSlot; // load address (indexed reads!) - be_t registerCount; // R registers count - be_t attributeInputMask; // attributes vs reads from - be_t attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) - be_t userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL) -}; - -typedef enum { - CgBinaryPTTNone = 0, - CgBinaryPTT2x16 = 1, - CgBinaryPTT1x32 = 2, -} CgBinaryPartialTexType; - -// attributes needed for pshaders -struct CgBinaryFragmentProgram -{ - be_t instructionCount; // #instructions - be_t attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) - be_t partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType - be_t texCoordsInputMask; // tex coords used by frag prog. (tex is bit n) - be_t texCoords2D; // tex coords that are 2d (tex is bit n) - be_t texCoordsCentroid; // tex coords that are centroid (tex is bit n) - unsigned char registerCount; // R registers count - unsigned char outputFromH0; // final color from R0 or H0 - unsigned char depthReplace; // fp generated z epth value - unsigned char pixelKill; // fp uses kill operations -}; - -#include "Emu/RSX/GL/GLFragmentProgram.h" -#include "Emu/RSX/GL/GLVertexProgram.h" -// defines a binary program -- *all* address/offsets are relative to the begining of CgBinaryProgram -struct CgBinaryProgram -{ - // vertex/pixel shader identification (BE/LE as well) - CGprofile profile; - - // binary revision (used to verify binary and driver structs match) - be_t binaryFormatRevision; - - // total size of this struct including profile and totalSize field! - be_t totalSize; - - // parameter usually queried using cgGet[First/Next]LeafParameter - be_t parameterCount; - CgBinaryParameterOffset parameterArray; - - // depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct - CgBinaryOffset program; - - // raw ucode data - be_t ucodeSize; - CgBinaryOffset ucode; - - // variable length data follows - unsigned char data[1]; -}; - -void compile_shader(std::string path) -{ - ShaderVar var("r0.yz.x"); - var.symplify(); - LOG_ERROR(GENERAL, var.get().c_str()); - - u32 ptr; - { - wxFile f(path); - - if (!f.IsOpened()) - return; - - size_t size = f.Length(); - vm::ps3::init(); - ptr = vm::alloc(size); - f.Read(vm::get_ptr(ptr), size); - f.Close(); - } - - CgBinaryProgram& prog = vm::get_ref(ptr); - LOG_ERROR(GENERAL, "%d - 0x%x", (u32)prog.profile, (u32)prog.binaryFormatRevision); - - std::string shader; - GLParamArray param_array; - u32 size; - - if (prog.profile == 7004) - { - CgBinaryFragmentProgram& fprog = vm::get_ref(ptr + prog.program); - - u32 ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); - - GLFragmentDecompilerThread(shader, param_array, ptr + prog.ucode, size, ctrl).Task(); - } - else - { - CgBinaryVertexProgram& vprog = vm::get_ref(ptr + prog.program); - - std::vector data; - be_t* vdata = vm::get_ptr>(ptr + prog.ucode); - for (u32 i = 0; i < prog.ucodeSize; ++i, ++vdata) - { - data.push_back(vdata[i]); - } - - GLVertexDecompilerThread(data, shader, param_array).Task(); - } - - LOG_ERROR(GENERAL, shader.c_str()); - vm::close(); -} - bool Rpcs3App::OnInit() { static const wxCmdLineEntryDesc desc[] @@ -314,9 +157,6 @@ bool Rpcs3App::OnInit() OnArguments(parser); - //compile_shader("compile_shader0.spo"); - //compile_shader("compile_shader1.spo"); - return true; } diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index ade3c6121a..5ec09d62b6 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -166,6 +166,7 @@ + @@ -205,6 +206,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index e55464ae48..30a242bf1a 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -96,6 +96,9 @@ Gui + + Gui + @@ -194,8 +197,8 @@ Gui - + Gui - + \ No newline at end of file From 8d383ea15c818356207ad0191fde2ef3d8f2ea32 Mon Sep 17 00:00:00 2001 From: O1L Date: Sun, 22 Feb 2015 19:47:44 +0400 Subject: [PATCH 2/3] Oops --- rpcs3/rpcs3.vcxproj.filters | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 30a242bf1a..82eaf2b9ea 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -200,5 +200,8 @@ Gui + + Gui + \ No newline at end of file From deebe3ca1fb4fc9d816010946ecd16f8e4b907e2 Mon Sep 17 00:00:00 2001 From: O1L Date: Sun, 22 Feb 2015 22:53:26 +0400 Subject: [PATCH 3/3] Used fmt::Format instead of sprintf --- rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp index 2729d1758f..979cb9df1c 100644 --- a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp @@ -73,10 +73,7 @@ std::string CgBinaryDisasm::AddConstDisAsm() const u32 z = GetData(data[2]); const u32 w = GetData(data[3]); - char buf[1024]; - sprintf(buf, "{0x%08x(%g), 0x%08x(%g), 0x%08x(%g), 0x%08x(%g)}", x, (float&)x, y, (float&)y, z, (float&)z, w, (float&)w); - - return fmt::format(buf); + return fmt::Format("{0x%08x(%g), 0x%08x(%g), 0x%08x(%g), 0x%08x(%g)}", x, (float&)x, y, (float&)y, z, (float&)z, w, (float&)w); } std::string CgBinaryDisasm::AddTexDisAsm()