mirror of
https://github.com/RPCS3/rsx_program_decompiler.git
synced 2026-01-31 01:25:19 +01:00
Implemented vertex program decompiler
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -267,8 +267,6 @@ namespace rsx
|
||||
|
||||
expression_from<boolean_t<1>> 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)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "rsx_decompiler.h"
|
||||
#include <glsl_language.h>
|
||||
#include "rsx_decompiler_base.h"
|
||||
#include <map>
|
||||
|
||||
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<float_point_t<4>> swizzle_as_dst(expression_from<float_point_t<4>> arg) const
|
||||
{
|
||||
std::string arg_mask;
|
||||
|
||||
for (char channel : destination_swizzle())
|
||||
{
|
||||
arg_mask += arg.mask[channel_to_index.at(channel)];
|
||||
}
|
||||
|
||||
return expression_from<float_point_t<4>>(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<bool, float_point_expr<4>> 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<char, std::vector<std::pair<int, int>>> 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<int, int> 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<boolean_t<1>>(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<float_point_t<1>> 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<float_point_t<1>>(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<typename ExprType>
|
||||
expression_from<void_t> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -328,16 +328,18 @@ int main(int argc, char** argv)
|
||||
|
||||
if (0)
|
||||
{
|
||||
using namespace rsx::fragment_program;
|
||||
std::vector<char> 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<char> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,11 @@ namespace shader_code
|
||||
template<size_t Count>
|
||||
using float_point_t = typename type_t<type_class_t::type_float, Count>;
|
||||
|
||||
using void_expr = expression_from<void_t>;
|
||||
template<int Count> using float_point_expr = expression_from<float_point_t<Count>>;
|
||||
template<int Count> using boolean_expr = expression_from<boolean_t<Count>>;
|
||||
template<int Count> using integer_expr = expression_from<integer_t<Count>>;
|
||||
|
||||
static expression_from<float_point_t<4>> texture(const expression_from<sampler1D_t>& texture, const expression_from<float_point_t<1>>& coord)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
@@ -308,6 +313,16 @@ namespace shader_code
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_pow>>::invoke(a, b);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> exp(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_exp>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> log(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_log>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> exp2(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_exp2>>::invoke(arg);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -253,6 +253,18 @@ namespace shader_code
|
||||
static constexpr char *name = "inversesqrt";
|
||||
};
|
||||
|
||||
template<>
|
||||
struct function_name_t<clike_language::function_class_t::function_exp>
|
||||
{
|
||||
static constexpr char *name = "exp";
|
||||
};
|
||||
|
||||
template<>
|
||||
struct function_name_t<clike_language::function_class_t::function_log>
|
||||
{
|
||||
static constexpr char *name = "log";
|
||||
};
|
||||
|
||||
template<>
|
||||
struct function_name_t<clike_language::function_class_t::function_exp2>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user