mirror of
https://github.com/RPCS3/rsx_program_decompiler.git
synced 2026-07-19 13:27:51 -04:00
Implemented IFE, LOOP instructions
Added operator- deduction Fixed loading big ucode files Minor fixes
This commit is contained in:
@@ -10,13 +10,15 @@
|
||||
template<typename DecompilerType>
|
||||
int process_ucode(const std::string& ipath, const std::string& opath)
|
||||
{
|
||||
if (auto &ifile_stream = std::ifstream{ ipath, std::ios::binary })
|
||||
if (auto &ifile_stream = std::ifstream{ ipath, std::ios::binary | std::ios::ate })
|
||||
{
|
||||
if (auto &ofile_stream = std::ofstream{ opath })
|
||||
{
|
||||
u32 buffer[512 * 4];
|
||||
u32 size = ifile_stream.read((char*)buffer, sizeof(buffer)).gcount();
|
||||
auto info = DecompilerType{ buffer, size }.decompile();
|
||||
std::vector<char> buffer(ifile_stream.tellg());
|
||||
ifile_stream.seekg(0);
|
||||
|
||||
ifile_stream.read(buffer.data(), buffer.size());
|
||||
auto info = DecompilerType{ buffer.data(), (u32)buffer.size() }.decompile();
|
||||
ofile_stream << info.text;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace rsx
|
||||
using FENCB = instruction < opcode::FENCB, suffix_none >;
|
||||
using BRK = instruction < opcode::BRK, suffix_none, arg<addr> >;
|
||||
using CAL = instruction < opcode::CAL, suffix_none, arg<addr> >;
|
||||
using IFE = instruction < opcode::IFE, H >;
|
||||
using IFE = instruction < opcode::IFE, suffix_none, arg<cond> >;
|
||||
using LOOP = instruction < opcode::LOOP, H >;
|
||||
using REP = instruction < opcode::REP, H >;
|
||||
using RET = instruction < opcode::RET, H >;
|
||||
@@ -148,8 +148,7 @@ namespace rsx
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static void function(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
if (id != opcode::FENCT && id != opcode::FENCT)
|
||||
throw std::runtime_error("unimplemented instruction: " + instructions_names[(std::size_t)id]);
|
||||
decompiler.nodest_instruction<id, flags>(decompiler.arg<args_type>()...);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -220,6 +219,8 @@ namespace rsx
|
||||
swizzle_y = src.swizzle_y;
|
||||
swizzle_z = src.swizzle_z;
|
||||
swizzle_w = src.swizzle_w;
|
||||
variable.is_abs = src.abs;
|
||||
variable.is_neg = src.neg;
|
||||
};
|
||||
|
||||
switch (index)
|
||||
@@ -317,7 +318,7 @@ namespace rsx
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
return decompiler.execution_condition();
|
||||
return decompiler.execution_condition_register();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -384,7 +385,7 @@ namespace rsx
|
||||
return expand_arg_t<T>::impl(*this);
|
||||
}
|
||||
|
||||
program_variable update_condition()
|
||||
program_variable update_condition_register()
|
||||
{
|
||||
program_variable result = {};
|
||||
|
||||
@@ -396,7 +397,7 @@ namespace rsx
|
||||
return info.vars.add(result);
|
||||
}
|
||||
|
||||
program_variable execution_condition()
|
||||
program_variable execution_condition_register(bool exclusive_channels_only = false)
|
||||
{
|
||||
program_variable result = {};
|
||||
|
||||
@@ -407,19 +408,37 @@ namespace rsx
|
||||
static const std::string mask = "xyzw";
|
||||
|
||||
std::string swizzle;
|
||||
swizzle += mask[ucode.src0.cond_swizzle_x];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_y];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_z];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_w];
|
||||
|
||||
if (exclusive_channels_only)
|
||||
{
|
||||
swizzle += mask[ucode.src0.cond_swizzle_x];
|
||||
if (ucode.src0.cond_swizzle_x != ucode.src0.cond_swizzle_y)
|
||||
swizzle += mask[ucode.src0.cond_swizzle_y];
|
||||
|
||||
if (ucode.src0.cond_swizzle_z != ucode.src0.cond_swizzle_x && ucode.src0.cond_swizzle_z != ucode.src0.cond_swizzle_y)
|
||||
swizzle += mask[ucode.src0.cond_swizzle_z];
|
||||
|
||||
if (ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_x &&
|
||||
ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_y &&
|
||||
ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_z)
|
||||
swizzle += mask[ucode.src0.cond_swizzle_w];
|
||||
}
|
||||
else
|
||||
{
|
||||
swizzle += mask[ucode.src0.cond_swizzle_x];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_y];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_z];
|
||||
swizzle += mask[ucode.src0.cond_swizzle_w];
|
||||
}
|
||||
|
||||
result.mask.add(swizzle);
|
||||
|
||||
return info.vars.add(result);
|
||||
}
|
||||
|
||||
void set_code_line(const std::string &code_line)
|
||||
void set_code_line(const std::string &code_line, int tab_before = 0, int tab_after = 0, bool to_end = true)
|
||||
{
|
||||
program_decompiler_core::builder.add_code_block(ucode_index, code_line);
|
||||
program_decompiler_core::builder.add_code_block(ucode_index, code_line, tab_before, tab_after, to_end);
|
||||
}
|
||||
|
||||
template<opcode id, u32 flags, int count>
|
||||
@@ -428,6 +447,15 @@ namespace rsx
|
||||
set_code_line(decompiler_impl::set_dst<id, flags, count>(this, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
template<opcode id, u32 flags>
|
||||
void nodest_instruction(const program_variable& arg0 = {}, const program_variable& arg1 = {}, const program_variable& arg2 = {})
|
||||
{
|
||||
if (id != opcode::FENCT && id != opcode::FENCB)
|
||||
{
|
||||
decompiler_impl::nodest_instruction<id, flags>(this, arg0, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void unknown_instruction(opcode op)
|
||||
{
|
||||
throw std::runtime_error("unimplemented instruction '" + instructions_names[(std::size_t)op] + "' (" + std::to_string((std::size_t)op) + ") #"
|
||||
|
||||
@@ -122,6 +122,62 @@ namespace rsx
|
||||
return "}";
|
||||
}
|
||||
|
||||
__forceinline static std::string execution_condition(decompiler* dec)
|
||||
{
|
||||
if (dec->ucode.src0.exec_if_gr &&
|
||||
dec->ucode.src0.exec_if_lt &&
|
||||
dec->ucode.src0.exec_if_eq)
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
if (!dec->ucode.src0.exec_if_gr &&
|
||||
!dec->ucode.src0.exec_if_lt &&
|
||||
!dec->ucode.src0.exec_if_eq)
|
||||
{
|
||||
return "if (false) ";
|
||||
}
|
||||
|
||||
program_variable execution_condition = dec->execution_condition_register(true);
|
||||
|
||||
if (execution_condition.mask.to_string().size() == 1)
|
||||
{
|
||||
std::string execution_condition_operation;
|
||||
|
||||
if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_operation = ">=";
|
||||
else if (dec->ucode.src0.exec_if_lt && dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_operation = "<=";
|
||||
else if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_lt)
|
||||
execution_condition_operation = "!=";
|
||||
else if (dec->ucode.src0.exec_if_gr)
|
||||
execution_condition_operation = ">";
|
||||
else if (dec->ucode.src0.exec_if_lt)
|
||||
execution_condition_operation = "<";
|
||||
else //if(dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_operation = "==";
|
||||
|
||||
return "if (" + execution_condition.to_string() + " " + execution_condition_operation + " 0.0f) ";
|
||||
}
|
||||
|
||||
std::string execution_condition_function;
|
||||
|
||||
if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_function = "greaterThanEquals";
|
||||
else if (dec->ucode.src0.exec_if_lt && dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_function = "lessThanEquals";
|
||||
else if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_lt)
|
||||
execution_condition_function = "notEquals";
|
||||
else if (dec->ucode.src0.exec_if_gr)
|
||||
execution_condition_function = "greaterThan";
|
||||
else if (dec->ucode.src0.exec_if_lt)
|
||||
execution_condition_function = "lessThan";
|
||||
else //if(dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_function = "equals";
|
||||
|
||||
return "if (any(" + execution_condition_function + "(" + execution_condition.to_string() + ", " + " vec4(0.0f)))) ";
|
||||
}
|
||||
|
||||
template<opcode id, u32 flags, int count>
|
||||
__forceinline static std::string set_dst(decompiler* dec, const program_variable& arg0, const program_variable& arg1, const program_variable& arg2)
|
||||
{
|
||||
@@ -146,7 +202,7 @@ namespace rsx
|
||||
"?", "?", "?", "?", "fma", "dot", "dot",
|
||||
"distantion", "min", "max", "lessThan", "greaterThanEquals", "lessThanEqual", "greaterThan",
|
||||
"notEqual", "equal", "fract", "floor", "?", "pk4", "up4",
|
||||
"ddx", "ddy", "texture", "txp", "txd", "rcp", "rsq",
|
||||
"dFdx", "dFdy", "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", "?",
|
||||
@@ -161,7 +217,6 @@ namespace rsx
|
||||
{
|
||||
case opcode::MOV:
|
||||
case opcode::MUL:
|
||||
case opcode::ADD:
|
||||
case opcode::DIV:
|
||||
//operators
|
||||
|
||||
@@ -171,13 +226,28 @@ namespace rsx
|
||||
|
||||
if (!arg1.is_null())
|
||||
{
|
||||
value = "(" + value + " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1) + ")";
|
||||
value += " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case opcode::ADD:
|
||||
{
|
||||
value = variable_to_string(arg0);
|
||||
std::string arg1_string = variable_to_string(arg1);
|
||||
if (arg1_string[0] == '-')
|
||||
{
|
||||
value += " - " + arg1_string.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
value += " + " + arg1_string;
|
||||
}
|
||||
}
|
||||
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:
|
||||
@@ -218,6 +288,23 @@ namespace rsx
|
||||
break;
|
||||
}
|
||||
|
||||
program_variable dst = dec->dst<flags, count>();
|
||||
|
||||
if (id == opcode::SIN || id == opcode::COS)
|
||||
{
|
||||
std::string dst_mask = dst.mask.to_string();
|
||||
|
||||
if (dst_mask.size() != 1)
|
||||
{
|
||||
size_t size = 4;
|
||||
|
||||
if (!dst_mask.empty())
|
||||
size = dst_mask.size();
|
||||
|
||||
value = "vec" + std::to_string(size) + "(" + value + ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & H)
|
||||
{
|
||||
switch (dec->ucode.dst.prec)
|
||||
@@ -229,20 +316,21 @@ namespace rsx
|
||||
value = "clamp(" + value + ", -65536, 65536)";
|
||||
break;
|
||||
|
||||
case 2: //fixed point 12? let it be unimplemented, atm
|
||||
value = "clamp(" + value + ", 0, 0)";
|
||||
case 2: //fixed point 12?
|
||||
value = "clamp(" + value + ", -1, 1)";
|
||||
//throw std::runtime_error("fragment program decompiler: unimplemented precision.");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dec->ucode.src1.scale)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: value = "(" + value + " * 2.0)"; break;
|
||||
case 2: value = "(" + value + " * 4.0)"; break;
|
||||
case 3: value = "(" + value + " * 8.0)"; break;
|
||||
case 5: value = "(" + value + " / 2.0)"; break;
|
||||
case 6: value = "(" + value + " / 4.0)"; break;
|
||||
case 7: value = "(" + value + " / 8.0)"; break;
|
||||
case 1: value = mask_t::append_brackets_if_needed(value) + " * 2.0"; break;
|
||||
case 2: value = mask_t::append_brackets_if_needed(value) + " * 4.0"; break;
|
||||
case 3: value = mask_t::append_brackets_if_needed(value) + " * 8.0"; break;
|
||||
case 5: value = mask_t::append_brackets_if_needed(value) + " / 2.0"; break;
|
||||
case 6: value = mask_t::append_brackets_if_needed(value) + " / 4.0"; break;
|
||||
case 7: value = mask_t::append_brackets_if_needed(value) + " / 8.0"; break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("fragment program decompiler: unimplemented scale (" + std::to_string(dec->ucode.src1.scale) + "). ");
|
||||
@@ -254,14 +342,13 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
std::string result;
|
||||
program_variable dst = dec->dst<flags, count>();
|
||||
program_variable update_condition;
|
||||
std::string result;
|
||||
|
||||
bool do_update_condition = false;
|
||||
if ((flags & C) && dec->ucode.dst.set_cond)
|
||||
{
|
||||
update_condition = dec->update_condition();
|
||||
update_condition = dec->update_condition_register();
|
||||
do_update_condition = !update_condition.is_null();
|
||||
}
|
||||
|
||||
@@ -282,7 +369,7 @@ namespace rsx
|
||||
}
|
||||
else
|
||||
{
|
||||
program_variable execution_condition = dec->execution_condition();
|
||||
program_variable execution_condition = dec->execution_condition_register();
|
||||
mask_t update_mask;
|
||||
update_mask
|
||||
.add(execution_condition.mask.to_string())
|
||||
@@ -306,26 +393,29 @@ namespace rsx
|
||||
else //if(dec->ucode.src0.exec_if_eq)
|
||||
execution_condition_operation = "==";
|
||||
|
||||
fmt::string update_mask_string = update_mask.to_string();
|
||||
std::string update_mask_string = update_mask.to_string();
|
||||
if (update_mask_string.empty())
|
||||
update_mask_string = "xyzw";
|
||||
|
||||
std::string dst_mask = dst.mask.to_string();
|
||||
if (dst_mask.empty())
|
||||
dst_mask = "xyzw";
|
||||
|
||||
std::string last_condition_group;
|
||||
std::string last_line;
|
||||
|
||||
for (char _mask : update_mask_string)
|
||||
for (char _mask : std::string("xyzw").substr(0, update_mask_string.size()))
|
||||
{
|
||||
const std::string mask(1, _mask);
|
||||
const std::string dot_mask = "." + mask;
|
||||
const mask_t mask = mask_t{}.add(std::string(1, _mask));
|
||||
|
||||
auto channel_execution_condition = execution_condition;
|
||||
std::string channel_execution_condition_mask = channel_execution_condition.mask.add(mask).to_string();
|
||||
std::string channel_execution_condition_mask = channel_execution_condition.mask.add(mask.to_string()).to_string();
|
||||
|
||||
if (channel_execution_condition_mask != last_condition_group)
|
||||
{
|
||||
if (!last_condition_group.empty())
|
||||
{
|
||||
result += "}\n\n";
|
||||
result += "}\n";
|
||||
}
|
||||
|
||||
result += "if (" + channel_execution_condition.to_string() + " " + execution_condition_operation + " 0.0f)\n{\n";
|
||||
@@ -338,31 +428,66 @@ namespace rsx
|
||||
if (dst)
|
||||
{
|
||||
auto channel_dst = dst;
|
||||
channel_dst.mask.add(mask);
|
||||
channel_dst.mask = mask_t{}.add(dst_mask).add(mask.to_string());
|
||||
channel_dst_string = channel_dst.to_string();
|
||||
std::string line = "\t" + channel_dst_string + " = " + value + dot_mask + ";\n";
|
||||
std::string line = "\t" + channel_dst_string + " = " + mask.apply_to(value) + ";\n";
|
||||
|
||||
if (last_line == line)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += line;
|
||||
last_line = line;
|
||||
}
|
||||
|
||||
if (do_update_condition)
|
||||
{
|
||||
std::string cond_value = (dst ? channel_dst_string : value) + dot_mask;
|
||||
std::string cond_value = mask.apply_to(dst ? channel_dst_string : value);
|
||||
|
||||
result += "\t" + update_condition.to_string() + dot_mask + " = " + cond_value + ";\n";
|
||||
result += "\t" + mask.apply_to(update_condition.to_string()) + " = " + cond_value + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_condition_group.empty())
|
||||
result += "}\n\n";
|
||||
result += "}\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<opcode id, u32 flags>
|
||||
static void nodest_instruction(decompiler* dec, const program_variable& arg0, const program_variable& arg1, const program_variable& arg2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case opcode::LOOP:
|
||||
dec->set_code_line(fmt::format("for (int i = %d; i < %d; i += %d)\n{",
|
||||
dec->ucode.src1.init_counter, dec->ucode.src1.end_counter, dec->ucode.src1.increment), 0, 1);
|
||||
|
||||
dec->builder.add_code_block(dec->ucode.src2.end_offset >> 2, "}", -1, 0);
|
||||
break;
|
||||
|
||||
case opcode::IFE:
|
||||
dec->set_code_line(execution_condition(dec) + "\n{", 0, 1);
|
||||
|
||||
if (dec->ucode.src1.else_offset != dec->ucode.src2.end_offset)
|
||||
dec->builder.add_code_block(dec->ucode.src1.else_offset >> 2, "}\nelse\n{", -1, 1);
|
||||
|
||||
dec->builder.add_code_block(dec->ucode.src2.end_offset >> 2, "}", -1, 0);
|
||||
break;
|
||||
|
||||
case opcode::BRK:
|
||||
{
|
||||
dec->set_code_line(execution_condition(dec) + "break;");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//break;
|
||||
throw std::runtime_error("unimplemented nodest instruction: " + instructions_names[(std::size_t)id]);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string finalyze(decompiler *dec)
|
||||
{
|
||||
std::string result = "\nvoid main()\n{\n";
|
||||
@@ -374,18 +499,12 @@ namespace rsx
|
||||
bool is_need_declare;
|
||||
};
|
||||
|
||||
struct source_info
|
||||
const std::size_t color_source_registers[] =
|
||||
{
|
||||
std::size_t r_register;
|
||||
std::size_t h_register;
|
||||
};
|
||||
|
||||
const source_info color_source_registers[] =
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 2, 4 },
|
||||
{ 3, 6 },
|
||||
{ 4, 8 }
|
||||
{ 0 },
|
||||
{ 2 },
|
||||
{ 3 },
|
||||
{ 4 }
|
||||
};
|
||||
program_variable color_variable{};
|
||||
color_variable.type = program_variable_type::output;
|
||||
@@ -394,7 +513,7 @@ namespace rsx
|
||||
|
||||
for (u32 i = 0; i < (u32)std::size(color_source_registers); ++i)
|
||||
{
|
||||
std::size_t color_register_index = dec->ctrl & 0x40 ? color_source_registers[i].r_register : color_source_registers[i].h_register;
|
||||
std::size_t color_register_index = dec->ctrl & 0x40 ? color_source_registers[i] : color_source_registers[i] * 2;
|
||||
std::string color_register = (dec->ctrl & 0x40 ? "R" : "H") + std::to_string(color_register_index);
|
||||
if (dec->info.vars.exists(color_register))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "rsx_program_decompiler.h"
|
||||
#include "fmt.h"
|
||||
#include <cctype>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
@@ -82,9 +83,45 @@ namespace rsx
|
||||
if (mask.empty())
|
||||
return expr;
|
||||
|
||||
return expr + "." + mask;
|
||||
return append_brackets_if_needed(expr) + "." + mask;
|
||||
}
|
||||
|
||||
std::string mask_t::append_brackets_if_needed(const std::string& expr)
|
||||
{
|
||||
int opened_brackets = 0;
|
||||
bool has_outside_brackets_op = false;
|
||||
bool is_first_visible_char = false;
|
||||
for (auto c : expr)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '(': ++opened_brackets; break;
|
||||
case ')': --opened_brackets; break;
|
||||
|
||||
case '-':
|
||||
if (is_first_visible_char)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case '+': case '*': case '/':
|
||||
if (opened_brackets == 0)
|
||||
{
|
||||
has_outside_brackets_op = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_first_visible_char && std::isgraph(c))
|
||||
is_first_visible_char = false;
|
||||
}
|
||||
|
||||
if (has_outside_brackets_op)
|
||||
return "(" + expr + ")";
|
||||
|
||||
return expr;
|
||||
};
|
||||
|
||||
std::string program_variable::to_string_impl() const
|
||||
{
|
||||
if (array_size)
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace rsx
|
||||
std::string to_string() const;
|
||||
std::string to_string();
|
||||
|
||||
std::string apply_to(const std::string& std) const;
|
||||
std::string apply_to(const std::string& expr) const;
|
||||
static std::string append_brackets_if_needed(const std::string& expr);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -210,6 +210,8 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="elf64.h" />
|
||||
<ClInclude Include="endianness.h" />
|
||||
<ClInclude Include="fmt.h" />
|
||||
<ClInclude Include="rsx\rsx.h" />
|
||||
<ClInclude Include="rsx\rsx_fragment_program.h" />
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fmt.h" />
|
||||
<ClInclude Include="elf64.h" />
|
||||
<ClInclude Include="endianness.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="rsx\rsx_program_decompiler.cpp">
|
||||
|
||||
Reference in New Issue
Block a user