diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 945154ba00..d54dc1af49 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -8,6 +8,8 @@ #include #include #include +#include "VertexProgramDecompiler.h" +#include "Utilities/File.h" #pragma comment (lib, "d3dcompiler.lib") @@ -116,12 +118,13 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState( if (!m_vp_buf_num) { LOG_WARNING(RSX, "VP not found in buffer!"); - // m_vertex_prog.Decompile(*vertexShader); + VertexDecompiler VS(vertexShader->data); + VS.Decompile(); m_vertex_prog.Compile(SHADER_TYPE::SHADER_TYPE_VERTEX); AddVertexProgram(m_vertex_prog, *vertexShader); // TODO: This shouldn't use current dir -// fs::file("./VertexProgram.txt", o_write | o_create | o_trunc).write(m_vertex_prog.shader.c_str(), m_vertex_prog.shader.size()); + fs::file("./VertexProgram.txt", o_write | o_create | o_trunc).write(VS.m_shader.c_str(), VS.m_shader.size()); } if (m_fp_buf_num && m_vp_buf_num) diff --git a/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.cpp new file mode 100644 index 0000000000..dd0056cdb7 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.cpp @@ -0,0 +1,782 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "VertexProgramDecompiler.h" + +#include "Utilities/Log.h" +#include "Emu/System.h" + + +std::string VertexDecompiler::GetMask(bool is_sca) +{ + std::string ret; + + if (is_sca) + { + if (d3.sca_writemask_x) ret += "x"; + if (d3.sca_writemask_y) ret += "y"; + if (d3.sca_writemask_z) ret += "z"; + if (d3.sca_writemask_w) ret += "w"; + } + else + { + if (d3.vec_writemask_x) ret += "x"; + if (d3.vec_writemask_y) ret += "y"; + if (d3.vec_writemask_z) ret += "z"; + if (d3.vec_writemask_w) ret += "w"; + } + + return ret.empty() || ret == "xyzw" ? "" : ("." + ret); +} + +std::string VertexDecompiler::GetVecMask() +{ + return GetMask(false); +} + +std::string VertexDecompiler::GetScaMask() +{ + return GetMask(true); +} + +std::string VertexDecompiler::GetDST(bool isSca) +{ + std::string ret; + + switch (isSca ? 0x1f : d3.dst) + { + case 0x1f: + ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp)); + break; + + default: + if (d3.dst > 15) + LOG_ERROR(RSX, fmt::Format("dst index out of range: %u", d3.dst)); + ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)"); + break; + } + + return ret; +} + +std::string VertexDecompiler::GetSRC(const u32 n) +{ + static const std::string reg_table[] = + { + "in_pos", "in_weight", "in_normal", + "in_diff_color", "in_spec_color", + "in_fog", + "in_point_size", "in_7", + "in_tc0", "in_tc1", "in_tc2", "in_tc3", + "in_tc4", "in_tc5", "in_tc6", "in_tc7" + }; + + std::string ret; + + switch (src[n].reg_type) + { + case 1: //temp + ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src)); + break; + case 2: //input + if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0]))) + { + ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src); + } + else + { + LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src)); + ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src); + } + break; + case 3: //const + m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]")); + ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]"; + break; + + default: + LOG_ERROR(RSX, fmt::Format("Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type))); + Emu.Pause(); + break; + } + + static const std::string f = "xyzw"; + + std::string swizzle; + + swizzle += f[src[n].swz_x]; + swizzle += f[src[n].swz_y]; + swizzle += f[src[n].swz_z]; + swizzle += f[src[n].swz_w]; + + if (swizzle != f) ret += '.' + swizzle; + + bool abs; + + switch (n) + { + case 0: abs = d0.src0_abs; break; + case 1: abs = d0.src1_abs; break; + case 2: abs = d0.src2_abs; break; + } + + if (abs) ret = "abs(" + ret + ")"; + if (src[n].neg) ret = "-" + ret; + + return ret; +} + +void VertexDecompiler::SetDST(bool is_sca, std::string value) +{ + if (d0.cond == 0) return; + + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + }; + + std::string mask = GetMask(is_sca); + + value += mask; + + if (is_sca && d0.vec_result) + { + //value = "vec4(" + value + ")"; + } + + if (d0.staturate) + { + value = "clamp(" + value + ", 0.0, 1.0)"; + } + + std::string dest; + + if (d0.cond_update_enable_0 && d0.cond_update_enable_1) + { + dest = m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask; + } + else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) + { + dest = GetDST(is_sca) + mask; + } + + //std::string code; + //if (d0.cond_test_enable) + // code += "$ifcond "; + //code += dest + value; + //AddCode(code + ";"); + + AddCodeCond(Format(dest), value); +} + +std::string VertexDecompiler::GetFunc() +{ + std::string name = "func$a"; + + for (const auto& func : m_funcs) { + if (func.name.compare(name) == 0) { + return name + "()"; + } + } + + m_funcs.emplace_back(); + FuncInfo &idx = m_funcs.back(); + idx.offset = GetAddr(); + idx.name = name; + + return name + "()"; +} + +std::string VertexDecompiler::GetTex() +{ + return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0)); +} + +std::string VertexDecompiler::Format(const std::string& code) +{ + const std::pair> repl_list[] = + { + { "$$", []() -> std::string { return "$"; } }, + { "$0", std::bind(std::mem_fn(&VertexDecompiler::GetSRC), this, 0) }, + { "$1", std::bind(std::mem_fn(&VertexDecompiler::GetSRC), this, 1) }, + { "$2", std::bind(std::mem_fn(&VertexDecompiler::GetSRC), this, 2) }, + { "$s", std::bind(std::mem_fn(&VertexDecompiler::GetSRC), this, 2) }, + { "$am", std::bind(std::mem_fn(&VertexDecompiler::AddAddrMask), this) }, + { "$a", std::bind(std::mem_fn(&VertexDecompiler::AddAddrReg), this) }, + + { "$t", std::bind(std::mem_fn(&VertexDecompiler::GetTex), this) }, + + { "$fa", [this]()->std::string { return std::to_string(GetAddr()); } }, + { "$f()", std::bind(std::mem_fn(&VertexDecompiler::GetFunc), this) }, + { "$ifcond ", [this]() -> std::string + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } + }, + { "$cond", std::bind(std::mem_fn(&VertexDecompiler::GetCond), this) } + }; + + return fmt::replace_all(code, repl_list); +} + +std::string VertexDecompiler::GetCond() +{ + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + }; + + if (d0.cond == 0) return "false"; + if (d0.cond == (lt | gt | eq)) return "true"; + + static const char* cond_string_table[(lt | gt | eq) + 1] = + { + "error", + "lessThan", + "equal", + "lessThanEqual", + "greaterThan", + "notEqual", + "greaterThanEqual", + "error" + }; + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle; + swizzle += f[d0.mask_x]; + swizzle += f[d0.mask_y]; + swizzle += f[d0.mask_z]; + swizzle += f[d0.mask_w]; + + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str()); +} + +void VertexDecompiler::AddCodeCond(const std::string& dst, const std::string& src) +{ + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + }; + + + if (!d0.cond_test_enable || d0.cond == (lt | gt | eq)) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (d0.cond == 0) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + static const char* cond_string_table[(lt | gt | eq) + 1] = + { + "error", + "lessThan", + "equal", + "lessThanEqual", + "greaterThan", + "notEqual", + "greaterThanEqual", + "error" + }; + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle; + swizzle += f[d0.mask_x]; + swizzle += f[d0.mask_y]; + swizzle += f[d0.mask_z]; + swizzle += f[d0.mask_w]; + + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str()); + + ShaderVar dst_var(dst); + dst_var.symplify(); + + //const char *c_mask = f; + + if (dst_var.swizzles[0].length() == 1) + { + AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); + } + else + { + for (int i = 0; i < dst_var.swizzles[0].length(); ++i) + { + AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); + } + } +} + + +std::string VertexDecompiler::AddAddrMask() +{ + static const char f[] = { 'x', 'y', 'z', 'w' }; + return std::string(".") + f[d0.addr_swz]; +} + +std::string VertexDecompiler::AddAddrReg() +{ + static const char f[] = { 'x', 'y', 'z', 'w' }; + return m_parr.AddParam(PARAM_NONE, "ivec4", "a" + std::to_string(d0.addr_reg_sel_1), "ivec4(0)") + AddAddrMask(); +} + +u32 VertexDecompiler::GetAddr() +{ + return (d2.iaddrh << 3) | d3.iaddrl; +} + +void VertexDecompiler::AddCode(const std::string& code) +{ + m_body.push_back(Format(code) + ";"); + m_cur_instr->body.push_back(Format(code)); +} + +void VertexDecompiler::SetDSTVec(const std::string& code) +{ + SetDST(false, code); +} + +void VertexDecompiler::SetDSTSca(const std::string& code) +{ + SetDST(true, code); +} + +std::string VertexDecompiler::BuildFuncBody(const FuncInfo& func) +{ + std::string result; + + for (uint i = func.offset; i 0; --i) + { + fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str()); + } + + f = fmt::Format("void %s()\n{\n\t%s();\n%s\tgl_Position = gl_Position * scaleOffsetMat;\n}\n", + m_funcs[0].name.c_str(), m_funcs[1].name.c_str(), f.c_str()); + + std::string main_body; + for (uint i = 0, lvl = 1; i < m_instr_count; i++) + { + lvl -= m_instructions[i].close_scopes; + if (lvl < 1) lvl = 1; + //assert(lvl >= 1); + for (uint j = 0; j < m_instructions[i].put_close_scopes; ++j) + { + --lvl; + if (lvl < 1) lvl = 1; + main_body.append(lvl, '\t') += "}\n"; + } + + for (uint j = 0; j < m_instructions[i].do_count; ++j) + { + main_body.append(lvl, '\t') += "do\n"; + main_body.append(lvl, '\t') += "{\n"; + lvl++; + } + + for (uint j = 0; j < m_instructions[i].body.size(); ++j) + { + main_body.append(lvl, '\t') += m_instructions[i].body[j] + "\n"; + } + + lvl += m_instructions[i].open_scopes; + } + + f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str()); + + for (uint i = 2; i& data) : + m_data(data) +{ + m_funcs.emplace_back(); + m_funcs[0].offset = 0; + m_funcs[0].name = "main"; + m_funcs.emplace_back(); + m_funcs[1].offset = 0; + m_funcs[1].name = "func0"; + //m_cur_func->body = "\tgl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n"; +} + +void VertexDecompiler::Decompile() +{ + m_parr.params.clear(); + m_instr_count = 0; + + for (int i = 0; i < m_max_instr_count; ++i) + { + m_instructions[i].reset(); + } + + bool is_has_BRA = false; + + for (u32 i = 1; m_instr_count < m_max_instr_count; m_instr_count++) + { + m_cur_instr = &m_instructions[m_instr_count]; + + if (is_has_BRA) + { + d3.HEX = m_data[i]; + i += 4; + } + else + { + d1.HEX = m_data[i++]; + + switch (d1.sca_opcode) + { + case 0x08: //BRA + LOG_ERROR(RSX, "BRA found. Please report to RPCS3 team."); + is_has_BRA = true; + m_jump_lvls.clear(); + d3.HEX = m_data[++i]; + i += 4; + break; + + case 0x09: //BRI + d2.HEX = m_data[i++]; + d3.HEX = m_data[i]; + i += 2; + m_jump_lvls.emplace(GetAddr()); + break; + + default: + d3.HEX = m_data[++i]; + i += 2; + break; + } + } + + if (d3.end) + { + m_instr_count++; + + if (i < m_data.size()) + { + LOG_ERROR(RSX, "Program end before buffer end."); + } + + break; + } + } + + uint jump_position = 0; + + if (is_has_BRA || !m_jump_lvls.empty()) + { + m_cur_instr = &m_instructions[0]; + AddCode("int jump_position = 0;"); + AddCode("while (true)"); + AddCode("{"); + m_cur_instr->open_scopes++; + + AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); + AddCode("{"); + m_cur_instr->open_scopes++; + } + + for (u32 i = 0; i < m_instr_count; ++i) + { + m_cur_instr = &m_instructions[i]; + + d0.HEX = m_data[i * 4 + 0]; + d1.HEX = m_data[i * 4 + 1]; + d2.HEX = m_data[i * 4 + 2]; + d3.HEX = m_data[i * 4 + 3]; + + src[0].src0l = d2.src0l; + src[0].src0h = d1.src0h; + src[1].src1 = d2.src1; + src[2].src2l = d3.src2l; + src[2].src2h = d2.src2h; + + if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end())) + { + m_cur_instr->close_scopes++; + AddCode("}"); + AddCode(""); + + AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); + AddCode("{"); + m_cur_instr->open_scopes++; + } + + if (!d1.sca_opcode && !d1.vec_opcode) + { + AddCode("//nop"); + } + + switch (d1.sca_opcode) + { + case RSX_SCA_OPCODE_NOP: break; + case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break; + case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break; + case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; + case RSX_SCA_OPCODE_RSQ: SetDSTSca("inversesqrt(abs($s))"); break; + case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break; + case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break; + case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break; + case RSX_SCA_OPCODE_BRA: + { + AddCode("$if ($cond)"); + AddCode("{"); + m_cur_instr->open_scopes++; + AddCode("jump_position = $a$am;"); + AddCode("continue;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } + break; + /* This triggers opengl driver lost connection error code 7 + case RSX_SCA_OPCODE_BRI: // works differently (BRI o[1].x(TR) L0;) + { + uint jump_position; + + if (is_has_BRA) + { + jump_position = GetAddr(); + } + else + { + int addr = GetAddr(); + + jump_position = 0; + for (auto pos : m_jump_lvls) + { + if (addr == pos) + break; + + ++jump_position; + } + } + + AddCode("$ifcond "); + AddCode("{"); + m_cur_instr->open_scopes++; + AddCode(fmt::Format("jump_position = %u;", jump_position)); + AddCode("continue;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } + break; + */ + case RSX_SCA_OPCODE_CAL: + // works same as BRI + AddCode("$ifcond $f(); //CAL"); + break; + case RSX_SCA_OPCODE_CLI: + // works same as BRI + AddCode("$ifcond $f(); //CLI"); + break; + case RSX_SCA_OPCODE_RET: + // works like BRI but shorter (RET o[1].x(TR);) + AddCode("$ifcond return;"); + break; + case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break; + case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break; + case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break; + case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break; + case RSX_SCA_OPCODE_BRB: + // works differently (BRB o[1].x !b0, L0;) + LOG_ERROR(RSX, "Unimplemented sca_opcode BRB"); + break; + case RSX_SCA_OPCODE_CLB: break; + // works same as BRB + LOG_ERROR(RSX, "Unimplemented sca_opcode CLB"); + break; + case RSX_SCA_OPCODE_PSH: break; + // works differently (PSH o[1].x A0;) + LOG_ERROR(RSX, "Unimplemented sca_opcode PSH"); + break; + case RSX_SCA_OPCODE_POP: break; + // works differently (POP o[1].x;) + LOG_ERROR(RSX, "Unimplemented sca_opcode POP"); + break; + + default: + AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode))); + LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)); + Emu.Pause(); + break; + } + + switch (d1.vec_opcode) + { + case RSX_VEC_OPCODE_NOP: break; + case RSX_VEC_OPCODE_MOV: SetDSTVec("$0"); break; + case RSX_VEC_OPCODE_MUL: SetDSTVec("($0 * $1)"); break; + case RSX_VEC_OPCODE_ADD: SetDSTVec("($0 + $2)"); break; + case RSX_VEC_OPCODE_MAD: SetDSTVec("($0 * $1 + $2)"); break; + case RSX_VEC_OPCODE_DP3: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_VEC_OPCODE_DPH: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; + case RSX_VEC_OPCODE_DP4: SetDSTVec("vec4(dot($0, $1))"); break; + case RSX_VEC_OPCODE_DST: SetDSTVec("vec4(distance($0, $1))"); break; + case RSX_VEC_OPCODE_MIN: SetDSTVec("min($0, $1)"); break; + case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break; + case RSX_VEC_OPCODE_SLT: SetDSTVec("vec4(lessThan($0, $1))"); break; + case RSX_VEC_OPCODE_SGE: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; + case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $a = ivec4($0)$am;"); break; + case RSX_VEC_OPCODE_FRC: SetDSTVec("fract($0)"); break; + case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break; + case RSX_VEC_OPCODE_SEQ: SetDSTVec("vec4(equal($0, $1))"); break; + case RSX_VEC_OPCODE_SFL: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; + case RSX_VEC_OPCODE_SGT: SetDSTVec("vec4(greaterThan($0, $1))"); break; + case RSX_VEC_OPCODE_SLE: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; + case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break; + case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; + case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break; + case RSX_VEC_OPCODE_TXL: SetDSTVec("texture($t, $0.xy)"); break; + + default: + AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); + LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)); + Emu.Pause(); + break; + } + } + + if (is_has_BRA || !m_jump_lvls.empty()) + { + m_cur_instr = &m_instructions[m_instr_count - 1]; + m_cur_instr->close_scopes++; + AddCode("}"); + AddCode("break;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } + + m_shader = BuildCode(); + + m_jump_lvls.clear(); + m_body.clear(); + if (m_funcs.size() > 2) + { + m_funcs.erase(m_funcs.begin() + 2, m_funcs.end()); + } +} + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.h b/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.h new file mode 100644 index 0000000000..2b9c9a02a9 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/VertexProgramDecompiler.h @@ -0,0 +1,296 @@ +#pragma once +#if defined(DX12_SUPPORT) +#include "Emu/RSX/RSXVertexProgram.h" +#include +#include + +enum ParamFlag +{ + PARAM_IN, + PARAM_OUT, + PARAM_UNIFORM, + PARAM_CONST, + PARAM_NONE, +}; + +struct GLParamItem +{ + std::string name; + std::string location; + std::string value; + + GLParamItem(const std::string& _name, int _location, const std::string& _value = "") + : name(_name) + , value(_value) + { + if (_location > -1) + location = "layout (location = " + std::to_string(_location) + ") "; + else + location = ""; + } +}; + +struct ParamType +{ + const ParamFlag flag; + std::string type; + std::vector items; + + ParamType(const ParamFlag _flag, const std::string& _type) + : flag(_flag) + , type(_type) + { + } + + bool SearchName(const std::string& name) + { + for (u32 i = 0; i params; + + ParamType* SearchParam(const std::string& type) + { + for (u32 i = 0; iSearchName(name); + } + + std::string AddParam(const ParamFlag flag, std::string type, const std::string& name, const std::string& value) + { + type = GetParamFlag(flag) + type; + ParamType* t = SearchParam(type); + + if (t) + { + if (!t->SearchName(name)) t->items.emplace_back(name, -1, value); + } + else + { + const u32 num = params.size(); + params.emplace_back(flag, type); + params[num].items.emplace_back(name, -1, value); + } + + return name; + } + + std::string AddParam(const ParamFlag flag, std::string type, const std::string& name, int location = -1) + { + type = GetParamFlag(flag) + type; + ParamType* t = SearchParam(type); + + if (t) + { + if (!t->SearchName(name)) t->items.emplace_back(name, location); + } + else + { + const u32 num = params.size(); + params.emplace_back(flag, type); + params[num].items.emplace_back(name, location); + } + + return name; + } +}; + +class ShaderVar +{ +public: + std::string name; + std::vector swizzles; + + ShaderVar() = default; + ShaderVar(const std::string& var) + { + auto var_blocks = fmt::split(var, { "." }); + + if (var_blocks.size() == 0) + { + assert(0); + } + + name = var_blocks[0]; + + if (var_blocks.size() == 1) + { + swizzles.push_back("xyzw"); + } + else + { + swizzles = std::vector(var_blocks.begin() + 1, var_blocks.end()); + } + } + + int get_vector_size() const + { + return swizzles[swizzles.size() - 1].length(); + } + + ShaderVar& symplify() + { + std::unordered_map swizzle; + + static std::unordered_map pos_to_swizzle = + { + { 0, 'x' }, + { 1, 'y' }, + { 2, 'z' }, + { 3, 'w' } + }; + + for (auto &i : pos_to_swizzle) + { + swizzle[i.second] = swizzles[0].length() > i.first ? swizzles[0][i.first] : 0; + } + + for (int i = 1; i < swizzles.size(); ++i) + { + std::unordered_map new_swizzle; + + for (auto &sw : pos_to_swizzle) + { + new_swizzle[sw.second] = swizzle[swizzles[i].length() <= sw.first ? '\0' : swizzles[i][sw.first]]; + } + + swizzle = new_swizzle; + } + + swizzles.clear(); + std::string new_swizzle; + + for (auto &i : pos_to_swizzle) + { + if (swizzle[i.second] != '\0') + new_swizzle += swizzle[i.second]; + } + + swizzles.push_back(new_swizzle); + + return *this; + } + + std::string get() const + { + if (swizzles.size() == 1 && swizzles[0] == "xyzw") + { + return name; + } + + return name + "." + fmt::merge({ swizzles }, "."); + } +}; + +struct VertexDecompiler +{ + struct FuncInfo + { + u32 offset; + std::string name; + }; + + struct Instruction + { + std::vector body; + int open_scopes; + int close_scopes; + int put_close_scopes; + int do_count; + + void reset() + { + body.clear(); + put_close_scopes = open_scopes = close_scopes = do_count = 0; + } + }; + + static const size_t m_max_instr_count = 512; + Instruction m_instructions[m_max_instr_count]; + Instruction* m_cur_instr; + size_t m_instr_count; + + std::set m_jump_lvls; + std::vector m_body; + std::vector m_funcs; + + //wxString main; + + std::vector& m_data; + ParamArray m_parr; + + std::string GetMask(bool is_sca); + std::string GetVecMask(); + std::string GetScaMask(); + std::string GetDST(bool is_sca = false); + std::string GetSRC(const u32 n); + std::string GetFunc(); + std::string GetTex(); + std::string GetCond(); + std::string AddAddrMask(); + std::string AddAddrReg(); + u32 GetAddr(); + std::string Format(const std::string& code); + + void AddCodeCond(const std::string& dst, const std::string& src); + void AddCode(const std::string& code); + void SetDST(bool is_sca, std::string value); + void SetDSTVec(const std::string& code); + void SetDSTSca(const std::string& code); + std::string BuildFuncBody(const FuncInfo& func); + std::string BuildCode(); + +public: + std::string m_shader; + VertexDecompiler(std::vector& data); + void Decompile(); +}; +#endif \ No newline at end of file diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 07f2c03563..5674643b14 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -974,6 +974,9 @@ Emu\GPU\RSX\D3D12 + + Emu\GPU\RSX\D3D12 + @@ -1846,5 +1849,8 @@ Emu\GPU\RSX\D3D12 + + Emu\GPU\RSX\D3D12 + \ No newline at end of file