diff --git a/rsx_program_decompiler/rsx_program_decompiler.vcxproj.user b/rsx_program_decompiler/rsx_program_decompiler.vcxproj.user index 7dd6d1c..8837e90 100644 --- a/rsx_program_decompiler/rsx_program_decompiler.vcxproj.user +++ b/rsx_program_decompiler/rsx_program_decompiler.vcxproj.user @@ -1,22 +1,22 @@  - -elf_extract_fp_cgbin rsx_fp_static_test2.ppu.elf cg.bin + -fp_glsl fp_cg.ucode out.glsl WindowsLocalDebugger $(SolutionDir)bin\ - -elf_extract_fp_cgbin rsx_fp_static_test2.ppu.elf cg.bin + -fp_glsl fp_cg.ucode out.glsl WindowsLocalDebugger $(SolutionDir)bin\ - -elf_extract_fp_cgbin rsx_fp_static_test2.ppu.elf cg.bin + -fp_glsl fp_cg.ucode out.glsl WindowsLocalDebugger $(SolutionDir)bin\ - -elf_extract_fp_cgbin rsx_fp_static_test2.ppu.elf cg.bin + -fp_glsl fp_cg.ucode out.glsl WindowsLocalDebugger $(SolutionDir)bin\ diff --git a/rsx_program_decompiler_lib/rsx/rsx_fragment_program_decompiler.h b/rsx_program_decompiler_lib/rsx/rsx_fragment_program_decompiler.h index b252ccb..afd71cb 100644 --- a/rsx_program_decompiler_lib/rsx/rsx_fragment_program_decompiler.h +++ b/rsx_program_decompiler_lib/rsx/rsx_fragment_program_decompiler.h @@ -16,7 +16,7 @@ namespace rsx }; template struct dest {}; - template struct src {}; + template struct src {}; struct texture {}; struct addr {}; struct cond {}; @@ -71,8 +71,8 @@ namespace rsx using MUL = instruction < opcode::MUL, H | C, dest<4>, arg>, arg> >; using ADD = instruction < opcode::ADD, H | C, dest<4>, arg>, arg> >; using MAD = instruction < opcode::MAD, H | C, dest<4>, arg>, arg>, arg> >; - using DP3 = instruction < opcode::DP3, H | C, dest<3>, arg>, arg> >; - using DP4 = instruction < opcode::DP4, H | C, dest<4>, arg>, arg> >; + using DP3 = instruction < opcode::DP3, H | C, dest<3>, arg>, arg> >; + using DP4 = instruction < opcode::DP4, H | C, dest<4>, arg>, arg> >; using DST = instruction < opcode::DST, H | C, dest<4>, arg>, arg> >; using MIN = instruction < opcode::MIN, H | C, dest<4>, arg>, arg> >; using MAX = instruction < opcode::MAX, H | C, dest<4>, arg>, arg> >; @@ -104,7 +104,7 @@ namespace rsx using SIN = instruction < opcode::SIN, H | C, dest<4>, arg > >; using PK2 = instruction < opcode::PK2, H | C, dest<4>, arg > >; using UP2 = instruction < opcode::UP2, H | C, dest<4>, arg > >; - using POW = instruction < opcode::POW, H | C, dest<4>, arg > >; + using POW = instruction < opcode::POW, H | C, dest<4>, arg >, arg > >; using PKB = instruction < opcode::PKB, H | C, dest<4>, arg > >; using UPB = instruction < opcode::UPB, H | C, dest<4>, arg > >; using PK16 = instruction < opcode::PK16, H | C, dest<4>, arg > >; @@ -120,10 +120,10 @@ namespace rsx using BEMLUM = instruction < opcode::BEMLUM, H | C, dest<4>, arg> >; using REFL = instruction < opcode::REFL, H | C, dest<4>, arg> >; using TIMESWTEX = instruction < opcode::TIMESWTEX, H | C, dest<4>, arg> >; - using DP2 = instruction < opcode::DP2, H | C, dest<2>, arg>, arg> >; + using DP2 = instruction < opcode::DP2, H | C, dest<2>, arg>, arg> >; using NRM = instruction < opcode::NRM, H | C, dest<4>, arg> >; using DIV = instruction < opcode::DIV, H | C, dest<4>, arg>, arg> >; - using DIVSQ = instruction < opcode::LOOP, H | C, dest<4>, arg>, arg> >; + using DIVSQ = instruction < opcode::DIVSQ, H | C, dest<4>, arg>, arg> >; using LIF = instruction < opcode::LIF, H >; using FENCT = instruction < opcode::FENCT, suffix_none >; using FENCB = instruction < opcode::FENCB, suffix_none >; @@ -148,6 +148,8 @@ namespace rsx template __forceinline static void function(decompiler& decompiler) { + if (id != opcode::FENCT && id != opcode::FENCT) + throw std::runtime_error("unimplemented instruction: " + instructions_names[(std::size_t)id]); } }; @@ -188,8 +190,8 @@ namespace rsx { }; - template - struct expand_arg_t> + template + struct expand_arg_t> { template __forceinline static program_variable impl(decompiler& decompiler) @@ -288,6 +290,20 @@ namespace rsx variable.mask.add(swizzle); + if (apply_dst_mask) + { + variable.mask.add(decompiler.dst_mask().to_string()).symplify(); + } + + if (count != 4) + { + std::string mask = variable.mask.to_string(); + if (mask.empty()) + mask = "xyzw"; + + variable.mask = mask_t{}.add(mask.substr(0, count)); + } + if (need_declare) variable = decompiler.info.vars.add(variable); @@ -315,6 +331,7 @@ namespace rsx result.name = "texture"; result.index = decompiler.ucode.dst.tex_num; result.size = 1; + result.type = program_variable_type::texture; return decompiler.info.vars.add(decompiler_impl::texture_variable(result)); } }; @@ -332,6 +349,20 @@ namespace rsx public: std::unordered_set functions_set; + template + mask_t dst_mask() + { + static const std::string mask = "xyzw"; + + std::string swizzle; + if (ucode.dst.mask_x) swizzle += mask[0]; + if (ucode.dst.mask_y) swizzle += mask[1]; + if (ucode.dst.mask_z) swizzle += mask[2]; + if (ucode.dst.mask_w) swizzle += mask[3]; + + return mask_t{}.add(swizzle.substr(0, count)); + } + template program_variable dst() { @@ -342,16 +373,7 @@ namespace rsx result.index = ucode.dst.dest_reg; result.name = ucode.dst.fp16 ? "H" : "R"; result.size = count; - - static const std::string mask = "xyzw"; - - std::string swizzle; - if (ucode.dst.mask_x) swizzle += mask[0]; - if (ucode.dst.mask_y) swizzle += mask[1]; - if (ucode.dst.mask_z) swizzle += mask[2]; - if (ucode.dst.mask_w) swizzle += mask[3]; - - result.mask.add(swizzle); + result.mask = dst_mask(); return info.vars.add(result); } @@ -369,6 +391,7 @@ namespace rsx result.name = "CC"; result.index = ucode.src0.cond_mod_reg_index; result.size = 4; + result.mask = dst_mask<4>(); return info.vars.add(result); } @@ -405,9 +428,9 @@ namespace rsx set_code_line(decompiler_impl::set_dst(this, arg0, arg1, arg2)); } - void unknown_instruction(u32 opcode) + void unknown_instruction(opcode op) { - throw std::runtime_error("unimplemented instruction '" + instructions_names[opcode] + "' (" + std::to_string(opcode) + ") #" + throw std::runtime_error("unimplemented instruction '" + instructions_names[(std::size_t)op] + "' (" + std::to_string((std::size_t)op) + ") #" + std::to_string(ucode_index)); } @@ -449,38 +472,19 @@ namespace rsx ucode = ucode_ptr[ucode_index].unpack(); - const u32 opcode = ucode.dst.opcode | (ucode.src1.opcode_is_branch << 6); + const fragment_program::opcode opcode = fragment_program::opcode(ucode.dst.opcode | (ucode.src1.opcode_is_branch << 6)); - //if (ucode_index == 20) - // break; - - if (opcode != 0) + if (opcode != fragment_program::opcode::NOP) { - auto function = instructions[opcode]; + auto function = instructions[(std::size_t)opcode]; - try + if (function) { - if (function) - { - function(*this); - } - else - { - unknown_instruction(opcode); - } + function(*this); } - catch (...) + else { - std::exception_ptr ex_p = std::current_exception(); - - try - { - std::rethrow_exception(ex_p); - } - catch (const std::exception& ex) - { - throw std::out_of_range(ex.what()); - } + unknown_instruction(opcode); } } diff --git a/rsx_program_decompiler_lib/rsx/rsx_glsl_fragment_program_decompiler.h b/rsx_program_decompiler_lib/rsx/rsx_glsl_fragment_program_decompiler.h index 5fd864e..18db29b 100644 --- a/rsx_program_decompiler_lib/rsx/rsx_glsl_fragment_program_decompiler.h +++ b/rsx_program_decompiler_lib/rsx/rsx_glsl_fragment_program_decompiler.h @@ -21,6 +21,7 @@ namespace rsx case program_variable_type::input: result += "in "; break; case program_variable_type::output: result += "layout(location = " + std::to_string(var.second.index) + ") out "; break; case program_variable_type::constant: result += "uniform "; break; + case program_variable_type::texture: result += "layout(binding = " + std::to_string(var.second.index) + ") uniform "; break; } if (var.second.storage_type.empty()) @@ -51,8 +52,6 @@ namespace rsx __forceinline static program_variable texture_variable(program_variable arg) { arg.storage_type = "sampler2D"; - arg.type = program_variable_type::constant; - return arg; } @@ -67,11 +66,41 @@ namespace rsx else { assert(arg.constant.type == program_constant_type::f32); - result = fmt::format("vec4(%g, %g, %g, %g)", - arg.constant.x.f32_value, - arg.constant.y.f32_value, - arg.constant.z.f32_value, - arg.constant.w.f32_value); + + std::string mask = arg.mask.to_string(); + std::unordered_map constant_map = + { + { 'x', arg.constant.x.f32_value }, + { 'y', arg.constant.y.f32_value }, + { 'z', arg.constant.z.f32_value }, + { 'w', arg.constant.w.f32_value }, + }; + + if (mask.empty()) + { + result = fmt::format("vec4(%g, %g, %g, %g)", + arg.constant.x.f32_value, + arg.constant.y.f32_value, + arg.constant.z.f32_value, + arg.constant.w.f32_value); + } + else if (mask.size() == 1) + { + result = fmt::format("%g", constant_map[mask[0]]); + } + else + { + result = fmt::format("vec%d(", mask.size()); + + for (size_t i = 0; i < mask.size(); ++i) + { + if (i) + result += ", "; + result += fmt::format("%g", constant_map[mask[i]]); + } + + result += ")"; + } } if (arg.is_abs) @@ -120,7 +149,7 @@ namespace rsx "ddx", "ddy", "texture", "txp", "txd", "rcp", "rsq", "exp2", "log2", "lit", "lrp", "str", "sfl", "cos", "sin", "pk2", "up2", "pow", "pkb", "upb", "pk16", - "up16", "bem" "pkg", "upg", "dpa2", "txl", "?", + "up16", "bem", "pkg", "upg", "dpa2", "txl", "?", "txb", "?", "texbem", "txpbem", "bemlum", "refl", "timeswtex", "dot", "normalize", "?", "divsq", "lif", "fenct", "fencb", "?", "break", "cal", "ife", "loop", "rep", "return" @@ -138,17 +167,17 @@ namespace rsx if (!arg0.is_null()) { - value += variable_to_string(arg0); + value = variable_to_string(arg0); if (!arg1.is_null()) { - value += " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1); + value = "(" + value + " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1) + ")"; } } break; case opcode::DIVSQ: - value += variable_to_string(arg0) + " / sqrt(" + variable_to_string(arg1) + ")"; + value = "(" + variable_to_string(arg0) + " / sqrt(" + variable_to_string(arg1) + "))"; break; case opcode::LIF: @@ -255,12 +284,13 @@ namespace rsx { program_variable execution_condition = dec->execution_condition(); mask_t update_mask; - update_mask.add(dst.mask.to_string()); - update_mask.add(execution_condition.mask.to_string()); - update_mask.add(fmt::string("xyzw").substr(0, count)); + update_mask + .add(execution_condition.mask.to_string()) + .add(dst.mask.to_string()); + + update_mask = mask_t{}.add(update_mask.to_string().substr(0, count)); fmt::string execution_condition_string = execution_condition; - std::string execution_condition_operation; if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq) diff --git a/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.cpp b/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.cpp index 75ea61a..507496e 100644 --- a/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.cpp +++ b/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.cpp @@ -75,6 +75,16 @@ namespace rsx return symplify().to_string_impl(); } + std::string mask_t::apply_to(const std::string& expr) const + { + std::string mask = to_string(); + + if (mask.empty()) + return expr; + + return expr + "." + mask; + } + std::string program_variable::to_string_impl() const { if (array_size) @@ -83,11 +93,6 @@ namespace rsx return index != ~0 ? name + std::to_string(index) : name; } - std::string program_variable::append_dot_if_not_empty(const std::string& string) const - { - return string.empty() ? std::string{} : "." + string; - }; - std::string program_variable::storage_name() const { return name + (array_size ? "[" + std::to_string(array_size + 1) + "]" : (index != ~0 ? std::to_string(index) : std::string{})); @@ -95,12 +100,12 @@ namespace rsx std::string program_variable::to_string() const { - return to_string_impl() + append_dot_if_not_empty(mask.to_string()); + return mask.apply_to(to_string_impl()); } std::string program_variable::to_string() { - return to_string_impl() + append_dot_if_not_empty(mask.to_string()); + return mask.symplify().apply_to(to_string_impl()); } bool program_variable::is_null() const diff --git a/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.h b/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.h index b475ff9..f37fa5e 100644 --- a/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.h +++ b/rsx_program_decompiler_lib/rsx/rsx_program_decompiler.h @@ -11,7 +11,8 @@ namespace rsx none, input, output, - constant + constant, + texture }; struct mask_t @@ -27,6 +28,8 @@ namespace rsx public: std::string to_string() const; std::string to_string(); + + std::string apply_to(const std::string& std) const; }; @@ -70,7 +73,6 @@ namespace rsx private: std::string to_string_impl() const; - std::string append_dot_if_not_empty(const std::string& string) const; public: std::string storage_name() const;