From 53acafb457322ff791ab5b41f831ad886c069192 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Wed, 6 Jan 2016 15:47:54 +0200 Subject: [PATCH] fp: fixed scalar instructions & implemented texture instructions vp: implemented TXL instruction minor improvements --- rsx_decompiler/rsx_decompiler.cpp | 4 +- rsx_decompiler/rsx_decompiler.h | 4 +- rsx_decompiler/rsx_fp_decompiler.cpp | 119 +++++++++++++++++++-------- rsx_decompiler/rsx_fp_ucode.cpp | 34 ++++---- rsx_decompiler/rsx_fp_ucode.h | 2 +- rsx_decompiler/rsx_vp_decompiler.cpp | 58 ++++++++++--- rsx_decompiler/rsx_vp_ucode.cpp | 28 ++++++- rsx_decompiler/rsx_vp_ucode.h | 9 +- rsx_program_decompiler/endianness.h | 12 ++- 9 files changed, 201 insertions(+), 69 deletions(-) diff --git a/rsx_decompiler/rsx_decompiler.cpp b/rsx_decompiler/rsx_decompiler.cpp index 6678c66..a458985 100644 --- a/rsx_decompiler/rsx_decompiler.cpp +++ b/rsx_decompiler/rsx_decompiler.cpp @@ -55,7 +55,7 @@ namespace rsx { if (program.input_attributes & (1 << index)) { - result.code += "in vec4 " + rsx::fragment_program::input_attrib_map[index] + ";\n"; + result.code += "in vec4 " + rsx::fragment_program::input_attrib_names[index] + ";\n"; } } break; @@ -65,7 +65,7 @@ namespace rsx { if (program.input_attributes & (1 << index)) { - result.code += "in vec4 " + rsx::vertex_program::input_registers_table[index] + ";\n"; + result.code += "in vec4 " + rsx::vertex_program::input_attrib_names[index] + ";\n"; } } break; diff --git a/rsx_decompiler/rsx_decompiler.h b/rsx_decompiler/rsx_decompiler.h index 7a0dd22..bd999ef 100644 --- a/rsx_decompiler/rsx_decompiler.h +++ b/rsx_decompiler/rsx_decompiler.h @@ -57,9 +57,10 @@ namespace rsx struct register_info { + std::string name; + int id; register_type type; - std::string name; bool operator==(const register_info& rhs) const { @@ -106,6 +107,7 @@ namespace rsx std::string entry_function; std::string code; + std::uint64_t ucode_size; std::uint64_t ucode_hash; }; diff --git a/rsx_decompiler/rsx_fp_decompiler.cpp b/rsx_decompiler/rsx_fp_decompiler.cpp index 0437b2e..b52ee83 100644 --- a/rsx_decompiler/rsx_fp_decompiler.cpp +++ b/rsx_decompiler/rsx_fp_decompiler.cpp @@ -2,6 +2,9 @@ #include "rsx_fp_ucode.h" #include #include +#include "../rsx_program_decompiler/endianness.h" + +using namespace endianness; namespace rsx { @@ -18,6 +21,8 @@ namespace rsx template using float_point_expr = typename base::template float_point_expr; + using sampler2D_expr = typename base::template expression_from; + template using float_point_t = typename base::template float_point_t; @@ -62,10 +67,25 @@ namespace rsx return info.name; } + sampler2D_expr texture(int index) + { + texture_info info; + info.id = index; + info.name = "texture" + std::to_string(index); + program.textures.insert(info); + + return info.name; + } + + float_point_expr<4> texture_coords_modifier(int index) + { + return{ "texture" + std::to_string(index) + "_cm" }; + } + float_point_expr<4> input(int index) { program.input_attributes |= (1 << index); - return input_attrib_map[index]; + return input_attrib_names[index]; } }; @@ -93,10 +113,10 @@ namespace rsx { instruction_t result; - result.data.dst._u32 = (data.dst._u32 << 16) | (data.dst._u32 >> 16); - result.data.src0._u32 = (data.src0._u32 << 16) | (data.src0._u32 >> 16); - result.data.src1._u32 = (data.src1._u32 << 16) | (data.src1._u32 >> 16); - result.data.src2._u32 = (data.src2._u32 << 16) | (data.src2._u32 >> 16); + (be_t&)result.data.dst._u32 = (data.dst._u32 << 16) | (data.dst._u32 >> 16); + (be_t&)result.data.src0._u32 = (data.src0._u32 << 16) | (data.src0._u32 >> 16); + (be_t&)result.data.src1._u32 = (data.src1._u32 << 16) | (data.src1._u32 >> 16); + (be_t&)result.data.src2._u32 = (data.src2._u32 << 16) | (data.src2._u32 >> 16); return result; } @@ -153,7 +173,7 @@ namespace rsx case src_reg_type_t::constant: return context.constant(); } - throw; + throw std::runtime_error("bad instruction argument (#" + std::to_string((u32)src.reg_type) + ") type."); }; float_point_expr<4> result = get_variable(src); @@ -178,6 +198,16 @@ namespace rsx return result; } + sampler2D_expr texture(context_t& context) const + { + return context.texture(data.dst.tex_num); + } + + float_point_expr<4> texture_coords_modifier(context_t& context) const + { + return context.texture_coords_modifier(data.dst.tex_num); + } + std::string destination_swizzle() const { std::string swizzle; @@ -267,7 +297,7 @@ namespace rsx return base::compare_function::equal; } - throw; + throw std::logic_error(""); } boolean_expr<1> execution_condition(condition_operation operation) @@ -307,9 +337,14 @@ namespace rsx return base::custom_compare(function, (int)instruction.destination_swizzle().size(), a, b); } - typename base::template expression_from tex() + sampler2D_expr texture() { - return{ "unk_tex" }; + return instruction.texture(context); + } + + float_point_expr<4> texture_coords(int src_index = 0) + { + return src(src_index) * instruction.texture_coords_modifier(context); } template @@ -329,6 +364,7 @@ namespace rsx { none, disable_swizzle_as_dst = 1, + allow_bx2 }; template @@ -374,7 +410,7 @@ namespace rsx break; default: - throw std::runtime_error("fragment program decompiler: unimplemented precision."); + throw std::runtime_error("fragment program decompiler: unimplemented precision. (" + std::to_string(instruction.data.dst.prec) +")."); } } @@ -467,7 +503,7 @@ namespace rsx if (instruction.data.dst.set_cond) { - expression.assign(cond.with_mask(dst_swizzle) = expression); + expression.assign(modify_cond.with_mask(dst_swizzle) = expression); } result += base::if_(cond.swizzle(channel_to_index.at(entry.first)).template call_operator>(operation, zero), expression); @@ -494,7 +530,7 @@ namespace rsx if (instruction.data.dst.set_cond) { - src.assign(float_point_expr<4>(modify_cond.text, dest.mask) = src); + src.assign(modify_cond.with_mask(dest.mask) = src); } } @@ -506,12 +542,16 @@ namespace rsx builder::writer_t set_dst(const float_point_expr<1>& arg, u32 flags = none) { - if (instruction.destination_swizzle().size() != 1) + switch (instruction.destination_swizzle().size()) { - return set_dst(float_point_t<4>::ctor(arg), flags); - } + case 1: return set_dst(float_point_expr<4>{ arg.to_string() }, flags | disable_swizzle_as_dst); + case 2: return set_dst(float_point_expr<4>{ float_point_t<2>::ctor(arg).to_string() }, flags); + case 3: return set_dst(float_point_expr<4>{ float_point_t<3>::ctor(arg).to_string() }, flags); + case 4: return set_dst(float_point_t<4>::ctor(arg), flags); - return set_dst(float_point_expr<4>{ arg.to_string() }, flags | disable_swizzle_as_dst); + default: + throw std::logic_error("bad destination swizzle."); + } } builder::writer_t set_dst(const boolean_expr<4>& arg, u32 flags = none) @@ -528,7 +568,7 @@ namespace rsx case 4: arg_string = float_point_t<4>::ctor(boolean_expr<4>{ arg.to_string() }).to_string(); break; default: - throw; + throw std::logic_error("bad destination swizzle."); } return set_dst(float_point_expr<4>{ arg_string, std::string("xyzw"), is_single, 4 }, flags); @@ -565,21 +605,21 @@ namespace rsx case (u32)opcode_t::kil: return conditional(typename base::void_expr{ "discard;" }); case (u32)opcode_t::pk4: return base::unimplemented("PK4"); case (u32)opcode_t::up4: return base::unimplemented("UP4"); - case (u32)opcode_t::ddx: return set_dst(base::ddx(src_swizzled_as_dst(0)), disable_swizzle_as_dst); - case (u32)opcode_t::ddy: return set_dst(base::ddy(src_swizzled_as_dst(0)), disable_swizzle_as_dst); - case (u32)opcode_t::tex: return set_dst(base::texture(tex(), src(0).xy())); - case (u32)opcode_t::txp: return set_dst(base::texture(tex(), src(0).xy() / src(0).w())); - case (u32)opcode_t::txd: return set_dst(base::texture_grad(tex(), src(0).xy(), src(1).xy(), src(2).xy())); - case (u32)opcode_t::rcp: return set_dst(float_point_t<1>::ctor(1.0f) / src_swizzled_as_dst(0), disable_swizzle_as_dst); - case (u32)opcode_t::rsq: return set_dst(base::rsqrt(src_swizzled_as_dst(0)), disable_swizzle_as_dst); - case (u32)opcode_t::ex2: return set_dst(base::exp2(src_swizzled_as_dst(0)), disable_swizzle_as_dst); - case (u32)opcode_t::lg2: return set_dst(base::log2(src_swizzled_as_dst(0)), disable_swizzle_as_dst); + //case (u32)opcode_t::ddx: return set_dst(base::ddx(src(0).xy()), disable_swizzle_as_dst); + //case (u32)opcode_t::ddy: return set_dst(base::ddy(src(0).xy()), disable_swizzle_as_dst); + case (u32)opcode_t::tex: return set_dst(base::texture(texture(), texture_coords().xy()), allow_bx2); + case (u32)opcode_t::txp: return set_dst(base::texture(texture(), texture_coords().xy() / src(0).w()), allow_bx2); + case (u32)opcode_t::txd: return set_dst(base::texture_grad(texture(), texture_coords().xy(), src(1).xy(), src(2).xy()), allow_bx2); + case (u32)opcode_t::rcp: return set_dst(float_point_t<1>::ctor(1.0f) / src(0).x(), disable_swizzle_as_dst); + case (u32)opcode_t::rsq: return set_dst(base::rsqrt(src(0).x()), disable_swizzle_as_dst); + case (u32)opcode_t::ex2: return set_dst(base::exp2(src(0).x()), disable_swizzle_as_dst); + case (u32)opcode_t::lg2: return set_dst(base::log2(src(0).x()), disable_swizzle_as_dst); case (u32)opcode_t::lit: return base::unimplemented("LIT"); case (u32)opcode_t::lrp: return base::unimplemented("LRP"); case (u32)opcode_t::str: return set_dst(1.0f); case (u32)opcode_t::sfl: return set_dst(0.0f); - case (u32)opcode_t::cos: return set_dst(base::cos(src_swizzled_as_dst(0)), disable_swizzle_as_dst); - case (u32)opcode_t::sin: return set_dst(base::sin(src_swizzled_as_dst(0)), disable_swizzle_as_dst); + case (u32)opcode_t::cos: return set_dst(base::cos(src(0).x()), disable_swizzle_as_dst); + case (u32)opcode_t::sin: return set_dst(base::sin(src(0).x()), disable_swizzle_as_dst); case (u32)opcode_t::pk2: return base::unimplemented("PK2"); case (u32)opcode_t::up2: return base::unimplemented("UP2"); case (u32)opcode_t::pow: return set_dst(base::pow(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst); @@ -597,8 +637,8 @@ namespace rsx return set_dst(float_point_t<4>::ctor(src_0.x() * src_1.x() + src_0.y() * src_1.y() + src(2).z())); } - case (u32)opcode_t::txl: return set_dst(base::texture_lod(tex(), src(0).xy(), src(1).x())); - case (u32)opcode_t::txb: return set_dst(base::texture_bias(tex(), src(0).xy(), src(1).x())); + case (u32)opcode_t::txl: return set_dst(base::texture_lod(texture(), texture_coords().xy(), src(1).x()), allow_bx2); + case (u32)opcode_t::txb: return set_dst(base::texture_bias(texture(), texture_coords().xy(), src(1).x()), allow_bx2); case (u32)opcode_t::texbem: return base::unimplemented("TEXBEM"); case (u32)opcode_t::txpbem: return base::unimplemented("TXPBEM"); case (u32)opcode_t::bemlum: return base::unimplemented("BEMLUM"); @@ -606,8 +646,8 @@ namespace rsx case (u32)opcode_t::timeswtex: return base::unimplemented("TIMESWTEX"); case (u32)opcode_t::dp2: return set_dst(base::dot(src(0).xy(), src(1).xy())); case (u32)opcode_t::nrm: return set_dst(base::normalize(src(0).xyz()).xyzx()); - case (u32)opcode_t::div: return set_dst(src_swizzled_as_dst(0) / src_swizzled_as_dst(1), disable_swizzle_as_dst); - case (u32)opcode_t::divsq: return set_dst(src_swizzled_as_dst(0) / base::sqrt(src_swizzled_as_dst(1)), disable_swizzle_as_dst); + case (u32)opcode_t::div: return set_dst(src_swizzled_as_dst(0) / src(1).x(), disable_swizzle_as_dst); + case (u32)opcode_t::divsq: return set_dst(src_swizzled_as_dst(0) / base::sqrt(src(1).x()), disable_swizzle_as_dst); case (u32)opcode_t::lif: return base::unimplemented("LIF"); case (u32)opcode_t::fenct: return base::comment("fenct"); case (u32)opcode_t::fencb: return base::comment("fencb"); @@ -639,7 +679,7 @@ namespace rsx case (u32)opcode_t::ret: return conditional(typename base::void_expr("return;")); } - throw; + throw std::runtime_error("bad instruction. (" + std::to_string(u32(instruction.data.dst.opcode) | (u32(instruction.data.src1.opcode_is_branch) << 6)) + ")"); } decompiled_shader decompile(std::size_t offset, instruction_t* instructions) @@ -657,16 +697,27 @@ namespace rsx instruction = instructions[index].unpack(); - base::writer += decode_instruction(); + try + { + base::writer += decode_instruction(); + } + catch (const std::runtime_error &ex) + { + base::writer += base::comment("exception: " + std::string(ex.what())); + } if (instruction.data.dst.end) + { + context.offset += context.is_next_is_constant ? sizeof(instruction_t) * 2 : sizeof(instruction_t); break; + } } context.program.entry_function = "func0"; base::writer.before(0, "void func0()\n{\n"); base::writer.after(base::writer.position, "}\n"); context.program.code = base::writer.finalize(); + context.program.ucode_size = context.offset; return context.program; } diff --git a/rsx_decompiler/rsx_fp_ucode.cpp b/rsx_decompiler/rsx_fp_ucode.cpp index 2e7faaa..02cbdff 100644 --- a/rsx_decompiler/rsx_fp_ucode.cpp +++ b/rsx_decompiler/rsx_fp_ucode.cpp @@ -4,24 +4,24 @@ namespace rsx { namespace fragment_program { - const std::string input_attrib_map[16] = + const std::string input_attrib_names[16] = { - "in_wpos", //0 - "in_col0", //1 - "in_col1", //2 - "in_fogc", //3 - "in_tex0", //4 - "in_tex1", //5 - "in_tex2", //6 - "in_tex3", //7 - "in_tex4", //8 - "in_tex5", //9 - "in_tex6", //10 - "in_tex7", //11 - "in_tex8", //12 - "in_tex9", //13 - "in_ssa", //14 - "in_unk" //15 + "wpos", //0 + "col0", //1 + "col1", //2 + "fogc", //3 + "tex0", //4 + "tex1", //5 + "tex2", //6 + "tex3", //7 + "tex4", //8 + "tex5", //9 + "tex6", //10 + "tex7", //11 + "tex8", //12 + "tex9", //13 + "ssa", //14 + "unk" //15 }; const std::string instructions_names[128] = diff --git a/rsx_decompiler/rsx_fp_ucode.h b/rsx_decompiler/rsx_fp_ucode.h index 69ce807..e33e6e3 100644 --- a/rsx_decompiler/rsx_fp_ucode.h +++ b/rsx_decompiler/rsx_fp_ucode.h @@ -233,6 +233,6 @@ namespace rsx std::uint64_t hash(const ucode_instr *ucode); extern const std::string instructions_names[128]; - extern const std::string input_attrib_map[16]; + extern const std::string input_attrib_names[16]; } } diff --git a/rsx_decompiler/rsx_vp_decompiler.cpp b/rsx_decompiler/rsx_vp_decompiler.cpp index abc8df1..41a17e4 100644 --- a/rsx_decompiler/rsx_vp_decompiler.cpp +++ b/rsx_decompiler/rsx_vp_decompiler.cpp @@ -18,6 +18,8 @@ namespace rsx template using float_point_expr = typename base::template float_point_expr; + using sampler2D_expr = typename base::template expression_from; + template using integer_expr = typename base::template integer_expr; @@ -62,13 +64,23 @@ namespace rsx + "]"; } + sampler2D_expr texture(int index) + { + texture_info info; + info.id = index; + info.name = "vtexture" + std::to_string(index); + program.textures.insert(info); + + return info.name; + } + float_point_expr<4> output(u32 index) { program.output_attributes |= (1 << index); register_info info; info.id = index; info.type = register_type::single_float_point; - info.name = rsx::fragment_program::input_attrib_map[index];//"o" + std::to_string(index); + info.name = "o" + std::to_string(index); program.temporary_registers.insert(info); return info.name; } @@ -97,7 +109,7 @@ namespace rsx float_point_expr<4> input(int index) { program.input_attributes |= (1 << index); - return input_registers_table[index]; + return input_attrib_names[index]; } }; @@ -178,6 +190,11 @@ namespace rsx return float_point_expr<4>(arg.text, arg_mask, arg.is_single, arg.base_count); } + sampler2D_expr texture() + { + return context.texture(instruction.unpack_src(0).tmp_src & 0x3); + } + float_point_expr<4> src(int index, bool is_swizzle_as_dst = false) { SRC src = instruction.unpack_src(index); @@ -426,14 +443,18 @@ namespace rsx return result; } - typename base::writer_t set_dst(float_point_expr<1> arg) + builder::writer_t set_dst(const float_point_expr<1>& arg) { - if (destination_swizzle().size() != 1) + switch (destination_swizzle().size()) { - return set_dst(float_point_t<4>::ctor(arg)); - } + case 1: return set_dst(float_point_expr<4>{ arg.to_string() }); + case 2: return set_dst(float_point_expr<4>{ float_point_t<2>::ctor(arg).to_string() }); + case 3: return set_dst(float_point_expr<4>{ float_point_t<3>::ctor(arg).to_string() }); + case 4: return set_dst(float_point_t<4>::ctor(arg)); - return set_dst(float_point_expr<4>{ arg.to_string() }); + default: + throw; + } } typename base::writer_t set_dst(boolean_expr<4> arg) @@ -598,7 +619,7 @@ namespace rsx case (u32)vec_opcode_t::add: return set_dst(src_swizzled_as_dst(0) + src_swizzled_as_dst(2)); case (u32)vec_opcode_t::mad: return set_dst((src_swizzled_as_dst(0) * src_swizzled_as_dst(1)).without_scope() + src_swizzled_as_dst(2)); case (u32)vec_opcode_t::dp3: return set_dst(base::dot(src(0).xyz(), src(1).xyz())); - case (u32)vec_opcode_t::dph: break; + case (u32)vec_opcode_t::dph: return set_dst(base::dot(float_point_t<4>::ctor(src(0).xyz(), 1.0), src(1))); break; case (u32)vec_opcode_t::dp4: return set_dst(base::dot(src(0), src(1))); case (u32)vec_opcode_t::dst: break; case (u32)vec_opcode_t::min: return set_dst(base::min(src_swizzled_as_dst(0), src_swizzled_as_dst(1))); @@ -615,7 +636,11 @@ namespace rsx case (u32)vec_opcode_t::sne: return set_dst(compare(base::compare_function::not_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); case (u32)vec_opcode_t::str: return set_dst(1.0f); case (u32)vec_opcode_t::ssg: break; - case (u32)vec_opcode_t::txl: break; + case (u32)vec_opcode_t::txl: + { + auto src_1 = src(1); + return set_dst(base::texture_lod(texture(), src_1.xy(), src_1.w())); + } default: throw; @@ -649,14 +674,27 @@ namespace rsx public: decompiled_shader decompile(std::size_t offset, instruction_t *instructions) { + context.program.ucode_size = 0; + for (std::size_t i = offset; i < 512; ++i, base::writer.next()) { instruction = instructions[i].unpack(); - base::writer += decode_instruction(); + try + { + base::writer += decode_instruction(); + } + catch (...) + { + base::writer += base::comment("exception!"); + } + + context.program.ucode_size += sizeof(instruction_t); if (instruction.data.d3.end) + { break; + } } context.program.entry_function = "func0"; diff --git a/rsx_decompiler/rsx_vp_ucode.cpp b/rsx_decompiler/rsx_vp_ucode.cpp index 2856bf2..6f70353 100644 --- a/rsx_decompiler/rsx_vp_ucode.cpp +++ b/rsx_decompiler/rsx_vp_ucode.cpp @@ -4,7 +4,7 @@ namespace rsx { namespace vertex_program { - const std::string input_registers_table[0x10] = + const std::string input_attrib_names[0x10] = { "in_pos", "in_weight", "in_normal", "in_diff_color", "in_spec_color", @@ -14,6 +14,32 @@ namespace rsx "in_tc4", "in_tc5", "in_tc6", "in_tc7" }; + static const std::string output_attrib_names[22] = + { + "front_diffuse_color", + "front_specular_color", + "back_diffuse_color", + "back_specular_color", + "fog", + "point_size", + "uc0", + "uc1", + "uc2", + "uc3", + "uc4", + "uc5", + "tex8", + "tex9", + "tex0", + "tex1", + "tex2", + "tex3", + "tex4", + "tex5", + "tex6", + "tex7", + }; + const std::string sca_op_names[0x20] = { "NOP", "MOV", "RCP", "RCC", "RSQ", "EXP", "LOG", diff --git a/rsx_decompiler/rsx_vp_ucode.h b/rsx_decompiler/rsx_vp_ucode.h index edb22fb..a4aa2f1 100644 --- a/rsx_decompiler/rsx_vp_ucode.h +++ b/rsx_decompiler/rsx_vp_ucode.h @@ -58,7 +58,11 @@ namespace rsx sne = 0x14, str = 0x15, ssg = 0x16, - txl = 0x19 + arr = 0x17, + ara = 0x18, + txl = 0x19, + psh = 0x1a, + pop = 0x1b, }; enum class src_register_type : u32 @@ -206,7 +210,8 @@ namespace rsx std::uint64_t hash(const ucode_instr *ucode); - extern const std::string input_registers_table[0x10]; + extern const std::string input_attrib_names[0x10]; + extern const std::string output_attrib_names[22]; extern const std::string sca_op_names[0x20]; extern const std::string vec_op_names[0x20]; } diff --git a/rsx_program_decompiler/endianness.h b/rsx_program_decompiler/endianness.h index 8766a5d..d721257 100644 --- a/rsx_program_decompiler/endianness.h +++ b/rsx_program_decompiler/endianness.h @@ -1,5 +1,15 @@ #pragma once -#include +#include + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; + +using s8 = int8_t; +using s16 = int16_t; +using s32 = int32_t; +using s64 = int64_t; namespace endianness {