From 46dd50682e1a417d14dbbcc70b2b2c888869e9d8 Mon Sep 17 00:00:00 2001 From: DHrpcs3 Date: Sun, 20 Dec 2015 08:59:49 +0200 Subject: [PATCH] Implemented vertex program decompiler --- rsx_decompiler/rsx_decompiler.cpp | 42 +- rsx_decompiler/rsx_fp_decompiler.cpp | 8 +- rsx_decompiler/rsx_vp_decompiler.cpp | 610 +++++++++++++++++- rsx_decompiler/rsx_vp_ucode.cpp | 10 + rsx_decompiler/rsx_vp_ucode.h | 14 +- .../rsx_program_decompiler.cpp | 8 +- shader_code/clike_builder.h | 15 + shader_code/clike_language.h | 4 + shader_code/glsl_language.h | 12 + 9 files changed, 691 insertions(+), 32 deletions(-) diff --git a/rsx_decompiler/rsx_decompiler.cpp b/rsx_decompiler/rsx_decompiler.cpp index b74d5ca..9bd3d48 100644 --- a/rsx_decompiler/rsx_decompiler.cpp +++ b/rsx_decompiler/rsx_decompiler.cpp @@ -21,7 +21,23 @@ namespace rsx for (const register_info& temporary : program.temporary_registers) { - result.code += "vec4 " + temporary.name + " = vec4(0.0);\n"; + std::string type; + switch (temporary.type) + { + case register_type::half_float_point: + case register_type::single_float_point: + type += "vec4"; + break; + + case register_type::integer: + type += "ivec4"; + break; + + default: + throw; + } + + result.code += type + " " + temporary.name + " = " + type + "(0);\n"; } result.code += "\n"; @@ -31,12 +47,30 @@ namespace rsx result.code += "uniform sampler2D " + texture.name + ";\n"; } - for (std::size_t index = 0; index < std::size(rsx::fragment_program::input_attrib_map); ++index) + switch (program.type) { - if (program.input_attributes & (1 << index)) + case program_type::fragment: + for (std::size_t index = 0; index < std::size(rsx::fragment_program::input_attrib_map); ++index) { - result.code += "in vec4 " + rsx::fragment_program::input_attrib_map[index] + ";\n"; + if (program.input_attributes & (1 << index)) + { + result.code += "in vec4 " + rsx::fragment_program::input_attrib_map[index] + ";\n"; + } } + break; + + case program_type::vertex: + for (std::size_t index = 0; index < std::size(rsx::vertex_program::input_registers_table); ++index) + { + if (program.input_attributes & (1 << index)) + { + result.code += "in vec4 " + rsx::vertex_program::input_registers_table[index] + ";\n"; + } + } + break; + + default: + throw; } result.code += "\n"; diff --git a/rsx_decompiler/rsx_fp_decompiler.cpp b/rsx_decompiler/rsx_fp_decompiler.cpp index d2deee9..ab3ed38 100644 --- a/rsx_decompiler/rsx_fp_decompiler.cpp +++ b/rsx_decompiler/rsx_fp_decompiler.cpp @@ -267,8 +267,6 @@ namespace rsx expression_from> execution_condition(condition_operation operation) { - auto cond = execution_condition_register(); - if (instruction.data.src0.exec_if_gr && instruction.data.src0.exec_if_eq && instruction.data.src0.exec_if_gr) { return true; @@ -279,6 +277,8 @@ namespace rsx return false; } + auto cond = execution_condition_register(); + if (instruction.data.src0.cond_swizzle_x == instruction.data.src0.cond_swizzle_y && instruction.data.src0.cond_swizzle_y == instruction.data.src0.cond_swizzle_z && instruction.data.src0.cond_swizzle_z == instruction.data.src0.cond_swizzle_w) @@ -417,7 +417,7 @@ namespace rsx if (!instruction.data.dst.set_cond && instruction.data.dst.no_dest) { //condition must be already handled in instruction semantic (IFE, LOOP, etc) - result += comment("WARNING: extra condition test skipped"); + result += warning("extra condition test skipped"); result += arg; } else @@ -432,7 +432,7 @@ namespace rsx if (instruction.data.dst.mask_z) condition_map[cond.mask[2]].push_back({ 2, channel_index++ }); if (instruction.data.dst.mask_w) condition_map[cond.mask[3]].push_back({ 3, channel_index }); - auto src = arg; + auto src = apply_instruction_modifiers(arg); if (flags & disable_swizzle_as_dst) { diff --git a/rsx_decompiler/rsx_vp_decompiler.cpp b/rsx_decompiler/rsx_vp_decompiler.cpp index 3790cc5..801b71c 100644 --- a/rsx_decompiler/rsx_vp_decompiler.cpp +++ b/rsx_decompiler/rsx_vp_decompiler.cpp @@ -1,6 +1,7 @@ #include "rsx_decompiler.h" #include #include "rsx_decompiler_base.h" +#include namespace rsx { @@ -11,6 +12,72 @@ namespace rsx struct context_t { decompiled_program program; + + std::string address_register(u32 address_register) + { + register_info info; + info.id = address_register; + info.name = "a" + std::to_string(info.id); + info.type = register_type::integer; + program.temporary_registers.insert(info); + + return info.name; + } + + std::string address_mask(u32 swizzle) + { + return std::string(1, mask[swizzle]); + } + + float_point_expr<4> constant(u32 id, u32 index_constant, u32 address_register_, u32 swizzle) + { + constant_info info; + info.id = 468; + info.name = "vc[468]"; + program.constants.insert(info); + + return "vc[" + std::to_string(id) + + (index_constant ? " + " + address_register(address_register_) + "." + address_mask(swizzle) : "") + + "]"; + } + + 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 = "o" + std::to_string(index); + program.temporary_registers.insert(info); + return info.name; + } + + float_point_expr<4> temporary(u32 index) + { + register_info info; + info.id = index; + info.type = register_type::single_float_point; + info.name = "r" + std::to_string(index); + program.temporary_registers.insert(info); + return info.name; + } + + float_point_expr<4> condition(int index) + { + register_info info; + info.id = index; + info.type = register_type::single_float_point; + info.name = "rc" + std::to_string(index); + program.temporary_registers.insert(info); + + return info.name; + } + + float_point_expr<4> input(int index) + { + program.input_attributes |= (1 << index); + return input_registers_table[index]; + } }; public: @@ -18,6 +85,33 @@ namespace rsx { ucode_instr data; + SRC unpack_src(int index) const + { + SRC result; + + switch (index) + { + case 0: + result.src0l = data.d2.src0l; + result.src0h = data.d1.src0h; + break; + + case 1: + result.src1 = data.d2.src1; + break; + + case 2: + result.src2l = data.d3.src2l; + result.src2h = data.d2.src2h; + break; + + default: + throw; + } + + return result; + } + static u32 swap_endianess(u32 data) { return @@ -27,7 +121,7 @@ namespace rsx ((data << 24) & 0xff000000); } - instruction_t unpack() + instruction_t unpack() const { instruction_t result; @@ -42,31 +136,511 @@ namespace rsx static_assert(sizeof(instruction_t) == 16, "Bad instruction_t implementation"); + private: instruction_t instruction; context_t context; + bool is_vec; + u32 temporary_destination_register_index() const + { + if (is_vec) + { + return instruction.data.d0.dst_tmp; + } + + return instruction.data.d3.sca_dst_tmp; + } + + u32 address_value() const + { + return (instruction.data.d2.iaddrh << 3) | instruction.data.d3.iaddrl; + } + + integer_expr<1> address_register() + { + return{ context.address_register(instruction.data.d0.addr_reg_sel_1), context.address_mask(instruction.data.d0.addr_swz), true, 4 }; + } + + expression_from> swizzle_as_dst(expression_from> arg) const + { + std::string arg_mask; + + for (char channel : destination_swizzle()) + { + arg_mask += arg.mask[channel_to_index.at(channel)]; + } + + return expression_from>(arg.text, arg_mask, arg.is_single, arg.base_count); + } + + float_point_expr<4> src(int index, bool is_swizzle_as_dst = false) + { + SRC src = instruction.unpack_src(index); + + u32 is_abs; + + switch (index) + { + case 0: is_abs = instruction.data.d0.src0_abs; break; + case 1: is_abs = instruction.data.d0.src1_abs; break; + case 2: is_abs = instruction.data.d0.src2_abs; break; + } + + auto get_register = [&]() + { + switch (src.register_type) + { + case src_register_type::temporary: + return context.temporary(src.tmp_src); + + case src_register_type::input: + return context.input(instruction.data.d1.input_src); + + case src_register_type::constant: + return context.constant(instruction.data.d1.const_src, + instruction.data.d3.index_const, + instruction.data.d0.addr_reg_sel_1, + instruction.data.d0.addr_swz); + } + + throw; + }; + + float_point_expr<4> result = get_register(); + + result.assign(result.swizzle(src.swz_x, src.swz_y, src.swz_z, src.swz_w)); + + if (is_swizzle_as_dst) + { + result.assign(swizzle_as_dst(result)); + } + + if (is_abs) + { + result.assign(abs(result)); + } + + if (src.neg) + { + result.assign(-result); + } + + return result; + } + + float_point_expr<4> src_swizzled_as_dst(int index) + { + return src(index, true); + } + + std::string destination_swizzle() const + { + std::string result; + + if (is_vec) + { + if (instruction.data.d3.vec_writemask_x) result += "x"; + if (instruction.data.d3.vec_writemask_y) result += "y"; + if (instruction.data.d3.vec_writemask_z) result += "z"; + if (instruction.data.d3.vec_writemask_w) result += "w"; + } + else + { + if (instruction.data.d3.sca_writemask_x) result += "x"; + if (instruction.data.d3.sca_writemask_y) result += "y"; + if (instruction.data.d3.sca_writemask_z) result += "z"; + if (instruction.data.d3.sca_writemask_w) result += "w"; + } + + return result; + } + + std::pair> destination_register() + { + if (is_vec && instruction.data.d0.vec_result) + { + return{ true, { context.output(instruction.data.d3.dst).text, destination_swizzle() } }; + } + + u32 tmp = temporary_destination_register_index(); + bool no_dest = tmp == 63; + + if (no_dest) + { + return{ false, {} }; + } + + return{ true,{ context.temporary(tmp).text, destination_swizzle() } }; + } + + float_point_expr<4> update_condition_register() + { + return{ context.condition(instruction.data.d0.cond_reg_sel_1).text, destination_swizzle() }; + } + float_point_expr<4> execution_condition_register() + { + std::string swizzle; + + swizzle += mask[instruction.data.d0.mask_x]; + swizzle += mask[instruction.data.d0.mask_y]; + swizzle += mask[instruction.data.d0.mask_z]; + swizzle += mask[instruction.data.d0.mask_w]; + + return{ context.condition(instruction.data.d0.cond_reg_sel_1).text, swizzle }; + } + + boolean_expr<4> compare(compare_function function, float_point_expr<4> a, float_point_expr<4> b) + { + return custom_compare(function, (int)destination_swizzle().size(), a, b); + } + + float_point_expr<4> apply_instruction_modifiers(float_point_expr<4> arg) + { + if (instruction.data.d0.staturate) + { + return clamp(arg, -1.0f, 1.0f); + } + + return arg; + } + + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + + always = (lt | eq | gt), + never = 0 + }; + + writer_t set_dst(float_point_expr<4> arg) + { + auto dst_pair = destination_register(); + bool has_dst = dst_pair.first; + bool has_result = has_dst || (instruction.data.d0.cond_update_enable_0 && instruction.data.d0.cond_update_enable_1); + float_point_expr<4> dest{ dst_pair.second }; + + writer_t result; + + if (instruction.data.d0.cond_test_enable && instruction.data.d0.cond != always) + { + if (!has_result) + { + result += warning("Extra condition skipped"); + result += arg; + } + else + { + static const std::string operations[0x8] = + { + "error", + "<", + "==", + "<=", + ">", + "!=", + ">=", + "error" + }; + + auto cond = execution_condition_register(); + std::string operation = operations[instruction.data.d0.cond]; + static const float_point_expr<1> zero(0.0f); + + std::map>> condition_map; + + int channel_index = 0; + + if (is_vec) + { + if (instruction.data.d3.vec_writemask_x) condition_map[cond.mask[0]].push_back({ 0, channel_index++ }); + if (instruction.data.d3.vec_writemask_y) condition_map[cond.mask[0]].push_back({ 1, channel_index++ }); + if (instruction.data.d3.vec_writemask_z) condition_map[cond.mask[0]].push_back({ 2, channel_index++ }); + if (instruction.data.d3.vec_writemask_w) condition_map[cond.mask[0]].push_back({ 3, channel_index }); + } + else + { + if (instruction.data.d3.sca_writemask_x) condition_map[cond.mask[0]].push_back({ 0, channel_index++ }); + if (instruction.data.d3.sca_writemask_y) condition_map[cond.mask[0]].push_back({ 1, channel_index++ }); + if (instruction.data.d3.sca_writemask_z) condition_map[cond.mask[0]].push_back({ 2, channel_index++ }); + if (instruction.data.d3.sca_writemask_w) condition_map[cond.mask[0]].push_back({ 3, channel_index }); + } + + auto src = apply_instruction_modifiers(arg); + + src.assign(float_point_expr<4>(arg.text, arg.mask, true, 4)); + + for (auto &entry : condition_map) + { + std::string src_swizzle; + std::string dst_swizzle; + + for (std::pair channels : entry.second) + { + src_swizzle += src.swizzle(channels.second).mask[0]; + dst_swizzle += dest.swizzle(channels.second).mask[0]; + } + + float_point_expr<4> expression{ src.with_mask(src_swizzle) }; + + if (has_dst) + { + expression.assign(dest.with_mask(dst_swizzle) = expression); + } + + if (instruction.data.d0.cond_update_enable_0 && instruction.data.d0.cond_update_enable_1) + { + expression.assign(cond.with_mask(dst_swizzle) = expression); + } + + result += if_(cond.swizzle(channel_to_index.at(entry.first)).call_operator>(operation, zero), expression); + } + } + } + else + { + float_point_expr<4> expression{ apply_instruction_modifiers(arg.without_scope()) }; + + if (has_dst) + { + expression.assign(dest = expression); + } + + if (instruction.data.d0.cond_update_enable_0 && instruction.data.d0.cond_update_enable_1) + { + expression.assign(update_condition_register() = expression); + } + + result += expression; + } + + return result; + } + + writer_t set_dst(expression_from> arg) + { + if (destination_swizzle().size() != 1) + { + return set_dst(float_point_t<4>::ctor(arg)); + } + + return set_dst(float_point_expr<4>{ arg.to_string() }); + } + + writer_t set_dst(boolean_expr<4> arg) + { + std::string arg_string; + + bool is_single = true; + + switch (destination_swizzle().size()) + { + case 1: arg_string = arg.to_string() + " ? 1.0 : 0.0"; is_single = false; break; + case 2: arg_string = float_point_t<2>::ctor(boolean_expr<2>{ arg.to_string() }).to_string(); break; + case 3: arg_string = float_point_t<3>::ctor(boolean_expr<3>{ arg.to_string() }).to_string(); break; + case 4: arg_string = float_point_t<4>::ctor(boolean_expr<4>{ arg.to_string() }).to_string(); break; + + default: + throw; + } + + return set_dst(float_point_expr<4>{ arg_string, std::string("xyzw"), is_single, 4 }); + } + + enum class condition_operation + { + all, + any + }; + + compare_function execution_condition_function() const + { + switch (instruction.data.d0.cond) + { + case gt | eq: return compare_function::greater_equal; + case lt | eq: return compare_function::less_equal; + case lt | gt: return compare_function::not_equal; + case gt: return compare_function::greater; + case lt: return compare_function::less; + case eq: return compare_function::equal; + } + + throw; + } + + boolean_expr<1> execution_condition(condition_operation operation) + { + if (instruction.data.d0.cond == always) + { + return true; + } + + if (instruction.data.d0.cond == never) + { + return false; + } + + auto cond = execution_condition_register(); + + if (instruction.data.d0.mask_x == instruction.data.d0.mask_y && + instruction.data.d0.mask_y == instruction.data.d0.mask_z && + instruction.data.d0.mask_z == instruction.data.d0.mask_w) + { + return custom_compare(execution_condition_function(), 1, cond.x(), expression_from>(0.0f)); + } + + auto result = custom_compare(execution_condition_function(), 4, cond, float_point_t<4>::ctor(0.0f)); + + switch (operation) + { + case condition_operation::all: return all(result); + case condition_operation::any: return any(result); + } + + throw; + } + + template + expression_from conditional(const ExprType& expr) + { + bool need_condition = false; + + if (need_condition) + { + return if_(any(execution_condition(condition_operation::any)), expr); + } + + return expr; + } + + expression_base_t decode_sca_instruction() + { + is_vec = false; + + switch (instruction.data.d1.sca_opcode) + { + case sca_opcode::mov: return set_dst(src_swizzled_as_dst(2)); + case sca_opcode::rcp: return set_dst(float_point_t<1>::ctor(1.0f) / src_swizzled_as_dst(2)); + case sca_opcode::rcc: return set_dst(clamp(float_point_t<1>::ctor(1.0f) / src_swizzled_as_dst(2), 5.42101e-20f, 1.884467e19f)); + case sca_opcode::rsq: return set_dst(rsqrt(src_swizzled_as_dst(2))); + case sca_opcode::exp: return set_dst(exp(src_swizzled_as_dst(2))); + case sca_opcode::log: return set_dst(log(src_swizzled_as_dst(2))); + case sca_opcode::lit: + { + auto t = src(2); + + float_point_expr<1> z_value{ (t.x() > 0.0f).text }; + z_value.assign("(" + z_value.text + " ? " + exp2(t.w() * log2(t.y())).text + " : 0.0)"); + + return set_dst(swizzle_as_dst(float_point_t<4>::ctor(1.0f, t.x(), z_value, 1.0f))); + } + case sca_opcode::bra: break; + case sca_opcode::bri: + { + std::size_t from = writer.position; + std::size_t to = address_value(); + + boolean_expr<1> condition{ execution_condition(condition_operation::all) }; + + if (to > from) + { + writer.before(from, "if (!(" + condition.to_string() + "))\n{\n"); + writer.before(to, "}\n"); + } + else + { + writer.before(from, "}\nwhile (" + condition.to_string() + ");\n"); + writer.before(to, "do\n{\n"); + } + } + return ""; + + case sca_opcode::cal: break; + case sca_opcode::cli: break; + case sca_opcode::ret: return conditional(void_expr{ "return" }); + case sca_opcode::lg2: return set_dst(log2(src_swizzled_as_dst(2))); + case sca_opcode::ex2: return set_dst(exp2(src_swizzled_as_dst(2))); + case sca_opcode::sin: return set_dst(sin(src_swizzled_as_dst(2))); + case sca_opcode::cos: return set_dst(cos(src_swizzled_as_dst(2))); + case sca_opcode::brb: break; + case sca_opcode::clb: break; + case sca_opcode::psh: break; + case sca_opcode::pop: break; + default: + throw; + } + + return unimplemented("sca " + sca_op_names[(int)instruction.data.d1.sca_opcode]); + } + + expression_base_t decode_vec_instruction() + { + is_vec = true; + + switch (instruction.data.d1.vec_opcode) + { + case vec_opcode::mov: return set_dst(src_swizzled_as_dst(0)); + case vec_opcode::mul: return set_dst(src_swizzled_as_dst(0) * src_swizzled_as_dst(1)); + case vec_opcode::add: return set_dst(src_swizzled_as_dst(0) + src_swizzled_as_dst(2)); + case vec_opcode::mad: return set_dst(src_swizzled_as_dst(0) * src_swizzled_as_dst(1).without_scope() + src_swizzled_as_dst(2)); + case vec_opcode::dp3: return set_dst(dot(src(0).xyz(), src(1).xyz())); + case vec_opcode::dph: break; + case vec_opcode::dp4: return set_dst(dot(src(0), src(1))); + case vec_opcode::dst: break; + case vec_opcode::min: return set_dst(min(src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::max: return set_dst(max(src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::slt: return set_dst(compare(compare_function::less, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::sge: return set_dst(compare(compare_function::greater_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::arl: return writer_t{} += address_register() = integer_t<1>::ctor(src(0).x()); + case vec_opcode::frc: return set_dst(fract(src_swizzled_as_dst(0))); + case vec_opcode::flr: return set_dst(floor(src_swizzled_as_dst(0)));; + case vec_opcode::seq: return set_dst(compare(compare_function::equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::sfl: return set_dst(0.0f); + case vec_opcode::sgt: return set_dst(compare(compare_function::greater, src_swizzled_as_dst(0), src_swizzled_as_dst(1)));; + case vec_opcode::sle: return set_dst(compare(compare_function::less_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::sne: return set_dst(compare(compare_function::not_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1))); + case vec_opcode::str: return set_dst(1.0f); + case vec_opcode::ssg: break; + case vec_opcode::txl: break; + + default: + throw; + } + + return unimplemented("vec " + vec_op_names[(int)instruction.data.d1.vec_opcode]); + } + + expression_base_t decode_instruction() + { + if (instruction.data.d1.sca_opcode == sca_opcode::nop && instruction.data.d1.vec_opcode == vec_opcode::nop) + { + return comment("NOP"); + } + + writer_t result; + + if (instruction.data.d1.sca_opcode != sca_opcode::nop) + { + result += decode_sca_instruction(); + } + + if (instruction.data.d1.vec_opcode != vec_opcode::nop) + { + result += decode_vec_instruction(); + } + + return result; + } + + public: decompiled_program decompile(std::size_t offset, instruction_t *instructions) { for (std::size_t i = offset; i < 512; ++i, writer.next()) { instruction = instructions[i].unpack(); - if (instruction.data.d1.sca_opcode == sca_opcode::nop && instruction.data.d1.vec_opcode == vec_opcode::nop) - { - writer += comment("NOP"); - } - else - { - if (instruction.data.d1.sca_opcode != sca_opcode::nop) - { - writer += comment(sca_op_names[(int)instruction.data.d1.sca_opcode]); - } - - if (instruction.data.d1.vec_opcode != vec_opcode::nop) - { - writer += comment(vec_op_names[(int)instruction.data.d1.vec_opcode]); - } - } + writer += decode_instruction(); if (instruction.data.d3.end) break; @@ -105,4 +679,4 @@ namespace rsx return result; } } -} \ No newline at end of file +} diff --git a/rsx_decompiler/rsx_vp_ucode.cpp b/rsx_decompiler/rsx_vp_ucode.cpp index 0e0441e..f54e9a5 100644 --- a/rsx_decompiler/rsx_vp_ucode.cpp +++ b/rsx_decompiler/rsx_vp_ucode.cpp @@ -4,6 +4,16 @@ namespace rsx { namespace vertex_program { + const std::string input_registers_table[0x10] = + { + "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" + }; + 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 b07e9e3..7317feb 100644 --- a/rsx_decompiler/rsx_vp_ucode.h +++ b/rsx_decompiler/rsx_vp_ucode.h @@ -7,7 +7,7 @@ namespace rsx namespace vertex_program { using u32 = std::uint32_t; - enum class sca_opcode + enum class sca_opcode : u32 { nop = 0x00, mov = 0x01, @@ -32,7 +32,7 @@ namespace rsx pop = 0x14 }; - enum class vec_opcode + enum class vec_opcode : u32 { nop = 0x00, mov = 0x01, @@ -60,6 +60,13 @@ namespace rsx txl = 0x19 }; + enum class src_register_type : u32 + { + temporary = 1, + input = 2, + constant = 3 + }; + union D0 { u32 _u32; @@ -173,7 +180,7 @@ namespace rsx struct { - u32 reg_type : 2; + src_register_type register_type : 2; u32 tmp_src : 6; u32 swz_w : 2; u32 swz_z : 2; @@ -191,6 +198,7 @@ namespace rsx D3 d3; }; + extern const std::string input_registers_table[0x10]; extern const std::string sca_op_names[0x20]; extern const std::string vec_op_names[0x20]; } diff --git a/rsx_program_decompiler/rsx_program_decompiler.cpp b/rsx_program_decompiler/rsx_program_decompiler.cpp index 39f761a..3733b00 100644 --- a/rsx_program_decompiler/rsx_program_decompiler.cpp +++ b/rsx_program_decompiler/rsx_program_decompiler.cpp @@ -328,16 +328,18 @@ int main(int argc, char** argv) if (0) { + using namespace rsx::fragment_program; std::vector file = load_file("tmp.fp.ucode"); - rsx::fragment_program::ucode_instr *instructions = (rsx::fragment_program::ucode_instr *)file.data(); - program = rsx::fragment_program::decompile(0, instructions, rsx::decompile_language::glsl); + ucode_instr *instructions = (ucode_instr *)file.data(); + program = decompile(0, instructions, rsx::decompile_language::glsl); } else { + using namespace rsx::vertex_program; std::vector file = load_file("tmp.vp.ucode"); - rsx::vertex_program::ucode_instr *instructions = (rsx::vertex_program::ucode_instr *)file.data(); + ucode_instr *instructions = (ucode_instr *)file.data(); program = rsx::vertex_program::decompile(0, instructions, rsx::decompile_language::glsl); } diff --git a/shader_code/clike_builder.h b/shader_code/clike_builder.h index 68989cc..a34af5c 100644 --- a/shader_code/clike_builder.h +++ b/shader_code/clike_builder.h @@ -153,6 +153,11 @@ namespace shader_code template using float_point_t = typename type_t; + using void_expr = expression_from; + template using float_point_expr = expression_from>; + template using boolean_expr = expression_from>; + template using integer_expr = expression_from>; + static expression_from> texture(const expression_from& texture, const expression_from>& coord) { return function_t, language::function_name_t>::invoke(texture, coord); @@ -308,6 +313,16 @@ namespace shader_code return function_t, language::function_name_t>::invoke(a, b); } template + static expression_from> exp(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> log(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template static expression_from> exp2(const expression_t& arg) { return function_t, language::function_name_t>::invoke(arg); diff --git a/shader_code/clike_language.h b/shader_code/clike_language.h index 6ca959b..5dfad32 100644 --- a/shader_code/clike_language.h +++ b/shader_code/clike_language.h @@ -88,6 +88,8 @@ namespace shader_code function_abs, function_fract, function_floor, + function_exp, + function_log, function_exp2, function_log2, function_pow, @@ -131,6 +133,8 @@ namespace shader_code bool is_single; int base_count = Count; + expression_helper_t() = default; + expression_helper_t(const std::string& text, bool is_single = true, int base_count = Count) : expression_base_t{ text } , is_single(is_single) diff --git a/shader_code/glsl_language.h b/shader_code/glsl_language.h index b80eba8..c75aa70 100644 --- a/shader_code/glsl_language.h +++ b/shader_code/glsl_language.h @@ -253,6 +253,18 @@ namespace shader_code static constexpr char *name = "inversesqrt"; }; + template<> + struct function_name_t + { + static constexpr char *name = "exp"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "log"; + }; + template<> struct function_name_t {