diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 550eb01dc5..1feb6e1964 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -8,6 +8,7 @@ #include #include #include "VertexProgramDecompiler.h" +#include "FragmentProgramDecompiler.h" #include "Utilities/File.h" #pragma comment (lib, "d3dcompiler.lib") @@ -106,12 +107,13 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState( if (!m_fp_buf_num) { LOG_WARNING(RSX, "FP not found in buffer!"); - // Decompile(*fragmentShader); + FragmentDecompiler FS(fragmentShader->addr, fragmentShader->size, fragmentShader->offset); + const std::string &shader = FS.Decompile(); m_fragment_prog.Compile("", SHADER_TYPE::SHADER_TYPE_FRAGMENT); AddFragmentProgram(m_fragment_prog, *fragmentShader); // TODO: This shouldn't use current dir - //fs::file("./FragmentProgram.txt", o_write | o_create | o_trunc).write(m_fragment_prog.shader.c_str(), m_fragment_prog.shader.size()); + fs::file("./FragmentProgram.txt", o_write | o_create | o_trunc).write(shader.c_str(), shader.size()); } if (!m_vp_buf_num) diff --git a/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.cpp new file mode 100644 index 0000000000..c965b6dda1 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.cpp @@ -0,0 +1,630 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "FragmentProgramDecompiler.h" + +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" + +FragmentDecompiler::FragmentDecompiler(u32 addr, u32& size, u32 ctrl) : + m_addr(addr), + m_size(size), + m_const_index(0), + m_location(0), + m_ctrl(ctrl) +{ + m_size = 0; +} + + +void FragmentDecompiler::SetDst(std::string code, bool append_mask) +{ + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; + + switch (src1.scale) + { + case 0: break; + case 1: code = "(" + code + " * 2.0)"; break; + case 2: code = "(" + code + " * 4.0)"; break; + case 3: code = "(" + code + " * 8.0)"; break; + case 5: code = "(" + code + " / 2.0)"; break; + case 6: code = "(" + code + " / 4.0)"; break; + case 7: code = "(" + code + " / 8.0)"; break; + + default: + LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale)); + Emu.Pause(); + break; + } + + if (dst.saturate) + { + code = "clamp(" + code + ", 0.0, 1.0)"; + } + + code += (append_mask ? "$m" : ""); + + if (dst.no_dest) + { + if (dst.set_cond) + { + AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";"); + } + else + { + AddCode("$ifcond " + code + ";"); + } + + return; + } + + std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m"; + + AddCodeCond(Format(dest), code); + //AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); + + if (dst.set_cond) + { + AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";"); + } +} + +void FragmentDecompiler::AddCode(const std::string& code) +{ + main.append(m_code_level, '\t') += Format(code) + "\n"; +} + +std::string FragmentDecompiler::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 FragmentDecompiler::AddReg(u32 index, int fp16) +{ + return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)"); +} + +bool FragmentDecompiler::HasReg(u32 index, int fp16) +{ + return m_parr.HasParam(PARAM_NONE, "vec4", + std::string(fp16 ? "h" : "r") + std::to_string(index)); +} + +std::string FragmentDecompiler::AddCond() +{ + return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index)); +} + +std::string FragmentDecompiler::AddConst() +{ + std::string name = std::string("fc") + std::to_string(m_size + 4 * 4); + if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) + { + return name; + } + + auto data = vm::ptr::make(m_addr + m_size + 4 * sizeof(u32)); + + m_offset = 2 * 4 * sizeof(u32); + u32 x = GetData(data[0]); + u32 y = GetData(data[1]); + u32 z = GetData(data[2]); + u32 w = GetData(data[3]); + return m_parr.AddParam(PARAM_UNIFORM, "vec4", name, + std::string("vec4(") + std::to_string((float&)x) + ", " + std::to_string((float&)y) + + ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")"); +} + +std::string FragmentDecompiler::AddTex() +{ + return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("tex") + std::to_string(dst.tex_num)); +} + +std::string FragmentDecompiler::Format(const std::string& code) +{ + const std::pair> repl_list[] = + { + { "$$", []() -> std::string { return "$"; } }, + { "$0", [this]() -> std::string {return GetSRC(src0);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), *this, src0) }, + { "$1", [this]() -> std::string {return GetSRC(src1);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), this, src1) }, + { "$2", [this]() -> std::string {return GetSRC(src2);} },//std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetSRC), this, src2) }, + { "$t", std::bind(std::mem_fn(&FragmentDecompiler::AddTex), this) }, + { "$m", std::bind(std::mem_fn(&FragmentDecompiler::GetMask), this) }, + { "$ifcond ", [this]() -> std::string + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } + }, + { "$cond", std::bind(std::mem_fn(&FragmentDecompiler::GetCond), this) }, + { "$c", std::bind(std::mem_fn(&FragmentDecompiler::AddConst), this) } + }; + + return fmt::replace_all(code, repl_list); +} + +std::string FragmentDecompiler::GetCond() +{ + if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) + { + return "true"; + } + else if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) + { + return "false"; + } + + 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]; + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + if (src0.exec_if_gr && src0.exec_if_eq) + { + cond = "greaterThanEqual"; + } + else if (src0.exec_if_lt && src0.exec_if_eq) + { + cond = "lessThanEqual"; + } + else if (src0.exec_if_gr && src0.exec_if_lt) + { + cond = "notEqual"; + } + else if (src0.exec_if_gr) + { + cond = "greaterThan"; + } + else if (src0.exec_if_lt) + { + cond = "lessThan"; + } + else //if(src0.exec_if_eq) + { + cond = "equal"; + } + + return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))"; +} + +void FragmentDecompiler::AddCodeCond(const std::string& dst, const std::string& src) +{ + if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + 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]; + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + if (src0.exec_if_gr && src0.exec_if_eq) + { + cond = "greaterThanEqual"; + } + else if (src0.exec_if_lt && src0.exec_if_eq) + { + cond = "lessThanEqual"; + } + else if (src0.exec_if_gr && src0.exec_if_lt) + { + cond = "notEqual"; + } + else if (src0.exec_if_gr) + { + cond = "greaterThan"; + } + else if (src0.exec_if_lt) + { + cond = "lessThan"; + } + else //if(src0.exec_if_eq) + { + cond = "equal"; + } + + cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))"; + + 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] + ";"); + } + } +} + +template std::string FragmentDecompiler::GetSRC(T src) +{ + std::string ret; + + switch (src.reg_type) + { + case 0: //tmp + ret += AddReg(src.tmp_reg_index, src.fp16); + break; + + case 1: //input + { + static const std::string reg_table[] = + { + "gl_Position", + "diff_color", "spec_color", + "fogc", + "tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8", "tc9", + "ssa" + }; + + 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 += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]); + } + else + { + LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num)); + ret += m_parr.AddParam(PARAM_IN, "vec4", "unk"); + Emu.Pause(); + } + break; + } + } + break; + + case 2: //const + ret += AddConst(); + break; + + default: + LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type)); + Emu.Pause(); + 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 (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; + + if (src.abs) ret = "abs(" + ret + ")"; + if (src.neg) ret = "-" + ret; + + return ret; +} + +std::string FragmentDecompiler::BuildCode() +{ + //main += fmt::Format("\tgl_FragColor = %c0;\n", m_ctrl & 0x40 ? 'r' : 'h'); + const std::pair table[] = + { + { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, + }; + + for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) + { + if (m_parr.HasParam(PARAM_NONE, "vec4", table[i].second)) + AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";"); + } + + if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n"; + + std::string p; + + for (auto& param : m_parr.params) { +// p += param.Format(); + } + + return std::string("#version 420\n" + "\n" + + p + "\n" + "void main()\n{\n" + main + "}\n"); +} + +std::string FragmentDecompiler::Decompile() +{ + auto data = vm::ptr::make(m_addr); + m_size = 0; + m_location = 0; + m_loop_count = 0; + m_code_level = 1; + + 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_code_level--; + AddCode("}"); + m_loop_count--; + } + + 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_code_level--; + AddCode("}"); + AddCode("else"); + AddCode("{"); + m_code_level++; + } + + dst.HEX = GetData(data[0]); + src0.HEX = GetData(data[1]); + src1.HEX = GetData(data[2]); + src2.HEX = GetData(data[3]); + + m_offset = 4 * sizeof(u32); + + const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); + + auto SCT = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; + case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break; + case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto SCB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; + case RSX_FP_OPCODE_REFL: LOG_ERROR(RSX, "Unimplemented SCB instruction: REFL"); break; // TODO: Is this in the right category? + case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break; + case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; + case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; + case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); break; + case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; + case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); break; // TODO: Is this in the right category? + case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_PK2: SetDst("packSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_PK4: SetDst("packSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break; + case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break; + case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto TEX_SRB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; + case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; + case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break; + case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); break; + case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; + case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); break; + case RSX_FP_OPCODE_TXP: SetDst("textureProj($t, $0.xyz, $1.x)"); break; //TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478) and The Simpsons Arcade Game (NPUB30563)) + case RSX_FP_OPCODE_TXPBEM: SetDst("textureProj($t, $0.xyz, $1.x)"); break; + case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break; + case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); break; + case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); break; + case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break; + case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break; + case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break; + + default: + return false; + } + + return true; + }; + + auto SIP = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_BRK: SetDst("break"); break; + case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break; + case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break; + case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break; + case RSX_FP_OPCODE_IFE: + AddCode("if($cond)"); + m_else_offsets.push_back(src1.else_offset << 2); + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + break; + case RSX_FP_OPCODE_LOOP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_REP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_RET: SetDst("return"); break; + + default: + return false; + } + + return true; + }; + + switch (opcode) + { + case RSX_FP_OPCODE_NOP: break; + case RSX_FP_OPCODE_KIL: SetDst("discard", false); 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)", opcode, forced_unit); + break; + } + + m_size += m_offset; + + if (dst.end) break; + + assert(m_offset % sizeof(u32) == 0); + data += m_offset / sizeof(u32); + } + + // flush m_code_level + m_code_level = 1; + std::string m_shader = BuildCode(); + main.clear(); +// m_parr.params.clear(); + return m_shader; +} + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.h new file mode 100644 index 0000000000..c406b3d269 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/FragmentProgramDecompiler.h @@ -0,0 +1,43 @@ +#pragma once +#if defined(DX12_SUPPORT) +#include "ShaderParam.h" +#include "Emu/RSX/RSXFragmentProgram.h" + +class FragmentDecompiler +{ + std::string main; + ParamArray m_parr; + u32 m_addr; + u32& m_size; + u32 m_const_index; + u32 m_offset; + u32 m_location; + u32 m_ctrl; + u32 m_loop_count; + int m_code_level; + std::vector m_end_offsets; + std::vector m_else_offsets; + + std::string GetMask(); + + void SetDst(std::string code, bool append_mask = true); + void AddCode(const std::string& code); + std::string AddReg(u32 index, int fp16); + bool HasReg(u32 index, int fp16); + std::string AddCond(); + std::string AddConst(); + std::string AddTex(); + std::string Format(const std::string& code); + + void AddCodeCond(const std::string& dst, const std::string& src); + std::string GetCond(); + template std::string GetSRC(T src); + std::string BuildCode(); + + u32 GetData(const u32 d) const { return d << 16 | d >> 16; } +public: + FragmentDecompiler(u32 addr, u32& size, u32 ctrl); + std::string Decompile(); +}; + +#endif \ No newline at end of file diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 232b4bd521..5ff058f7d5 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -45,6 +45,7 @@ + @@ -508,6 +509,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index f30d1fdaee..cc40c3f295 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -980,6 +980,9 @@ Emu\GPU\RSX\D3D12 + + Emu\GPU\RSX\D3D12 + Emu\GPU\RSX\D3D12 @@ -1861,6 +1864,9 @@ Emu\GPU\RSX\D3D12 + + Emu\GPU\RSX\D3D12 + Emu\GPU\RSX\D3D12