mirror of
https://github.com/RPCS3/rsx_program_decompiler.git
synced 2026-07-19 13:27:51 -04:00
clang: fixed compilation errors
Cleanup
This commit is contained in:
@@ -8,9 +8,9 @@ namespace rsx
|
||||
const std::unordered_map<char, int> channel_to_index = { { 'x', 0 },{ 'y', 1 },{ 'z', 2 },{ 'w', 3 } };
|
||||
const std::string mask = "xyzw";
|
||||
|
||||
complete_program finalize_program(const decompiled_program& program)
|
||||
complete_shader finalize_program(const decompiled_shader& program)
|
||||
{
|
||||
complete_program result{ "#version 420\n\n" };
|
||||
complete_shader result{ "#version 420\n\n" };
|
||||
|
||||
for (const constant_info& constant : program.constants)
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace rsx
|
||||
fragment
|
||||
};
|
||||
|
||||
struct decompiled_program
|
||||
struct decompiled_shader
|
||||
{
|
||||
program_type type;
|
||||
decompile_language code_language;
|
||||
@@ -105,28 +105,31 @@ namespace rsx
|
||||
|
||||
std::string entry_function;
|
||||
std::string code;
|
||||
|
||||
std::uint64_t ucode_hash;
|
||||
};
|
||||
|
||||
struct complete_program
|
||||
struct complete_shader
|
||||
{
|
||||
std::string code;
|
||||
std::uint64_t ucode_hash;
|
||||
};
|
||||
|
||||
extern const std::string index_to_channel[4];
|
||||
extern const std::unordered_map<char, int> channel_to_index;
|
||||
extern const std::string mask;
|
||||
|
||||
complete_program finalize_program(const decompiled_program& program);
|
||||
complete_shader finalize_program(const decompiled_shader& program);
|
||||
|
||||
|
||||
namespace fragment_program
|
||||
{
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang);
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang);
|
||||
}
|
||||
|
||||
namespace vertex_program
|
||||
{
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang);
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,51 +100,52 @@
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<IncludePath>$(SolutionDir)shader_code\;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)shader_code/;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib/$(Platform)-$(Configuration)/;$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp/$(ProjectName)/$(Platform)-$(Configuration)/</IntDir>
|
||||
<OutDir>$(SolutionDir)lib/$(Platform)-$(Configuration)/</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -160,6 +161,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -175,6 +177,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -190,6 +193,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -205,6 +209,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -220,6 +225,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="rsx_decompiler.cpp" />
|
||||
<ClCompile Include="rsx_fp_ucode.cpp" />
|
||||
|
||||
@@ -5,10 +5,14 @@
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
using namespace shader_code;
|
||||
|
||||
template<typename Language>
|
||||
struct decompiler_base : shader_code::clike_builder<Language>
|
||||
struct decompiler_base : clike_builder<Language>
|
||||
{
|
||||
writer_t writer;
|
||||
using base = clike_builder<Language>;
|
||||
|
||||
builder::writer_t writer;
|
||||
|
||||
enum class compare_function
|
||||
{
|
||||
@@ -20,8 +24,9 @@ namespace rsx
|
||||
not_equal
|
||||
};
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> single_compare_function(compare_function function, expression_t<Type, Count> a, expression_t<Type, Count> b)
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static typename base::boolean_expr<Count> single_compare_function(compare_function function,
|
||||
typename base::expression_t<Type, Count> a, typename base::expression_t<Type, Count> b)
|
||||
{
|
||||
std::string operator_string;
|
||||
|
||||
@@ -41,24 +46,26 @@ namespace rsx
|
||||
return a.to_string() + " " + operator_string + " " + b.to_string();
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> vector_compare_function(compare_function function, expression_t<Type, Count> a, expression_t<Type, Count> b)
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static typename base::boolean_expr<Count> vector_compare_function(compare_function function,
|
||||
typename base::expression_t<Type, Count> a, typename base::expression_t<Type, Count> b)
|
||||
{
|
||||
switch (function)
|
||||
{
|
||||
case compare_function::less: return less(a, b);
|
||||
case compare_function::greater: return greater(a, b);
|
||||
case compare_function::equal: return equal(a, b);
|
||||
case compare_function::less_equal: return less_equal(a, b);
|
||||
case compare_function::greater_equal: return greater_equal(a, b);
|
||||
case compare_function::not_equal: return not_equal(a, b);
|
||||
case compare_function::less: return base::less(a, b);
|
||||
case compare_function::greater: return base::greater(a, b);
|
||||
case compare_function::equal: return base::equal(a, b);
|
||||
case compare_function::less_equal: return base::less_equal(a, b);
|
||||
case compare_function::greater_equal: return base::greater_equal(a, b);
|
||||
case compare_function::not_equal: return base::not_equal(a, b);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> custom_compare(compare_function function, int channel_count, expression_t<Type, Count> a, expression_t<Type, Count> b)
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static typename base::boolean_expr<Count> custom_compare(compare_function function, int channel_count,
|
||||
typename base::expression_t<Type, Count> a, typename base::expression_t<Type, Count> b)
|
||||
{
|
||||
if (channel_count == 1)
|
||||
{
|
||||
@@ -68,21 +75,17 @@ namespace rsx
|
||||
return vector_compare_function(function, a, b);
|
||||
}
|
||||
|
||||
writer_t comment(const std::string& lines)
|
||||
builder::writer_t comment(const std::string& lines)
|
||||
{
|
||||
writer_t result;
|
||||
|
||||
result += "//" + lines + "\n";
|
||||
|
||||
return result;
|
||||
return{ "//" + lines + "\n" };
|
||||
}
|
||||
|
||||
writer_t warning(const std::string& lines)
|
||||
builder::writer_t warning(const std::string& lines)
|
||||
{
|
||||
return comment("WARNING: " + lines);
|
||||
}
|
||||
|
||||
writer_t unimplemented(const std::string& lines)
|
||||
builder::writer_t unimplemented(const std::string& lines)
|
||||
{
|
||||
return comment("TODO: " + lines);
|
||||
}
|
||||
|
||||
@@ -10,13 +10,27 @@ namespace rsx
|
||||
template<typename Language>
|
||||
class decompiler : public decompiler_base<Language>
|
||||
{
|
||||
using base = decompiler_base<Language>;
|
||||
|
||||
template<int Count>
|
||||
using boolean_expr = typename base::boolean_expr<Count>;
|
||||
|
||||
template<int Count>
|
||||
using float_point_expr = typename base::float_point_expr<Count>;
|
||||
|
||||
template<int Count>
|
||||
using float_point_t = typename base::float_point_t<Count>;
|
||||
|
||||
template<int Count>
|
||||
using boolean_t = typename base::boolean_t<Count>;
|
||||
|
||||
struct context_t
|
||||
{
|
||||
decompiled_program program;
|
||||
decompiled_shader program;
|
||||
bool is_next_is_constant;
|
||||
u32 offset;
|
||||
|
||||
expression_from<float_point_t<4>> constant()
|
||||
typename base::float_point_expr<4> constant()
|
||||
{
|
||||
constant_info info;
|
||||
info.id = offset + sizeof(instruction_t);
|
||||
@@ -27,7 +41,7 @@ namespace rsx
|
||||
return info.name;
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> temporary(bool is_fp16, int index)
|
||||
typename base::float_point_expr<4> temporary(bool is_fp16, int index)
|
||||
{
|
||||
register_info info;
|
||||
info.id = index;
|
||||
@@ -37,7 +51,7 @@ namespace rsx
|
||||
return info.name;
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> condition(int index)
|
||||
typename base::float_point_expr<4> condition(int index)
|
||||
{
|
||||
register_info info;
|
||||
info.id = index;
|
||||
@@ -48,7 +62,7 @@ namespace rsx
|
||||
return info.name;
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> input(int index)
|
||||
typename base::float_point_expr<4> input(int index)
|
||||
{
|
||||
program.input_attributes |= (1 << index);
|
||||
return input_attrib_map[index];
|
||||
@@ -75,23 +89,14 @@ namespace rsx
|
||||
bool abs;
|
||||
};
|
||||
|
||||
static u32 swap_endianess(u32 data)
|
||||
{
|
||||
return
|
||||
((data >> 24) & 0x000000ff) |
|
||||
((data >> 8) & 0x0000ff00) |
|
||||
((data << 8) & 0x00ff0000) |
|
||||
((data << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
instruction_t unpack()
|
||||
{
|
||||
instruction_t result;
|
||||
|
||||
result.data.dst._u32 = swap_endianess((data.dst._u32 << 16) | (data.dst._u32 >> 16));
|
||||
result.data.src0._u32 = swap_endianess((data.src0._u32 << 16) | (data.src0._u32 >> 16));
|
||||
result.data.src1._u32 = swap_endianess((data.src1._u32 << 16) | (data.src1._u32 >> 16));
|
||||
result.data.src2._u32 = swap_endianess((data.src2._u32 << 16) | (data.src2._u32 >> 16));
|
||||
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);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -116,7 +121,7 @@ namespace rsx
|
||||
return result;
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> swizzle_as_dst(expression_from<float_point_t<4>> arg) const
|
||||
typename base::float_point_expr<4> swizzle_as_dst(typename base::float_point_expr<4> arg) const
|
||||
{
|
||||
std::string arg_mask;
|
||||
|
||||
@@ -125,10 +130,10 @@ namespace rsx
|
||||
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);
|
||||
return float_point_expr<4>(arg.text, arg_mask, arg.is_single, arg.base_count);
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> src(context_t& context, int index, bool is_swizzle_as_dst = false) const
|
||||
typename base::float_point_expr<4> src(context_t& context, int index, bool is_swizzle_as_dst = false) const
|
||||
{
|
||||
src_t src;
|
||||
|
||||
@@ -151,7 +156,7 @@ namespace rsx
|
||||
throw;
|
||||
};
|
||||
|
||||
expression_from<float_point_t<4>> result = get_variable(src);
|
||||
typename base::float_point_expr<4> result = get_variable(src);
|
||||
|
||||
result.assign(result.swizzle(src.swizzle_x, src.swizzle_y, src.swizzle_z, src.swizzle_w));
|
||||
|
||||
@@ -162,7 +167,7 @@ namespace rsx
|
||||
|
||||
if (src.abs)
|
||||
{
|
||||
result.assign(abs(result));
|
||||
result.assign(base::abs(result));
|
||||
}
|
||||
|
||||
if (src.neg)
|
||||
@@ -185,7 +190,7 @@ namespace rsx
|
||||
return swizzle;
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> destination(context_t& context) const
|
||||
typename base::float_point_expr<4> destination(context_t& context) const
|
||||
{
|
||||
if (data.dst.no_dest)
|
||||
{
|
||||
@@ -201,22 +206,22 @@ namespace rsx
|
||||
instruction_t instruction;
|
||||
context_t context;
|
||||
|
||||
expression_from<float_point_t<4>> src(int index, bool is_swizzle_as_dst = false)
|
||||
typename base::float_point_expr<4> src(int index, bool is_swizzle_as_dst = false)
|
||||
{
|
||||
return instruction.src(context, index, is_swizzle_as_dst);
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> src_swizzled_as_dst(int index)
|
||||
typename base::float_point_expr<4> src_swizzled_as_dst(int index)
|
||||
{
|
||||
return src(index, instruction.data.dst.set_cond || !instruction.data.dst.no_dest);
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> modify_condition_register()
|
||||
typename base::float_point_expr<4> modify_condition_register()
|
||||
{
|
||||
return context.condition(instruction.data.src0.cond_mod_reg_index);
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> execution_condition_register()
|
||||
typename base::float_point_expr<4> execution_condition_register()
|
||||
{
|
||||
std::string swizzle;
|
||||
|
||||
@@ -234,38 +239,38 @@ namespace rsx
|
||||
any
|
||||
};
|
||||
|
||||
compare_function execution_condition_function() const
|
||||
typename base::compare_function execution_condition_function() const
|
||||
{
|
||||
if (instruction.data.src0.exec_if_gr && instruction.data.src0.exec_if_eq)
|
||||
{
|
||||
return compare_function::greater_equal;
|
||||
return base::compare_function::greater_equal;
|
||||
}
|
||||
if (instruction.data.src0.exec_if_lt && instruction.data.src0.exec_if_eq)
|
||||
{
|
||||
return compare_function::less_equal;
|
||||
return base::compare_function::less_equal;
|
||||
}
|
||||
if (instruction.data.src0.exec_if_gr && instruction.data.src0.exec_if_lt)
|
||||
{
|
||||
return compare_function::not_equal;
|
||||
return base::compare_function::not_equal;
|
||||
}
|
||||
if (instruction.data.src0.exec_if_gr)
|
||||
{
|
||||
return compare_function::greater;
|
||||
return base::compare_function::greater;
|
||||
}
|
||||
if (instruction.data.src0.exec_if_lt)
|
||||
{
|
||||
return compare_function::less;
|
||||
return base::compare_function::less;
|
||||
}
|
||||
|
||||
if (instruction.data.src0.exec_if_eq)
|
||||
{
|
||||
return compare_function::equal;
|
||||
return base::compare_function::equal;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
expression_from<boolean_t<1>> execution_condition(condition_operation operation)
|
||||
typename base::boolean_expr<1> execution_condition(condition_operation operation)
|
||||
{
|
||||
if (instruction.data.src0.exec_if_gr && instruction.data.src0.exec_if_eq && instruction.data.src0.exec_if_gr)
|
||||
{
|
||||
@@ -283,38 +288,38 @@ namespace rsx
|
||||
instruction.data.src0.cond_swizzle_y == instruction.data.src0.cond_swizzle_z &&
|
||||
instruction.data.src0.cond_swizzle_z == instruction.data.src0.cond_swizzle_w)
|
||||
{
|
||||
return custom_compare(execution_condition_function(), 1, cond.x(), expression_from<float_point_t<1>>(0.0f));
|
||||
return base::custom_compare(execution_condition_function(), 1, cond.x(), float_point_expr<1>(0.0f));
|
||||
}
|
||||
|
||||
auto result = custom_compare(execution_condition_function(), 4, cond, float_point_t<4>::ctor(0.0f));
|
||||
auto result = base::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);
|
||||
case condition_operation::all: return base::all(result);
|
||||
case condition_operation::any: return base::any(result);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
expression_from<boolean_t<4>> compare(compare_function function, expression_from<float_point_t<4>> a, expression_from<float_point_t<4>> b)
|
||||
typename boolean_expr<4> compare(typename base::compare_function function, float_point_expr<4> a, float_point_expr<4> b)
|
||||
{
|
||||
return custom_compare(function, (int)instruction.destination_swizzle().size(), a, b);
|
||||
return base::custom_compare(function, (int)instruction.destination_swizzle().size(), a, b);
|
||||
}
|
||||
|
||||
expression_from<sampler2D_t> tex()
|
||||
typename base::expression_from<typename base::sampler2D_t> tex()
|
||||
{
|
||||
return{ "unk_tex" };
|
||||
}
|
||||
|
||||
template<typename ExprType>
|
||||
expression_from<void_t> conditional(const ExprType& expr)
|
||||
typename base::void_expr conditional(const ExprType& expr)
|
||||
{
|
||||
bool need_condition = false;
|
||||
|
||||
if (need_condition)
|
||||
{
|
||||
return if_(any(execution_condition(condition_operation::any)), expr);
|
||||
return base::if_(base::any(execution_condition(condition_operation::any)), expr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
@@ -329,17 +334,17 @@ namespace rsx
|
||||
template<typename Type>
|
||||
Type apply_instruction_modifiers(Type arg)
|
||||
{
|
||||
using float_t = expression_from<float_point_t<1>>;
|
||||
using float_expr = float_point_expr<1>;
|
||||
|
||||
switch (instruction.data.src1.scale)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: arg.assign(arg * (float_t)2.0f); break;
|
||||
case 2: arg.assign(arg * (float_t)4.0f); break;
|
||||
case 3: arg.assign(arg * (float_t)8.0f); break;
|
||||
case 5: arg.assign(arg / (float_t)2.0f); break;
|
||||
case 6: arg.assign(arg / (float_t)4.0f); break;
|
||||
case 7: arg.assign(arg / (float_t)8.0f); break;
|
||||
case 1: arg.assign(arg * (float_expr)2.0f); break;
|
||||
case 2: arg.assign(arg * (float_expr)4.0f); break;
|
||||
case 3: arg.assign(arg * (float_expr)8.0f); break;
|
||||
case 5: arg.assign(arg / (float_expr)2.0f); break;
|
||||
case 6: arg.assign(arg / (float_expr)4.0f); break;
|
||||
case 7: arg.assign(arg / (float_expr)8.0f); break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("fragment program decompiler: unimplemented scale (" + std::to_string(instruction.data.src1.scale) + "). ");
|
||||
@@ -347,7 +352,7 @@ namespace rsx
|
||||
|
||||
if (instruction.data.dst.saturate)
|
||||
{
|
||||
arg.assign(clamp(arg, 0.0f, 1.0f));
|
||||
arg.assign(base::clamp(arg, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -361,11 +366,11 @@ namespace rsx
|
||||
//result is fp16, clamp to fp16
|
||||
|
||||
case 1: //fp16
|
||||
arg.assign(clamp(arg, -65536.0f, 65536.0f));
|
||||
arg.assign(base::clamp(arg, -65536.0f, 65536.0f));
|
||||
break;
|
||||
|
||||
case 2: //fixed point 12
|
||||
arg.assign(clamp(arg, -1.0f, 1.0f));
|
||||
arg.assign(base::clamp(arg, -1.0f, 1.0f));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -376,9 +381,9 @@ namespace rsx
|
||||
return arg;
|
||||
}
|
||||
|
||||
writer_t set_dst(const expression_from<float_point_t<4>>& arg, u32 flags = none)
|
||||
builder::writer_t set_dst(const typename base::float_point_expr<4>& arg, u32 flags = none)
|
||||
{
|
||||
writer_t result;
|
||||
builder::writer_t result;
|
||||
|
||||
auto modify_cond = modify_condition_register();
|
||||
auto dest = instruction.destination(context);
|
||||
@@ -417,12 +422,12 @@ 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 += warning("extra condition test skipped");
|
||||
result += base::warning("extra condition test skipped");
|
||||
result += arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const expression_from<float_point_t<1>> zero(0.0f);
|
||||
static const typename base::float_point_expr<1> zero(0.0f);
|
||||
|
||||
std::map<char, std::vector<std::pair<int, int>>> condition_map;
|
||||
|
||||
@@ -436,7 +441,7 @@ namespace rsx
|
||||
|
||||
if (flags & disable_swizzle_as_dst)
|
||||
{
|
||||
src.assign(expression_from<float_point_t<4>>(arg.text, arg.mask, true, (int)dest.mask.size()));
|
||||
src.assign(float_point_expr<4>(arg.text, arg.mask, true, (int)dest.mask.size()));
|
||||
}
|
||||
|
||||
for (auto &entry : condition_map)
|
||||
@@ -450,7 +455,7 @@ namespace rsx
|
||||
dst_swizzle += dest.swizzle(channels.second).mask[0];
|
||||
}
|
||||
|
||||
expression_from<float_point_t<4>> expression{ src.with_mask(src_swizzle) };
|
||||
typename base::float_point_expr<4> expression{ src.with_mask(src_swizzle) };
|
||||
|
||||
if (!instruction.data.dst.no_dest)
|
||||
{
|
||||
@@ -462,13 +467,13 @@ namespace rsx
|
||||
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);
|
||||
result += base::if_(cond.swizzle(channel_to_index.at(entry.first)).call_operator<typename base::boolean_t<1>>(operation, zero), expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
expression_from<float_point_t<4>> src = arg;
|
||||
float_point_expr<4> src = arg;
|
||||
|
||||
if (instruction.data.dst.set_cond || !instruction.data.dst.no_dest)
|
||||
{
|
||||
@@ -486,7 +491,7 @@ namespace rsx
|
||||
|
||||
if (instruction.data.dst.set_cond)
|
||||
{
|
||||
src.assign(expression_from<float_point_t<4>>(modify_cond.text, dest.mask) = src);
|
||||
src.assign(float_point_expr<4>(modify_cond.text, dest.mask) = src);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,17 +501,17 @@ namespace rsx
|
||||
return result;
|
||||
}
|
||||
|
||||
writer_t set_dst(const expression_from<float_point_t<1>>& arg, u32 flags = none)
|
||||
builder::writer_t set_dst(const typename base::float_point_expr<1>& arg, u32 flags = none)
|
||||
{
|
||||
if (instruction.destination_swizzle().size() != 1)
|
||||
{
|
||||
return set_dst(float_point_t<4>::ctor(arg), flags);
|
||||
}
|
||||
|
||||
return set_dst(expression_from<float_point_t<4>>{ arg.to_string() }, flags | disable_swizzle_as_dst);
|
||||
return set_dst(float_point_expr<4>{ arg.to_string() }, flags | disable_swizzle_as_dst);
|
||||
}
|
||||
|
||||
writer_t set_dst(const expression_from<boolean_t<4>>& arg, u32 flags = none)
|
||||
builder::writer_t set_dst(const boolean_expr<4>& arg, u32 flags = none)
|
||||
{
|
||||
std::string arg_string;
|
||||
|
||||
@@ -515,28 +520,28 @@ namespace rsx
|
||||
switch (instruction.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(expression_from<boolean_t<2>>{ arg.to_string() }).to_string(); break;
|
||||
case 3: arg_string = float_point_t<3>::ctor(expression_from<boolean_t<3>>{ arg.to_string() }).to_string(); break;
|
||||
case 4: arg_string = float_point_t<4>::ctor(expression_from<boolean_t<4>>{ arg.to_string() }).to_string(); 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(expression_from<float_point_t<4>>{ arg_string, std::string("xyzw"), is_single, 4 }, flags);
|
||||
return set_dst(float_point_expr<4>{ arg_string, std::string("xyzw"), is_single, 4 }, flags);
|
||||
}
|
||||
|
||||
expression_base_t decode_instruction()
|
||||
builder::expression_base_t decode_instruction()
|
||||
{
|
||||
switch (instruction.data.dst.opcode | (instruction.data.src1.opcode_is_branch << 6))
|
||||
{
|
||||
case opcode::nop: return comment("nop");
|
||||
case opcode::nop: return base::comment("nop");
|
||||
case opcode::mov: return set_dst(src_swizzled_as_dst(0), disable_swizzle_as_dst);
|
||||
case opcode::mul: return set_dst(src_swizzled_as_dst(0) * src_swizzled_as_dst(1), disable_swizzle_as_dst);
|
||||
case opcode::add: return set_dst(src_swizzled_as_dst(0) + src_swizzled_as_dst(1), disable_swizzle_as_dst);
|
||||
case opcode::mad: return set_dst((src_swizzled_as_dst(0) * src_swizzled_as_dst(1)).without_scope() + src_swizzled_as_dst(2), disable_swizzle_as_dst);
|
||||
case opcode::dp3: return set_dst(dot(src(0).xyz(), src(1).xyz()));
|
||||
case opcode::dp4: return set_dst(dot(src(0), src(1)));
|
||||
case opcode::dp3: return set_dst(base::dot(src(0).xyz(), src(1).xyz()));
|
||||
case opcode::dp4: return set_dst(base::dot(src(0), src(1)));
|
||||
case opcode::dst:
|
||||
{
|
||||
auto src_0 = src(0);
|
||||
@@ -544,44 +549,44 @@ namespace rsx
|
||||
|
||||
return set_dst(float_point_t<4>::ctor(1.0f, src_0.y() * src_1.y(), src_0.z(), src_1.w()));
|
||||
}
|
||||
case opcode::min: return set_dst(min(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::max: return set_dst(max(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::slt: return set_dst(compare(compare_function::less, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sge: return set_dst(compare(compare_function::greater_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sle: return set_dst(compare(compare_function::less_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sgt: return set_dst(compare(compare_function::greater, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sne: return set_dst(compare(compare_function::not_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::seq: return set_dst(compare(compare_function::equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::frc: return set_dst(fract(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::flr: return set_dst(floor(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::kil: return conditional(expression_from<void_t>("discard;"));
|
||||
case opcode::pk4: return unimplemented("PK4");
|
||||
case opcode::up4: return unimplemented("UP4");
|
||||
case opcode::ddx: return set_dst(ddx(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::ddy: return set_dst(ddy(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::tex: return set_dst(texture(tex(), src(0).xy()));
|
||||
case opcode::txp: return set_dst(texture(tex(), src(0).xy() / src(0).w()));
|
||||
case opcode::txd: return set_dst(texture_grad(tex(), src(0).xy(), src(1).xy(), src(2).xy()));
|
||||
case opcode::min: return set_dst(base::min(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::max: return set_dst(base::max(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::slt: return set_dst(compare(base::compare_function::less, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sge: return set_dst(compare(base::compare_function::greater_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sle: return set_dst(compare(base::compare_function::less_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sgt: return set_dst(compare(base::compare_function::greater, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::sne: return set_dst(compare(base::compare_function::not_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::seq: return set_dst(compare(base::compare_function::equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::frc: return set_dst(base::fract(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::flr: return set_dst(base::floor(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::kil: return conditional(typename base::void_expr{ "discard;" });
|
||||
case opcode::pk4: return base::unimplemented("PK4");
|
||||
case opcode::up4: return base::unimplemented("UP4");
|
||||
case opcode::ddx: return set_dst(base::ddx(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::ddy: return set_dst(base::ddy(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::tex: return set_dst(base::texture(tex(), src(0).xy()));
|
||||
case opcode::txp: return set_dst(base::texture(tex(), src(0).xy() / src(0).w()));
|
||||
case opcode::txd: return set_dst(base::texture_grad(tex(), src(0).xy(), src(1).xy(), src(2).xy()));
|
||||
case opcode::rcp: return set_dst(float_point_t<1>::ctor(1.0f) / src_swizzled_as_dst(0), disable_swizzle_as_dst);
|
||||
case opcode::rsq: return set_dst(rsqrt(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::ex2: return set_dst(exp2(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::lg2: return set_dst(log2(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::lit: return unimplemented("LIT");
|
||||
case opcode::lrp: return unimplemented("LRP");
|
||||
case opcode::rsq: return set_dst(base::rsqrt(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::ex2: return set_dst(base::exp2(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::lg2: return set_dst(base::log2(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::lit: return base::unimplemented("LIT");
|
||||
case opcode::lrp: return base::unimplemented("LRP");
|
||||
case opcode::str: return set_dst(1.0f);
|
||||
case opcode::sfl: return set_dst(0.0f);
|
||||
case opcode::cos: return set_dst(cos(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::sin: return set_dst(sin(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::pk2: return unimplemented("PK2");
|
||||
case opcode::up2: return unimplemented("UP2");
|
||||
case opcode::pow: return set_dst(pow(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::pkb: return unimplemented("PKB");
|
||||
case opcode::upb: return unimplemented("UPB");
|
||||
case opcode::pk16: return unimplemented("PK16");
|
||||
case opcode::up16: return unimplemented("UP16");
|
||||
case opcode::bem: return unimplemented("BEM");
|
||||
case opcode::pkg: return unimplemented("PKG");
|
||||
case opcode::upg: return unimplemented("UPG");
|
||||
case opcode::cos: return set_dst(base::cos(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::sin: return set_dst(base::sin(src_swizzled_as_dst(0)), disable_swizzle_as_dst);
|
||||
case opcode::pk2: return base::unimplemented("PK2");
|
||||
case opcode::up2: return base::unimplemented("UP2");
|
||||
case opcode::pow: return set_dst(base::pow(src_swizzled_as_dst(0), src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::pkb: return base::unimplemented("PKB");
|
||||
case opcode::upb: return base::unimplemented("UPB");
|
||||
case opcode::pk16: return base::unimplemented("PK16");
|
||||
case opcode::up16: return base::unimplemented("UP16");
|
||||
case opcode::bem: return base::unimplemented("BEM");
|
||||
case opcode::pkg: return base::unimplemented("PKG");
|
||||
case opcode::upg: return base::unimplemented("UPG");
|
||||
case opcode::dp2a:
|
||||
{
|
||||
auto src_0 = src(0);
|
||||
@@ -589,34 +594,34 @@ 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 opcode::txl: return set_dst(texture_lod(tex(), src(0).xy(), src(1).x()));
|
||||
case opcode::txb: return set_dst(texture_bias(tex(), src(0).xy(), src(1).x()));
|
||||
case opcode::texbem: return unimplemented("TEXBEM");
|
||||
case opcode::txpbem: return unimplemented("TXPBEM");
|
||||
case opcode::bemlum: return unimplemented("BEMLUM");
|
||||
case opcode::refl: return unimplemented("REFL");
|
||||
case opcode::timeswtex: return unimplemented("TIMESWTEX");
|
||||
case opcode::dp2: return set_dst(dot(src(0).xy(), src(1).xy()));
|
||||
case opcode::nrm: return set_dst(normalize(src(0).xyz()).xyzx());
|
||||
case opcode::txl: return set_dst(base::texture_lod(tex(), src(0).xy(), src(1).x()));
|
||||
case opcode::txb: return set_dst(base::texture_bias(tex(), src(0).xy(), src(1).x()));
|
||||
case opcode::texbem: return base::unimplemented("TEXBEM");
|
||||
case opcode::txpbem: return base::unimplemented("TXPBEM");
|
||||
case opcode::bemlum: return base::unimplemented("BEMLUM");
|
||||
case opcode::refl: return base::unimplemented("REFL");
|
||||
case opcode::timeswtex: return base::unimplemented("TIMESWTEX");
|
||||
case opcode::dp2: return set_dst(base::dot(src(0).xy(), src(1).xy()));
|
||||
case opcode::nrm: return set_dst(base::normalize(src(0).xyz()).xyzx());
|
||||
case opcode::div: return set_dst(src_swizzled_as_dst(0) / src_swizzled_as_dst(1), disable_swizzle_as_dst);
|
||||
case opcode::divsq: return set_dst(src_swizzled_as_dst(0) / sqrt(src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::lif: return unimplemented("LIF");
|
||||
case opcode::fenct: return comment("fenct");
|
||||
case opcode::fencb: return comment("fencb");
|
||||
case opcode::brk: return conditional(expression_from<void_t>("break;"));
|
||||
case opcode::cal: return unimplemented("CAL");
|
||||
case opcode::divsq: return set_dst(src_swizzled_as_dst(0) / base::sqrt(src_swizzled_as_dst(1)), disable_swizzle_as_dst);
|
||||
case opcode::lif: return base::unimplemented("LIF");
|
||||
case opcode::fenct: return base::comment("fenct");
|
||||
case opcode::fencb: return base::comment("fencb");
|
||||
case opcode::brk: return conditional(typename base::void_expr("break;"));
|
||||
case opcode::cal: return base::unimplemented("CAL");
|
||||
case opcode::ife:
|
||||
writer += writer_t{ "if (" + execution_condition(condition_operation::all).to_string() + ")\n{\n" };
|
||||
base::writer += typename base::writer_t{ "if (" + execution_condition(condition_operation::all).to_string() + ")\n{\n" };
|
||||
|
||||
if (instruction.data.src2.end_offset != instruction.data.src1.else_offset)
|
||||
writer.before(instruction.data.src1.else_offset >> 2, "}\nelse\n{\n");
|
||||
base::writer.before(instruction.data.src1.else_offset >> 2, "}\nelse\n{\n");
|
||||
|
||||
writer.after(instruction.data.src2.end_offset >> 2, "}\n");
|
||||
base::writer.after(instruction.data.src2.end_offset >> 2, "}\n");
|
||||
|
||||
return "";
|
||||
return{ "" };
|
||||
|
||||
case opcode::loop:
|
||||
writer += writer_t
|
||||
base::writer += typename base::writer_t
|
||||
{
|
||||
"for ("
|
||||
"int i = " + std::to_string(instruction.data.src1.init_counter) + "; " +
|
||||
@@ -625,21 +630,21 @@ namespace rsx
|
||||
")\n{\n"
|
||||
};
|
||||
|
||||
writer.after(instruction.data.src2.end_offset >> 2, "}\n");
|
||||
return "";
|
||||
case opcode::rep: return unimplemented("REP");
|
||||
case opcode::ret: return conditional(expression_from<void_t>("return;"));
|
||||
base::writer.after(instruction.data.src2.end_offset >> 2, "}\n");
|
||||
return{ "" };
|
||||
case opcode::rep: return base::unimplemented("REP");
|
||||
case opcode::ret: return conditional(typename base::void_expr("return;"));
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
decompiled_program decompile(std::size_t offset, instruction_t* instructions)
|
||||
decompiled_shader decompile(std::size_t offset, instruction_t* instructions)
|
||||
{
|
||||
context.offset = 0;
|
||||
context.is_next_is_constant = false;
|
||||
|
||||
for (std::size_t index = offset; true; ++index, writer.next(), context.offset += sizeof(instruction_t))
|
||||
for (std::size_t index = offset; true; ++index, base::writer.next(), context.offset += sizeof(instruction_t))
|
||||
{
|
||||
if (context.is_next_is_constant)
|
||||
{
|
||||
@@ -649,28 +654,30 @@ namespace rsx
|
||||
|
||||
instruction = instructions[index].unpack();
|
||||
|
||||
writer += decode_instruction();
|
||||
base::writer += decode_instruction();
|
||||
|
||||
if (instruction.data.dst.end)
|
||||
break;
|
||||
}
|
||||
|
||||
context.program.entry_function = "func0";
|
||||
context.program.code = "void func0()\n{\n" + writer.build() + "}\n";
|
||||
base::writer.before(0, "void func0()\n{\n");
|
||||
base::writer.after(base::writer.position, "}\n");
|
||||
context.program.code = base::writer.finalize();
|
||||
|
||||
return context.program;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Language>
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr *instructions)
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr *instructions)
|
||||
{
|
||||
return decompiler<Language>{}.decompile(offset, (decompiler<Language>::instruction_t*)instructions);
|
||||
return decompiler<Language>{}.decompile(offset, (typename decompiler<Language>::instruction_t*)instructions);
|
||||
}
|
||||
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr *instructions, decompile_language lang)
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr *instructions, decompile_language lang)
|
||||
{
|
||||
decompiled_program result;
|
||||
decompiled_shader result;
|
||||
switch (lang)
|
||||
{
|
||||
case decompile_language::glsl:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "pch.h"
|
||||
#include "rsx_fp_ucode.h"
|
||||
|
||||
namespace rsx
|
||||
@@ -25,13 +24,6 @@ namespace rsx
|
||||
"in_unk" //15
|
||||
};
|
||||
|
||||
const std::string input_attr_regs[16] =
|
||||
{
|
||||
"WPOS", "COL0", "COL1", "FOGC", "TEX0",
|
||||
"TEX1", "TEX2", "TEX3", "TEX4", "TEX5",
|
||||
"TEX6", "TEX7", "TEX8", "TEX9", "SSA"
|
||||
};
|
||||
|
||||
const std::string instructions_names[128] =
|
||||
{
|
||||
"NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DP4",
|
||||
@@ -45,5 +37,24 @@ namespace rsx
|
||||
"DP2", "NRM", "DIV", "DIVSQ", "LIF", "FENCT", "FENCB",
|
||||
"NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET"
|
||||
};
|
||||
|
||||
std::uint64_t hash(const ucode_instr *ucode)
|
||||
{
|
||||
std::uint64_t hash = 0xCBF29CE484222325ULL;
|
||||
|
||||
for (const ucode_instr *ptr = ucode; !ptr->end(); ++ptr)
|
||||
{
|
||||
hash ^= ptr->dst._u32 | (std::uint64_t(ptr->src0._u32) << 32);
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
|
||||
hash ^= ptr->src1._u32 | (std::uint64_t(ptr->src2._u32) << 32);
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
|
||||
if (ptr->has_constant())
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,9 +213,25 @@ namespace rsx
|
||||
SRC0 src0;
|
||||
SRC1 src1;
|
||||
SRC2 src2;
|
||||
|
||||
static bool is_constant(u32 data)
|
||||
{
|
||||
return src_reg_type_t((data >> 8) & 0x3) == src_reg_type_t::constant;
|
||||
}
|
||||
|
||||
bool has_constant() const
|
||||
{
|
||||
return is_constant(src0._u32) || is_constant(src1._u32) || is_constant(src2._u32);
|
||||
}
|
||||
|
||||
bool end() const
|
||||
{
|
||||
return (dst._u32 >> 8) & 0x1;
|
||||
}
|
||||
};
|
||||
|
||||
extern const std::string input_attr_regs[16];
|
||||
std::uint64_t hash(const ucode_instr *ucode);
|
||||
|
||||
extern const std::string instructions_names[128];
|
||||
extern const std::string input_attrib_map[16];
|
||||
}
|
||||
|
||||
@@ -7,11 +7,32 @@ namespace rsx
|
||||
{
|
||||
namespace vertex_program
|
||||
{
|
||||
class decompiler : public decompiler_base<shader_code::glsl_language>
|
||||
template<typename Language>
|
||||
class decompiler : public decompiler_base<Language>
|
||||
{
|
||||
using base = decompiler_base<Language>;
|
||||
|
||||
template<int Count>
|
||||
using boolean_expr = typename base::boolean_expr<Count>;
|
||||
|
||||
template<int Count>
|
||||
using float_point_expr = typename base::float_point_expr<Count>;
|
||||
|
||||
template<int Count>
|
||||
using integer_expr = typename base::integer_expr<Count>;
|
||||
|
||||
template<int Count>
|
||||
using float_point_t = typename base::float_point_t<Count>;
|
||||
|
||||
template<int Count>
|
||||
using boolean_t = typename base::boolean_t<Count>;
|
||||
|
||||
template<int Count>
|
||||
using integer_t = typename base::integer_t<Count>;
|
||||
|
||||
struct context_t
|
||||
{
|
||||
decompiled_program program;
|
||||
decompiled_shader program;
|
||||
|
||||
std::string address_register(u32 address_register)
|
||||
{
|
||||
@@ -47,7 +68,7 @@ namespace rsx
|
||||
register_info info;
|
||||
info.id = index;
|
||||
info.type = register_type::single_float_point;
|
||||
info.name = "o" + std::to_string(index);
|
||||
info.name = rsx::fragment_program::input_attrib_map[index];//"o" + std::to_string(index);
|
||||
program.temporary_registers.insert(info);
|
||||
return info.name;
|
||||
}
|
||||
@@ -112,25 +133,9 @@ namespace rsx
|
||||
return result;
|
||||
}
|
||||
|
||||
static u32 swap_endianess(u32 data)
|
||||
const instruction_t& unpack() const
|
||||
{
|
||||
return
|
||||
((data >> 24) & 0x000000ff) |
|
||||
((data >> 8) & 0x0000ff00) |
|
||||
((data << 8) & 0x00ff0000) |
|
||||
((data << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
instruction_t unpack() const
|
||||
{
|
||||
instruction_t result;
|
||||
|
||||
result.data.d0._u32 = swap_endianess(data.d0._u32);
|
||||
result.data.d1._u32 = swap_endianess(data.d1._u32);
|
||||
result.data.d2._u32 = swap_endianess(data.d2._u32);
|
||||
result.data.d3._u32 = swap_endianess(data.d3._u32);
|
||||
|
||||
return result;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,7 +166,7 @@ namespace rsx
|
||||
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
|
||||
float_point_expr<4> swizzle_as_dst(float_point_expr<4> arg) const
|
||||
{
|
||||
std::string arg_mask;
|
||||
|
||||
@@ -170,7 +175,7 @@ namespace rsx
|
||||
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);
|
||||
return float_point_expr<4>(arg.text, arg_mask, arg.is_single, arg.base_count);
|
||||
}
|
||||
|
||||
float_point_expr<4> src(int index, bool is_swizzle_as_dst = false)
|
||||
@@ -217,7 +222,7 @@ namespace rsx
|
||||
|
||||
if (is_abs)
|
||||
{
|
||||
result.assign(abs(result));
|
||||
result.assign(base::abs(result));
|
||||
}
|
||||
|
||||
if (src.neg)
|
||||
@@ -289,16 +294,16 @@ namespace rsx
|
||||
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)
|
||||
boolean_expr<4> compare(typename base::compare_function function, float_point_expr<4> a, float_point_expr<4> b)
|
||||
{
|
||||
return custom_compare(function, (int)destination_swizzle().size(), a, b);
|
||||
return base::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 base::clamp(arg, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
return arg;
|
||||
@@ -314,20 +319,20 @@ namespace rsx
|
||||
never = 0
|
||||
};
|
||||
|
||||
writer_t set_dst(float_point_expr<4> arg)
|
||||
typename base::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;
|
||||
typename base::writer_t result;
|
||||
|
||||
if (instruction.data.d0.cond_test_enable && instruction.data.d0.cond != always)
|
||||
{
|
||||
if (!has_result)
|
||||
{
|
||||
result += warning("Extra condition skipped");
|
||||
result += base::warning("Extra condition skipped");
|
||||
result += arg;
|
||||
}
|
||||
else
|
||||
@@ -394,7 +399,7 @@ namespace rsx
|
||||
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);
|
||||
result += base::if_(cond.swizzle(channel_to_index.at(entry.first)).call_operator<boolean_t<1>>(operation, zero), expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +423,7 @@ namespace rsx
|
||||
return result;
|
||||
}
|
||||
|
||||
writer_t set_dst(expression_from<float_point_t<1>> arg)
|
||||
typename base::writer_t set_dst(float_point_expr<1> arg)
|
||||
{
|
||||
if (destination_swizzle().size() != 1)
|
||||
{
|
||||
@@ -428,7 +433,7 @@ namespace rsx
|
||||
return set_dst(float_point_expr<4>{ arg.to_string() });
|
||||
}
|
||||
|
||||
writer_t set_dst(boolean_expr<4> arg)
|
||||
typename base::writer_t set_dst(boolean_expr<4> arg)
|
||||
{
|
||||
std::string arg_string;
|
||||
|
||||
@@ -454,16 +459,16 @@ namespace rsx
|
||||
any
|
||||
};
|
||||
|
||||
compare_function execution_condition_function() const
|
||||
typename base::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;
|
||||
case gt | eq: return base::compare_function::greater_equal;
|
||||
case lt | eq: return base::compare_function::less_equal;
|
||||
case lt | gt: return base::compare_function::not_equal;
|
||||
case gt: return base::compare_function::greater;
|
||||
case lt: return base::compare_function::less;
|
||||
case eq: return base::compare_function::equal;
|
||||
}
|
||||
|
||||
throw;
|
||||
@@ -487,34 +492,34 @@ namespace rsx
|
||||
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));
|
||||
return base::custom_compare(execution_condition_function(), 1, cond.x(), float_point_expr<1>(0.0f));
|
||||
}
|
||||
|
||||
auto result = custom_compare(execution_condition_function(), 4, cond, float_point_t<4>::ctor(0.0f));
|
||||
auto result = base::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);
|
||||
case condition_operation::all: return base::all(result);
|
||||
case condition_operation::any: return base::any(result);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
template<typename ExprType>
|
||||
expression_from<void_t> conditional(const ExprType& expr)
|
||||
typename base::void_expr conditional(const ExprType& expr)
|
||||
{
|
||||
bool need_condition = false;
|
||||
|
||||
if (need_condition)
|
||||
{
|
||||
return if_(any(execution_condition(condition_operation::any)), expr);
|
||||
return base::if_(base::any(execution_condition(condition_operation::any)), expr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
expression_base_t decode_sca_instruction()
|
||||
typename base::expression_base_t decode_sca_instruction()
|
||||
{
|
||||
is_vec = false;
|
||||
|
||||
@@ -522,47 +527,47 @@ namespace rsx
|
||||
{
|
||||
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::rcc: return set_dst(base::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(base::rsqrt(base::abs(src_swizzled_as_dst(2))));
|
||||
case sca_opcode::exp: return set_dst(base::exp(src_swizzled_as_dst(2)));
|
||||
case sca_opcode::log: return set_dst(base::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)");
|
||||
z_value.assign("(" + z_value.text + " ? " + base::exp2(t.w() * base::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 from = base::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");
|
||||
base::writer.before(from, "if (!(" + condition.to_string() + "))\n{\n");
|
||||
base::writer.before(to, "}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.before(from, "}\nwhile (" + condition.to_string() + ");\n");
|
||||
writer.before(to, "do\n{\n");
|
||||
base::writer.before(from, "}\nwhile (" + condition.to_string() + ");\n");
|
||||
base::writer.before(to, "do\n{\n");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
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::ret: return conditional(typename base::void_expr{ "return" });
|
||||
case sca_opcode::lg2: return set_dst(base::log2(src_swizzled_as_dst(2)));
|
||||
case sca_opcode::ex2: return set_dst(base::exp2(src_swizzled_as_dst(2)));
|
||||
case sca_opcode::sin: return set_dst(base::sin(src_swizzled_as_dst(2)));
|
||||
case sca_opcode::cos: return set_dst(base::cos(src_swizzled_as_dst(2)));
|
||||
case sca_opcode::brb: break;
|
||||
case sca_opcode::clb: break;
|
||||
case sca_opcode::psh: break;
|
||||
@@ -571,10 +576,10 @@ namespace rsx
|
||||
throw;
|
||||
}
|
||||
|
||||
return unimplemented("sca " + sca_op_names[(int)instruction.data.d1.sca_opcode]);
|
||||
return base::unimplemented("sca " + sca_op_names[(int)instruction.data.d1.sca_opcode]);
|
||||
}
|
||||
|
||||
expression_base_t decode_vec_instruction()
|
||||
typename base::expression_base_t decode_vec_instruction()
|
||||
{
|
||||
is_vec = true;
|
||||
|
||||
@@ -584,22 +589,22 @@ namespace rsx
|
||||
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::dp3: return set_dst(base::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::dp4: return set_dst(base::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::min: return set_dst(base::min(src_swizzled_as_dst(0), src_swizzled_as_dst(1)));
|
||||
case vec_opcode::max: return set_dst(base::max(src_swizzled_as_dst(0), src_swizzled_as_dst(1)));
|
||||
case vec_opcode::slt: return set_dst(compare(base::compare_function::less, src_swizzled_as_dst(0), src_swizzled_as_dst(1)));
|
||||
case vec_opcode::sge: return set_dst(compare(base::compare_function::greater_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)));
|
||||
case vec_opcode::arl: return typename base::writer_t{} += address_register() = integer_t<1>::ctor(src(0).x());
|
||||
case vec_opcode::frc: return set_dst(base::fract(src_swizzled_as_dst(0)));
|
||||
case vec_opcode::flr: return set_dst(base::floor(src_swizzled_as_dst(0)));;
|
||||
case vec_opcode::seq: return set_dst(compare(base::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::sgt: return set_dst(compare(base::compare_function::greater, src_swizzled_as_dst(0), src_swizzled_as_dst(1)));;
|
||||
case vec_opcode::sle: return set_dst(compare(base::compare_function::less_equal, src_swizzled_as_dst(0), src_swizzled_as_dst(1)));
|
||||
case vec_opcode::sne: return set_dst(compare(base::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;
|
||||
@@ -608,17 +613,17 @@ namespace rsx
|
||||
throw;
|
||||
}
|
||||
|
||||
return unimplemented("vec " + vec_op_names[(int)instruction.data.d1.vec_opcode]);
|
||||
return base::unimplemented("vec " + vec_op_names[(int)instruction.data.d1.vec_opcode]);
|
||||
}
|
||||
|
||||
expression_base_t decode_instruction()
|
||||
typename base::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");
|
||||
return base::comment("NOP");
|
||||
}
|
||||
|
||||
writer_t result;
|
||||
typename base::writer_t result;
|
||||
|
||||
if (instruction.data.d1.sca_opcode != sca_opcode::nop)
|
||||
{
|
||||
@@ -634,34 +639,36 @@ namespace rsx
|
||||
}
|
||||
|
||||
public:
|
||||
decompiled_program decompile(std::size_t offset, instruction_t *instructions)
|
||||
decompiled_shader decompile(std::size_t offset, instruction_t *instructions)
|
||||
{
|
||||
for (std::size_t i = offset; i < 512; ++i, writer.next())
|
||||
for (std::size_t i = offset; i < 512; ++i, base::writer.next())
|
||||
{
|
||||
instruction = instructions[i].unpack();
|
||||
|
||||
writer += decode_instruction();
|
||||
base::writer += decode_instruction();
|
||||
|
||||
if (instruction.data.d3.end)
|
||||
break;
|
||||
}
|
||||
|
||||
context.program.entry_function = "func0";
|
||||
context.program.code = "void func0()\n{\n" + writer.build() + "}\n";
|
||||
base::writer.before(0, "void func0()\n{\n");
|
||||
base::writer.after(base::writer.position, "}\n");
|
||||
context.program.code = base::writer.finalize();
|
||||
|
||||
return context.program;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Language>
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr *instructions)
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr *instructions)
|
||||
{
|
||||
return decompiler{}.decompile(offset, (decompiler::instruction_t*)instructions);
|
||||
return decompiler<Language>{}.decompile(offset, (typename decompiler<Language>::instruction_t*)instructions);
|
||||
}
|
||||
|
||||
decompiled_program decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang)
|
||||
decompiled_shader decompile(std::size_t offset, ucode_instr* instructions, decompile_language lang)
|
||||
{
|
||||
decompiled_program result;
|
||||
decompiled_shader result;
|
||||
|
||||
switch (lang)
|
||||
{
|
||||
|
||||
@@ -28,5 +28,21 @@ namespace rsx
|
||||
"SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", {},
|
||||
{}, "TXL"
|
||||
};
|
||||
|
||||
std::uint64_t hash(const ucode_instr *ucode)
|
||||
{
|
||||
std::uint64_t hash = 0xCBF29CE484222325ULL;
|
||||
|
||||
for (const ucode_instr *ptr = ucode; !ptr->end(); ++ptr)
|
||||
{
|
||||
hash ^= ptr->d0._u32 | (std::uint64_t(ptr->d1._u32) << 32);
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
|
||||
hash ^= ptr->d2._u32 | (std::uint64_t(ptr->d3._u32) << 32);
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,8 +196,15 @@ namespace rsx
|
||||
D1 d1;
|
||||
D2 d2;
|
||||
D3 d3;
|
||||
|
||||
bool end() const
|
||||
{
|
||||
return d3.end;
|
||||
}
|
||||
};
|
||||
|
||||
std::uint64_t hash(const ucode_instr *ucode);
|
||||
|
||||
extern const std::string input_registers_table[0x10];
|
||||
extern const std::string sca_op_names[0x20];
|
||||
extern const std::string vec_op_names[0x20];
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_program_decompiler_lib", "rsx_program_decompiler_lib\rsx_program_decompiler_lib.vcxproj", "{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_program_decompiler", "rsx_program_decompiler\rsx_program_decompiler.vcxproj", "{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE} = {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}
|
||||
{97E17077-A21F-45EF-9C3A-73A0BC092D7E} = {97E17077-A21F-45EF-9C3A-73A0BC092D7E}
|
||||
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F} = {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}
|
||||
EndProjectSection
|
||||
@@ -25,10 +22,6 @@ Global
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x64.Build.0 = Debug|x64
|
||||
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.ActiveCfg = Release|x64
|
||||
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.Build.0 = Release|x64
|
||||
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x64.Build.0 = Debug|x64
|
||||
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x64.ActiveCfg = Release|x64
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <endianness.h>
|
||||
#include "endianness.h"
|
||||
|
||||
namespace cg
|
||||
{
|
||||
|
||||
@@ -45,6 +45,18 @@ int extract_ucode(const std::string& ipath, const std::string& opath)
|
||||
std::vector<u8> buffer(input_size);
|
||||
ifile_stream.read((char*)buffer.data(), buffer.size());
|
||||
cg::CgBinaryProgram* program = (cg::CgBinaryProgram*)buffer.data();
|
||||
|
||||
//swap endianess
|
||||
{
|
||||
endianness::be<u32> *be_ptr = (endianness::be<u32> *)(buffer.data() + program->ucode);
|
||||
u32 *ne_ptr = (u32 *)be_ptr;
|
||||
|
||||
for (u32 i = 0, end = program->ucodeSize; i < end; i += sizeof(u32))
|
||||
{
|
||||
*ne_ptr++ = *be_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
ofile_stream.write((char*)(buffer.data() + program->ucode), program->ucodeSize);
|
||||
|
||||
return 0;
|
||||
@@ -196,7 +208,6 @@ LRESULT __stdcall WindowProcedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
default:
|
||||
std::cout << '.';
|
||||
return DefWindowProc(hwnd, msg, wp, lp);
|
||||
}
|
||||
}
|
||||
@@ -302,12 +313,12 @@ void test(const std::string &shader)
|
||||
#endif
|
||||
|
||||
|
||||
void print_info(const rsx::decompiled_program& program)
|
||||
void print_info(const rsx::decompiled_shader& program)
|
||||
{
|
||||
//std::cout << "[RAW CODE]" << std::endl;
|
||||
//std::cout << program.code;
|
||||
|
||||
rsx::complete_program complete_program = rsx::finalize_program(program);
|
||||
rsx::complete_shader complete_program = rsx::finalize_program(program);
|
||||
std::cout << "[COMPLETE CODE]" << std::endl;
|
||||
std::cout << complete_program.code;
|
||||
|
||||
@@ -324,9 +335,9 @@ int main(int argc, char** argv)
|
||||
extract_ucode("tmp.fp.cg", "tmp.fp.ucode");
|
||||
extract_ucode("tmp.vp.cg", "tmp.vp.ucode");
|
||||
|
||||
rsx::decompiled_program program;
|
||||
rsx::decompiled_shader program;
|
||||
|
||||
if (0)
|
||||
if (1)
|
||||
{
|
||||
using namespace rsx::fragment_program;
|
||||
std::vector<char> file = load_file("tmp.fp.ucode");
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="rsx_program_decompiler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CgBinaryProgram.h" />
|
||||
<ClInclude Include="elf64.h" />
|
||||
<ClInclude Include="endianness.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -75,7 +80,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)shader_code/;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
@@ -88,7 +93,7 @@
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)shader_code/;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
@@ -98,7 +103,7 @@
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)shader_code/;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
@@ -108,7 +113,7 @@
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(SolutionDir)rsx_program_decompiler_lib\;$(SolutionDir)shader_code/;$(SolutionDir)rsx_decompiler\;$(IncludePath)</IncludePath>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -3,4 +3,9 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="rsx_program_decompiler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CgBinaryProgram.h" />
|
||||
<ClInclude Include="endianness.h" />
|
||||
<ClInclude Include="elf64.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "rsx_glsl_fragment_program_decompiler.h"
|
||||
#include "rsx_glsl_vertex_program_decompiler.h"
|
||||
@@ -1,211 +0,0 @@
|
||||
#pragma once
|
||||
#include "fmt.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace fragment_program
|
||||
{
|
||||
enum class opcode
|
||||
{
|
||||
NOP = 0x00, // No-Operation
|
||||
MOV = 0x01, // Move
|
||||
MUL = 0x02, // Multiply
|
||||
ADD = 0x03, // Add
|
||||
MAD = 0x04, // Multiply-Add
|
||||
DP3 = 0x05, // 3-component Dot Product
|
||||
DP4 = 0x06, // 4-component Dot Product
|
||||
DST = 0x07, // Distance
|
||||
MIN = 0x08, // Minimum
|
||||
MAX = 0x09, // Maximum
|
||||
SLT = 0x0A, // Set-If-LessThan
|
||||
SGE = 0x0B, // Set-If-GreaterEqual
|
||||
SLE = 0x0C, // Set-If-LessEqual
|
||||
SGT = 0x0D, // Set-If-GreaterThan
|
||||
SNE = 0x0E, // Set-If-NotEqual
|
||||
SEQ = 0x0F, // Set-If-Equal
|
||||
FRC = 0x10, // Fraction (fract)
|
||||
FLR = 0x11, // Floor
|
||||
KIL = 0x12, // Kill fragment
|
||||
PK4 = 0x13, // Pack four signed 8-bit values
|
||||
UP4 = 0x14, // Unpack four signed 8-bit values
|
||||
DDX = 0x15, // Partial-derivative in x (Screen space derivative w.r.t. x)
|
||||
DDY = 0x16, // Partial-derivative in y (Screen space derivative w.r.t. y)
|
||||
TEX = 0x17, // Texture lookup
|
||||
TXP = 0x18, // Texture sample with projection (Projective texture lookup)
|
||||
TXD = 0x19, // Texture sample with partial differentiation (Texture lookup with derivatives)
|
||||
RCP = 0x1A, // Reciprocal
|
||||
RSQ = 0x1B, // Reciprocal Square Root
|
||||
EX2 = 0x1C, // Exponentiation base 2
|
||||
LG2 = 0x1D, // Log base 2
|
||||
LIT = 0x1E, // Lighting coefficients
|
||||
LRP = 0x1F, // Linear Interpolation
|
||||
STR = 0x20, // Set-If-True
|
||||
SFL = 0x21, // Set-If-False
|
||||
COS = 0x22, // Cosine
|
||||
SIN = 0x23, // Sine
|
||||
PK2 = 0x24, // Pack two 16-bit floats
|
||||
UP2 = 0x25, // Unpack two 16-bit floats
|
||||
POW = 0x26, // Power
|
||||
PKB = 0x27, // Pack bytes
|
||||
UPB = 0x28, // Unpack bytes
|
||||
PK16 = 0x29, // Pack 16 bits
|
||||
UP16 = 0x2A, // Unpack 16
|
||||
BEM = 0x2B, // Bump-environment map (a.k.a. 2D coordinate transform)
|
||||
PKG = 0x2C, // Pack with sRGB transformation
|
||||
UPG = 0x2D, // Unpack gamma
|
||||
DP2A = 0x2E, // 2-component dot product with scalar addition
|
||||
TXL = 0x2F, // Texture sample with explicit LOD
|
||||
TXB = 0x31, // Texture sample with bias
|
||||
TEXBEM = 0x33,
|
||||
TXPBEM = 0x34,
|
||||
BEMLUM = 0x35,
|
||||
REFL = 0x36, // Reflection vector
|
||||
TIMESWTEX = 0x37,
|
||||
DP2 = 0x38, // 2-component dot product
|
||||
NRM = 0x39, // Normalize
|
||||
DIV = 0x3A, // Division
|
||||
DIVSQ = 0x3B, // Divide by Square Root
|
||||
LIF = 0x3C, // Final part of LIT
|
||||
FENCT = 0x3D, // Fence T?
|
||||
FENCB = 0x3E, // Fence B?
|
||||
BRK = 0x40, // Break
|
||||
CAL = 0x41, // Subroutine call
|
||||
IFE = 0x42, // If
|
||||
LOOP = 0x43, // Loop
|
||||
REP = 0x44, // Repeat
|
||||
RET = 0x45 // Return
|
||||
};
|
||||
|
||||
union alignas(4) OPDEST
|
||||
{
|
||||
u32 HEX;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 end : 1; // Set to 1 if this is the last instruction
|
||||
u32 dest_reg : 6; // Destination register index
|
||||
u32 fp16 : 1; // Destination is a half register (H0 to H47)
|
||||
u32 set_cond : 1; // Condition Code Registers (CC0 and CC1) are updated
|
||||
u32 mask_x : 1;
|
||||
u32 mask_y : 1;
|
||||
u32 mask_z : 1;
|
||||
u32 mask_w : 1;
|
||||
u32 src_attr_reg_num : 4;
|
||||
u32 tex_num : 4;
|
||||
u32 exp_tex : 1; // _bx2
|
||||
u32 prec : 2;
|
||||
u32 opcode : 6;
|
||||
u32 no_dest : 1;
|
||||
u32 saturate : 1; // _sat
|
||||
};
|
||||
};
|
||||
|
||||
union alignas(4) SRC0
|
||||
{
|
||||
u32 HEX;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 reg_type : 2;
|
||||
u32 tmp_reg_index : 6;
|
||||
u32 fp16 : 1;
|
||||
u32 swizzle_x : 2;
|
||||
u32 swizzle_y : 2;
|
||||
u32 swizzle_z : 2;
|
||||
u32 swizzle_w : 2;
|
||||
u32 neg : 1;
|
||||
u32 exec_if_lt : 1;
|
||||
u32 exec_if_eq : 1;
|
||||
u32 exec_if_gr : 1;
|
||||
u32 cond_swizzle_x : 2;
|
||||
u32 cond_swizzle_y : 2;
|
||||
u32 cond_swizzle_z : 2;
|
||||
u32 cond_swizzle_w : 2;
|
||||
u32 abs : 1;
|
||||
u32 cond_mod_reg_index : 1;
|
||||
u32 cond_reg_index : 1;
|
||||
};
|
||||
};
|
||||
|
||||
union alignas(4) SRC1
|
||||
{
|
||||
u32 HEX;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 reg_type : 2;
|
||||
u32 tmp_reg_index : 6;
|
||||
u32 fp16 : 1;
|
||||
u32 swizzle_x : 2;
|
||||
u32 swizzle_y : 2;
|
||||
u32 swizzle_z : 2;
|
||||
u32 swizzle_w : 2;
|
||||
u32 neg : 1;
|
||||
u32 abs : 1;
|
||||
u32 input_mod_src0 : 3;
|
||||
u32: 6;
|
||||
u32 scale : 3;
|
||||
u32 opcode_is_branch : 1;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 else_offset : 31;
|
||||
u32: 1;
|
||||
};
|
||||
|
||||
// LOOP, REP
|
||||
struct
|
||||
{
|
||||
u32: 2;
|
||||
u32 end_counter : 8; // End counter value for LOOP or rep count for REP
|
||||
u32 init_counter : 8; // Initial counter value for LOOP
|
||||
u32: 1;
|
||||
u32 increment : 8; // Increment value for LOOP
|
||||
};
|
||||
};
|
||||
|
||||
union alignas(4) SRC2
|
||||
{
|
||||
u32 HEX;
|
||||
|
||||
u32 end_offset;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 reg_type : 2;
|
||||
u32 tmp_reg_index : 6;
|
||||
u32 fp16 : 1;
|
||||
u32 swizzle_x : 2;
|
||||
u32 swizzle_y : 2;
|
||||
u32 swizzle_z : 2;
|
||||
u32 swizzle_w : 2;
|
||||
u32 neg : 1;
|
||||
u32 abs : 1;
|
||||
u32 addr_reg : 11;
|
||||
u32 use_index_reg : 1;
|
||||
u32 perspective_corr : 1;
|
||||
};
|
||||
};
|
||||
static const char* input_attr_regs[] =
|
||||
{
|
||||
"WPOS", "COL0", "COL1", "FOGC", "TEX0",
|
||||
"TEX1", "TEX2", "TEX3", "TEX4", "TEX5",
|
||||
"TEX6", "TEX7", "TEX8", "TEX9", "SSA"
|
||||
};
|
||||
|
||||
static const std::string instructions_names[] =
|
||||
{
|
||||
"NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DP4",
|
||||
"DST", "MIN", "MAX", "SLT", "SGE", "SLE", "SGT",
|
||||
"SNE", "SEQ", "FRC", "FLR", "KIL", "PK4", "UP4",
|
||||
"DDX", "DDY", "TEX", "TXP", "TXD", "RCP", "RSQ",
|
||||
"EX2", "LG2", "LIT", "LRP", "STR", "SFL", "COS",
|
||||
"SIN", "PK2", "UP2", "POW", "PKB", "UPB", "PK16",
|
||||
"UP16", "BEM", "PKG", "UPG", "DP2A", "TXL", "NULL",
|
||||
"TXB", "NULL", "TEXBEM", "TXPBEM", "BEMLUM", "REFL", "TIMESWTEX",
|
||||
"DP2", "NRM", "DIV", "DIVSQ", "LIF", "FENCT", "FENCB",
|
||||
"NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
#pragma once
|
||||
#include "rsx_fragment_program.h"
|
||||
#include "rsx_program_decompiler.h"
|
||||
#include <unordered_set>
|
||||
#include "endianness.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace fragment_program
|
||||
{
|
||||
enum suffix
|
||||
{
|
||||
suffix_none,
|
||||
H = 1 << 0,
|
||||
C = 1 << 1
|
||||
};
|
||||
|
||||
template<int size> struct dest {};
|
||||
template<int index, int size, bool apply_dst_mask = true> struct src {};
|
||||
struct texture {};
|
||||
struct addr {};
|
||||
struct cond {};
|
||||
template<typename T> struct arg {};
|
||||
|
||||
union alignas(16) ucode_data
|
||||
{
|
||||
struct alignas(16)
|
||||
{
|
||||
OPDEST dst;
|
||||
SRC0 src0;
|
||||
SRC1 src1;
|
||||
SRC2 src2;
|
||||
};
|
||||
|
||||
u32 data[4];
|
||||
|
||||
ucode_data unpack()
|
||||
{
|
||||
ucode_data result;
|
||||
|
||||
result.data[0] = endianness::swap(data[0]); result.data[0] = (result.data[0] << 16) | (result.data[0] >> 16);
|
||||
result.data[1] = endianness::swap(data[1]); result.data[1] = (result.data[1] << 16) | (result.data[1] >> 16);
|
||||
result.data[2] = endianness::swap(data[2]); result.data[2] = (result.data[2] << 16) | (result.data[2] >> 16);
|
||||
result.data[3] = endianness::swap(data[3]); result.data[3] = (result.data[3] << 16) | (result.data[3] >> 16);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(ucode_data) == 4 * 4, "bad ucode_data");
|
||||
|
||||
template<typename decompiler_impl>
|
||||
class decompiler;
|
||||
|
||||
template<opcode id, u32 flags, typename... Tuple>
|
||||
struct handle_instruction
|
||||
{
|
||||
};
|
||||
|
||||
template<opcode id, u32 flags, typename... Tuple>
|
||||
struct instruction
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
static void impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
handle_instruction < id, flags, Tuple... >::function(decompiler);
|
||||
}
|
||||
};
|
||||
|
||||
using MOV = instruction < opcode::MOV, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using MUL = instruction < opcode::MUL, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using ADD = instruction < opcode::ADD, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using MAD = instruction < opcode::MAD, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>>, arg<src<2, 4>> >;
|
||||
using DP3 = instruction < opcode::DP3, H | C, dest<3>, arg<src<0, 3, false>>, arg<src<1, 3, false>> >;
|
||||
using DP4 = instruction < opcode::DP4, H | C, dest<4>, arg<src<0, 4, false>>, arg<src<1, 4, false>> >;
|
||||
using DST = instruction < opcode::DST, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using MIN = instruction < opcode::MIN, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using MAX = instruction < opcode::MAX, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SLT = instruction < opcode::SLT, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SGE = instruction < opcode::SGE, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SLE = instruction < opcode::SLE, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SGT = instruction < opcode::SGT, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SNE = instruction < opcode::SNE, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using SEQ = instruction < opcode::SEQ, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using FRC = instruction < opcode::FRC, H | C, dest<4>, arg<src<0, 1>> >;
|
||||
using FLR = instruction < opcode::FLR, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using KIL = instruction < opcode::KIL, suffix_none, arg<cond> >;
|
||||
using PK4 = instruction < opcode::PK4, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using UP4 = instruction < opcode::UP4, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using DDX = instruction < opcode::DDX, H | C, dest<2>, arg<src<0, 2> > >;
|
||||
using DDY = instruction < opcode::DDY, H | C, dest<2>, arg<src<0, 2> > >;
|
||||
using TEX = instruction < opcode::TEX, H | C, dest<4>, arg<src<0, 4>>, arg<texture> >;
|
||||
using TXP = instruction < opcode::TXP, H | C, dest<4>, arg<src<0, 4>>, arg<texture> >;
|
||||
using TXD = instruction < opcode::TXD, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using RCP = instruction < opcode::RCP, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using RSQ = instruction < opcode::RSQ, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using EX2 = instruction < opcode::EX2, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using LG2 = instruction < opcode::LG2, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using LIT = instruction < opcode::LIT, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using LRP = instruction < opcode::LRP, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using STR = instruction < opcode::STR, H | C, dest<4> >;
|
||||
using SFL = instruction < opcode::SFL, H | C, dest<4> >;
|
||||
using COS = instruction < opcode::COS, H | C, dest<4>, arg<src<0, 1> > >;
|
||||
using SIN = instruction < opcode::SIN, H | C, dest<4>, arg<src<0, 1> > >;
|
||||
using PK2 = instruction < opcode::PK2, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using UP2 = instruction < opcode::UP2, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using POW = instruction < opcode::POW, H | C, dest<4>, arg<src<0, 4> >, arg<src<1, 4> > >;
|
||||
using PKB = instruction < opcode::PKB, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using UPB = instruction < opcode::UPB, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using PK16 = instruction < opcode::PK16, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using UP16 = instruction < opcode::UP16, H | C, dest<4>, arg<src<0, 4> > >;
|
||||
using BEM = instruction < opcode::BEM, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using PKG = instruction < opcode::PKG, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using UPG = instruction < opcode::UPG, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using DP2A = instruction < opcode::DP2A, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using TXL = instruction < opcode::TXL, H | C, dest<4>, arg<src<0, 4>>, arg<texture> >;
|
||||
using TXB = instruction < opcode::TXB, H | C, dest<4>, arg<src<0, 4>>, arg<texture> >;
|
||||
using TEXBEM = instruction < opcode::TEXBEM, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using TXPBEM = instruction < opcode::TXPBEM, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using BEMLUM = instruction < opcode::BEMLUM, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using REFL = instruction < opcode::REFL, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using TIMESWTEX = instruction < opcode::TIMESWTEX, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using DP2 = instruction < opcode::DP2, H | C, dest<2>, arg<src<0, 2, false>>, arg<src<1, 2, false>> >;
|
||||
using NRM = instruction < opcode::NRM, H | C, dest<4>, arg<src<0, 4>> >;
|
||||
using DIV = instruction < opcode::DIV, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using DIVSQ = instruction < opcode::DIVSQ, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
|
||||
using LIF = instruction < opcode::LIF, H >;
|
||||
using FENCT = instruction < opcode::FENCT, suffix_none >;
|
||||
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, suffix_none, arg<cond> >;
|
||||
using LOOP = instruction < opcode::LOOP, H >;
|
||||
using REP = instruction < opcode::REP, H >;
|
||||
using RET = instruction < opcode::RET, H >;
|
||||
|
||||
template<typename decompiler_impl>
|
||||
using instruction_impl_func = void(*)(decompiler<decompiler_impl>&);
|
||||
|
||||
struct info : program_info
|
||||
{
|
||||
std::vector<u32> constant_offsets;
|
||||
};
|
||||
|
||||
template<opcode id, u32 flags, typename... args_type>
|
||||
struct handle_instruction < id, flags, arg<args_type>... >
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static void function(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
decompiler.nodest_instruction<id, flags>(decompiler.arg<args_type>()...);
|
||||
}
|
||||
};
|
||||
|
||||
template<opcode id, u32 flags, int dest_count, typename... args_type>
|
||||
struct handle_instruction < id, flags, dest<dest_count>, arg<args_type>... >
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static void function(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
decompiler.set_dst<id, flags, dest_count>(decompiler.arg<args_type>()...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename decompiler_impl>
|
||||
class decompiler : public program_decompiler_core
|
||||
{
|
||||
ucode_data* ucode_ptr;
|
||||
u32 ucode_size;
|
||||
u32 ucode_index;
|
||||
|
||||
public:
|
||||
bool is_next_constant = false;
|
||||
|
||||
fragment_program::info info;
|
||||
ucode_data ucode;
|
||||
u32 ctrl;
|
||||
|
||||
decompiler(void* ucode_ptr, u32 ucode_size, u32 ctrl = 0x40)
|
||||
: ucode_ptr((ucode_data*)ucode_ptr)
|
||||
, ucode_size(ucode_size)
|
||||
, ctrl(ctrl)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
struct expand_arg_t
|
||||
{
|
||||
};
|
||||
|
||||
template<int index, int count, bool apply_dst_mask>
|
||||
struct expand_arg_t<src<index, count, apply_dst_mask>>
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
program_variable_type variable_type = program_variable_type::none;
|
||||
program_variable variable = {};
|
||||
|
||||
variable.size = count;
|
||||
|
||||
bool is_fp16 = false;
|
||||
int type;
|
||||
|
||||
const auto& dst = decompiler.ucode.dst;
|
||||
const auto& src0 = decompiler.ucode.src0;
|
||||
const auto& src1 = decompiler.ucode.src1;
|
||||
const auto& src2 = decompiler.ucode.src2;
|
||||
|
||||
u8 swizzle_x, swizzle_y, swizzle_z, swizzle_w;
|
||||
|
||||
auto get_data_from = [&](auto &src)
|
||||
{
|
||||
is_fp16 = src.fp16;
|
||||
type = src.reg_type;
|
||||
variable.index = src.tmp_reg_index;
|
||||
swizzle_x = src.swizzle_x;
|
||||
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)
|
||||
{
|
||||
case 0: get_data_from(src0); break;
|
||||
case 1: get_data_from(src1); break;
|
||||
case 2: get_data_from(src2); break;
|
||||
}
|
||||
|
||||
bool need_declare = true;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0: //temporary register
|
||||
variable.name = is_fp16 ? "H" : "R";
|
||||
variable.type = program_variable_type::none;
|
||||
break;
|
||||
|
||||
case 1: //input register
|
||||
{
|
||||
variable.type = program_variable_type::input;
|
||||
|
||||
if (0)
|
||||
{
|
||||
variable.index = dst.src_attr_reg_num;
|
||||
variable.name = "fragment_input";
|
||||
variable.array_size = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const std::string register_table[] =
|
||||
{
|
||||
"position",
|
||||
"diff_color", "spec_color",
|
||||
"fogc",
|
||||
"tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8", "tc9",
|
||||
"ssa"
|
||||
};
|
||||
|
||||
variable.index = ~0;
|
||||
variable.type = program_variable_type::input;
|
||||
variable.name = register_table[dst.src_attr_reg_num];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: //constant
|
||||
need_declare = false;
|
||||
decompiler.is_next_constant = true;
|
||||
variable.constant.type = program_constant_type::f32;
|
||||
{
|
||||
ucode_data constant = decompiler.ucode_ptr[decompiler.ucode_index + 1].unpack();
|
||||
variable.constant.x.i32_value = constant.data[0];
|
||||
variable.constant.y.i32_value = constant.data[1];
|
||||
variable.constant.z.i32_value = constant.data[2];
|
||||
variable.constant.w.i32_value = constant.data[3];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
static const std::string mask = "xyzw";
|
||||
|
||||
std::string swizzle;
|
||||
swizzle += mask[swizzle_x];
|
||||
swizzle += mask[swizzle_y];
|
||||
swizzle += mask[swizzle_z];
|
||||
swizzle += mask[swizzle_w];
|
||||
|
||||
variable.mask.add(swizzle);
|
||||
|
||||
if (apply_dst_mask)
|
||||
{
|
||||
variable.mask.add(decompiler.dst_mask<count>().to_string()).symplify();
|
||||
}
|
||||
|
||||
if (count != 4)
|
||||
{
|
||||
std::string mask = variable.mask.to_string();
|
||||
if (mask.empty())
|
||||
mask = "xyzw";
|
||||
|
||||
variable.mask = mask_t{}.add(mask.substr(0, count));
|
||||
}
|
||||
|
||||
if (need_declare)
|
||||
variable = decompiler.info.vars.add(variable);
|
||||
|
||||
return variable;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct expand_arg_t<cond>
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
return decompiler.execution_condition_register();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct expand_arg_t<texture>
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
program_variable result = {};
|
||||
result.name = "texture";
|
||||
result.index = decompiler.ucode.dst.tex_num;
|
||||
result.size = 1;
|
||||
result.type = program_variable_type::texture;
|
||||
return decompiler.info.vars.add(decompiler_impl::texture_variable(result));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct expand_arg_t<addr>
|
||||
{
|
||||
template<typename decompiler_impl>
|
||||
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
|
||||
{
|
||||
return{ "label",{}, program_variable_type::none, 1, 0 };
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
std::unordered_set<std::string> functions_set;
|
||||
|
||||
template<int count>
|
||||
mask_t dst_mask()
|
||||
{
|
||||
static const std::string mask = "xyzw";
|
||||
|
||||
std::string swizzle;
|
||||
if (ucode.dst.mask_x) swizzle += mask[0];
|
||||
if (ucode.dst.mask_y) swizzle += mask[1];
|
||||
if (ucode.dst.mask_z) swizzle += mask[2];
|
||||
if (ucode.dst.mask_w) swizzle += mask[3];
|
||||
|
||||
return mask_t{}.add(swizzle.substr(0, count));
|
||||
}
|
||||
|
||||
template<u32 flags, int count>
|
||||
program_variable dst()
|
||||
{
|
||||
if (ucode.dst.no_dest)
|
||||
return{};
|
||||
|
||||
program_variable result = {};
|
||||
result.index = ucode.dst.dest_reg;
|
||||
result.name = ucode.dst.fp16 ? "H" : "R";
|
||||
result.size = count;
|
||||
result.mask = dst_mask<count>();
|
||||
|
||||
return info.vars.add(result);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
program_variable arg()
|
||||
{
|
||||
return expand_arg_t<T>::impl(*this);
|
||||
}
|
||||
|
||||
program_variable update_condition_register()
|
||||
{
|
||||
program_variable result = {};
|
||||
|
||||
result.name = "CC";
|
||||
result.index = ucode.src0.cond_mod_reg_index;
|
||||
result.size = 4;
|
||||
result.mask = dst_mask<4>();
|
||||
|
||||
return info.vars.add(result);
|
||||
}
|
||||
|
||||
program_variable execution_condition_register(bool exclusive_channels_only = false)
|
||||
{
|
||||
program_variable result = {};
|
||||
|
||||
result.name = "CC";
|
||||
result.index = ucode.src0.cond_reg_index;
|
||||
result.size = 4;
|
||||
|
||||
static const std::string mask = "xyzw";
|
||||
|
||||
std::string swizzle;
|
||||
|
||||
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, int tab_before = 0, int tab_after = 0, bool to_end = true)
|
||||
{
|
||||
program_decompiler_core::builder.add_code_block(ucode_index, code_line, tab_before, tab_after, to_end);
|
||||
}
|
||||
|
||||
template<opcode id, u32 flags, int count>
|
||||
void set_dst(const program_variable& arg0 = {}, const program_variable& arg1 = {}, const program_variable& arg2 = {})
|
||||
{
|
||||
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) + ") #"
|
||||
+ std::to_string(ucode_index));
|
||||
}
|
||||
|
||||
std::string function_begin(const std::string& name)
|
||||
{
|
||||
functions_set.insert(name);
|
||||
return decompiler_impl::function_begin(name);
|
||||
}
|
||||
|
||||
std::string function_end()
|
||||
{
|
||||
return decompiler_impl::function_end();
|
||||
}
|
||||
|
||||
public:
|
||||
fragment_program::info& decompile()
|
||||
{
|
||||
static const instruction_impl_func<decompiler_impl> instructions[0x80] =
|
||||
{
|
||||
nullptr, MOV::impl, MUL::impl, ADD::impl, MAD::impl, DP3::impl, DP4::impl,
|
||||
DST::impl, MIN::impl, MAX::impl, SLT::impl, SGE::impl, SLE::impl, SGT::impl,
|
||||
SNE::impl, SEQ::impl, FRC::impl, FLR::impl, KIL::impl, PK4::impl, UP4::impl,
|
||||
DDX::impl, DDY::impl, TEX::impl, TXP::impl, TXD::impl, RCP::impl, RSQ::impl,
|
||||
EX2::impl, LG2::impl, LIT::impl, LRP::impl, STR::impl, SFL::impl, COS::impl,
|
||||
SIN::impl, PK2::impl, UP2::impl, POW::impl, PKB::impl, UPB::impl, PK16::impl,
|
||||
UP16::impl, BEM::impl, PKG::impl, UPG::impl, DP2A::impl, TXL::impl, nullptr,
|
||||
TXB::impl, nullptr, TEXBEM::impl, TXPBEM::impl, BEMLUM::impl, REFL::impl, TIMESWTEX::impl,
|
||||
DP2::impl, NRM::impl, DIV::impl, DIVSQ::impl, LIF::impl, FENCT::impl, FENCB::impl,
|
||||
nullptr, BRK::impl, CAL::impl, IFE::impl, LOOP::impl, REP::impl, RET::impl
|
||||
};
|
||||
|
||||
for (ucode_index = 0; ucode_index < ucode_size; ++ucode_index)
|
||||
{
|
||||
if (is_next_constant)
|
||||
{
|
||||
is_next_constant = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
ucode = ucode_ptr[ucode_index].unpack();
|
||||
|
||||
const fragment_program::opcode opcode = fragment_program::opcode(ucode.dst.opcode | (ucode.src1.opcode_is_branch << 6));
|
||||
|
||||
if (opcode != fragment_program::opcode::NOP)
|
||||
{
|
||||
auto function = instructions[(std::size_t)opcode];
|
||||
|
||||
if (function)
|
||||
{
|
||||
function(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
unknown_instruction(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
if (ucode.dst.end)
|
||||
break;
|
||||
}
|
||||
|
||||
builder.add_code_block(0, function_begin("label0"), 0, 1, false);
|
||||
|
||||
std::string end = decompiler_impl::finalyze(this);
|
||||
|
||||
builder.add_code_block(0, decompiler_impl::get_header(this), 0, 0, false);
|
||||
builder.add_code_block(ucode_index, function_end(), -1, 0);
|
||||
builder.add_code_block(ucode_index, end);
|
||||
|
||||
info.text = builder.build();
|
||||
return info;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,549 +0,0 @@
|
||||
#pragma once
|
||||
#include "rsx_program_decompiler.h"
|
||||
#include "rsx_fragment_program_decompiler.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace fragment_program
|
||||
{
|
||||
struct glsl_decompiler_impl
|
||||
{
|
||||
using decompiler = fragment_program::decompiler < glsl_decompiler_impl >;
|
||||
|
||||
__forceinline static std::string get_header(decompiler* dec)
|
||||
{
|
||||
std::string result = "#version 420\n\n";
|
||||
for (auto &var : dec->info.vars)
|
||||
{
|
||||
switch (var.second.type)
|
||||
{
|
||||
case program_variable_type::input: result += "in "; break;
|
||||
case program_variable_type::output: result += "layout(location = " + std::to_string(var.second.index) + ") out "; break;
|
||||
case program_variable_type::constant: result += "uniform "; break;
|
||||
case program_variable_type::texture: result += "layout(binding = " + std::to_string(var.second.index) + ") uniform "; break;
|
||||
}
|
||||
|
||||
if (var.second.storage_type.empty())
|
||||
{
|
||||
if (var.second.size == 1)
|
||||
{
|
||||
var.second.storage_type = "float";
|
||||
}
|
||||
else
|
||||
{
|
||||
var.second.storage_type = "vec" + std::to_string(var.second.size);
|
||||
}
|
||||
}
|
||||
|
||||
result += var.second.storage_type + " " + var.second.name +
|
||||
(var.second.array_size ? ("[" + std::to_string(var.second.array_size + 1) + "]") :
|
||||
(var.second.index != ~0 ? std::to_string(var.second.index) : std::string{})) + ";\n";
|
||||
}
|
||||
|
||||
for (auto &func : dec->functions_set)
|
||||
{
|
||||
result += "void " + func + "();\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__forceinline static program_variable texture_variable(program_variable arg)
|
||||
{
|
||||
arg.storage_type = "sampler2D";
|
||||
return arg;
|
||||
}
|
||||
|
||||
__forceinline static std::string variable_to_string(const program_variable& arg)
|
||||
{
|
||||
fmt::string result;
|
||||
|
||||
if (arg.constant.type == program_constant_type::none)
|
||||
{
|
||||
result = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(arg.constant.type == program_constant_type::f32);
|
||||
|
||||
std::string mask = arg.mask.to_string();
|
||||
std::unordered_map<char, float> constant_map =
|
||||
{
|
||||
{ 'x', arg.constant.x.f32_value },
|
||||
{ 'y', arg.constant.y.f32_value },
|
||||
{ 'z', arg.constant.z.f32_value },
|
||||
{ 'w', arg.constant.w.f32_value },
|
||||
};
|
||||
|
||||
if (mask.empty())
|
||||
{
|
||||
result = fmt::format("vec4(%g, %g, %g, %g)",
|
||||
arg.constant.x.f32_value,
|
||||
arg.constant.y.f32_value,
|
||||
arg.constant.z.f32_value,
|
||||
arg.constant.w.f32_value);
|
||||
}
|
||||
else if (mask.size() == 1)
|
||||
{
|
||||
result = fmt::format("%g", constant_map[mask[0]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = fmt::format("vec%d(", mask.size());
|
||||
|
||||
for (size_t i = 0; i < mask.size(); ++i)
|
||||
{
|
||||
if (i)
|
||||
result += ", ";
|
||||
result += fmt::format("%g", constant_map[mask[i]]);
|
||||
}
|
||||
|
||||
result += ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.is_abs)
|
||||
result = "abs(" + result + ")";
|
||||
|
||||
if (arg.is_neg)
|
||||
result = "-" + result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__forceinline static std::string function_begin(const std::string& name)
|
||||
{
|
||||
return "\nvoid " + name + "()\n{";
|
||||
}
|
||||
|
||||
__forceinline static std::string function_end()
|
||||
{
|
||||
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)
|
||||
{
|
||||
opcode _id = id;
|
||||
|
||||
static const char operators[] =
|
||||
{
|
||||
'?', '?', '*', '+', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?',
|
||||
'?', '?', '/', '?', '?', '?', '?',
|
||||
'?', '?', '?', '?', '?', '?', '?'
|
||||
};
|
||||
|
||||
static const std::string functions[] =
|
||||
{
|
||||
"?", "?", "?", "?", "fma", "dot", "dot",
|
||||
"distantion", "min", "max", "lessThan", "greaterThanEquals", "lessThanEqual", "greaterThan",
|
||||
"notEqual", "equal", "fract", "floor", "?", "pk4", "up4",
|
||||
"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", "?",
|
||||
"txb", "?", "texbem", "txpbem", "bemlum", "refl", "timeswtex",
|
||||
"dot", "normalize", "?", "divsq", "lif", "fenct", "fencb",
|
||||
"?", "break", "cal", "ife", "loop", "rep", "return"
|
||||
};
|
||||
|
||||
fmt::string value;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case opcode::MOV:
|
||||
case opcode::MUL:
|
||||
case opcode::DIV:
|
||||
//operators
|
||||
|
||||
if (!arg0.is_null())
|
||||
{
|
||||
value = variable_to_string(arg0);
|
||||
|
||||
if (!arg1.is_null())
|
||||
{
|
||||
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) + ")";
|
||||
break;
|
||||
|
||||
case opcode::LIF:
|
||||
{
|
||||
program_variable arg0_y = arg0; arg0_y.mask.add("y");
|
||||
program_variable arg0_w = arg0; arg0_w.mask.add("w");
|
||||
std::string arg0_y_string = variable_to_string(arg0_y);
|
||||
std::string arg0_w_string = variable_to_string(arg0_w);
|
||||
|
||||
//vec4(1.0f, $0.y, ($0.y > 0 ? pow(2.0f, $0.w) : 0.0f), 1.0f)
|
||||
value += "vec4(1.0f, " + arg0_y_string + ", (" + arg0_y_string + " > 0.0f ? pow(2.0f, " + arg0_w_string + ") : 0.0f), 1.0f)";
|
||||
|
||||
//value += variable_to_string(arg0) + " / sqrt(" + variable_to_string(arg1) + ")";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//functions
|
||||
|
||||
value += functions[(std::size_t)id] + "(";
|
||||
|
||||
if (!arg0.is_null())
|
||||
{
|
||||
value += variable_to_string(arg0);
|
||||
|
||||
if (!arg1.is_null())
|
||||
{
|
||||
value += ", " + variable_to_string(arg1);
|
||||
|
||||
if (!arg2.is_null())
|
||||
{
|
||||
value += ", " + variable_to_string(arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value += ")";
|
||||
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)
|
||||
{
|
||||
case 0: //fp32, do nothing
|
||||
break;
|
||||
|
||||
case 1: //fp16, clamping
|
||||
value = "clamp(" + value + ", -65536, 65536)";
|
||||
break;
|
||||
|
||||
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 = 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) + "). ");
|
||||
}
|
||||
|
||||
if (dec->ucode.dst.saturate)
|
||||
{
|
||||
value = "clamp(" + value + ", 0, 1)";
|
||||
}
|
||||
}
|
||||
|
||||
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_register();
|
||||
do_update_condition = !update_condition.is_null();
|
||||
}
|
||||
|
||||
if (dec->ucode.src0.exec_if_eq && dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_lt)
|
||||
{
|
||||
std::string dst_string;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
dst_string = dst.to_string();
|
||||
result += dst_string + " = " + value + ";\n";
|
||||
}
|
||||
|
||||
if (do_update_condition)
|
||||
{
|
||||
result += update_condition.to_string() + " = " + (dst ? dst_string : value) + ";\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
program_variable execution_condition = dec->execution_condition_register();
|
||||
mask_t update_mask;
|
||||
update_mask
|
||||
.add(execution_condition.mask.to_string())
|
||||
.add(dst.mask.to_string());
|
||||
|
||||
update_mask = mask_t{}.add(update_mask.to_string().substr(0, count));
|
||||
|
||||
fmt::string execution_condition_string = execution_condition;
|
||||
std::string execution_condition_operation;
|
||||
|
||||
if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq)
|
||||
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 = "==";
|
||||
|
||||
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 : std::string("xyzw").substr(0, update_mask_string.size()))
|
||||
{
|
||||
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()).to_string();
|
||||
|
||||
if (channel_execution_condition_mask != last_condition_group)
|
||||
{
|
||||
if (!last_condition_group.empty())
|
||||
{
|
||||
result += "}\n";
|
||||
}
|
||||
|
||||
result += "if (" + channel_execution_condition.to_string() + " " + execution_condition_operation + " 0.0f)\n{\n";
|
||||
last_condition_group = channel_execution_condition_mask;
|
||||
last_line.clear();
|
||||
}
|
||||
|
||||
std::string channel_dst_string;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
auto channel_dst = dst;
|
||||
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 + " = " + mask.apply_to(value) + ";\n";
|
||||
|
||||
if (last_line == line)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += line;
|
||||
last_line = line;
|
||||
}
|
||||
|
||||
if (do_update_condition)
|
||||
{
|
||||
std::string cond_value = mask.apply_to(dst ? channel_dst_string : value);
|
||||
|
||||
result += "\t" + mask.apply_to(update_condition.to_string()) + " = " + cond_value + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_condition_group.empty())
|
||||
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";
|
||||
result += "\tlabel0();\n";
|
||||
|
||||
struct destination_info
|
||||
{
|
||||
std::string name;
|
||||
bool is_need_declare;
|
||||
};
|
||||
|
||||
const std::size_t color_source_registers[] =
|
||||
{
|
||||
{ 0 },
|
||||
{ 2 },
|
||||
{ 3 },
|
||||
{ 4 }
|
||||
};
|
||||
program_variable color_variable{};
|
||||
color_variable.type = program_variable_type::output;
|
||||
color_variable.size = 4;
|
||||
color_variable.name = "ocolor";
|
||||
|
||||
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] : 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))
|
||||
{
|
||||
color_variable.index = i;
|
||||
result += "\t" + dec->info.vars.add(color_variable).to_string() + " = " + color_register + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (dec->ctrl & 0xe)
|
||||
{
|
||||
if (dec->ctrl & 0x40)
|
||||
{
|
||||
if (dec->info.vars.exists("R1"))
|
||||
{
|
||||
result += "\tgl_FragDepth = R1.z;\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dec->info.vars.exists("H2"))
|
||||
{
|
||||
result += "\tgl_FragDepth = H2.z;\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result + "}";
|
||||
}
|
||||
};
|
||||
|
||||
using glsl_decompiler = decompiler < glsl_decompiler_impl >;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "rsx_vertex_program_decompiler.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace vertex_program
|
||||
{
|
||||
using glsl_decompiler = decompiler;
|
||||
}
|
||||
}
|
||||
@@ -1,335 +0,0 @@
|
||||
#include "rsx_program_decompiler.h"
|
||||
#include "fmt.h"
|
||||
#include <cctype>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
mask_t& mask_t::add(const std::string& mask)
|
||||
{
|
||||
if (!mask.empty())
|
||||
swizzles.push_back(mask);
|
||||
return *this;
|
||||
}
|
||||
|
||||
mask_t& mask_t::symplify()
|
||||
{
|
||||
if (swizzles.size() < 2)
|
||||
return *this;
|
||||
|
||||
std::unordered_map<char, char> swizzle;
|
||||
|
||||
static std::unordered_map<int, char> pos_to_swizzle =
|
||||
{
|
||||
{ 0, 'x' },
|
||||
{ 1, 'y' },
|
||||
{ 2, 'z' },
|
||||
{ 3, 'w' }
|
||||
};
|
||||
|
||||
auto it = swizzles.begin();
|
||||
|
||||
const std::string& sw_front = *it;
|
||||
|
||||
for (auto &i : pos_to_swizzle)
|
||||
{
|
||||
swizzle[i.second] = sw_front.length() > i.first ? sw_front[i.first] : 0;
|
||||
}
|
||||
|
||||
for (++it; it != swizzles.end(); ++it)
|
||||
{
|
||||
std::unordered_map<char, char> new_swizzle;
|
||||
|
||||
for (auto &sw : pos_to_swizzle)
|
||||
{
|
||||
new_swizzle[sw.second] = swizzle[it->length() <= sw.first ? '\0' : (*it)[sw.first]];
|
||||
}
|
||||
|
||||
swizzle = new_swizzle;
|
||||
}
|
||||
|
||||
swizzles.clear();
|
||||
std::string new_swizzle;
|
||||
|
||||
for (auto &i : pos_to_swizzle)
|
||||
{
|
||||
if (swizzle[i.second] != '\0')
|
||||
new_swizzle += swizzle[i.second];
|
||||
}
|
||||
|
||||
swizzles.push_back(new_swizzle);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string mask_t::to_string_impl() const
|
||||
{
|
||||
return fmt::merge(swizzles, ".");
|
||||
}
|
||||
|
||||
std::string mask_t::to_string() const
|
||||
{
|
||||
return to_string_impl();
|
||||
}
|
||||
|
||||
std::string mask_t::to_string()
|
||||
{
|
||||
return symplify().to_string_impl();
|
||||
}
|
||||
|
||||
std::string mask_t::apply_to(const std::string& expr) const
|
||||
{
|
||||
std::string mask = to_string();
|
||||
|
||||
if (mask.empty())
|
||||
return expr;
|
||||
|
||||
return 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)
|
||||
return name + "[" + std::to_string(index) + "]";
|
||||
|
||||
return index != ~0 ? name + std::to_string(index) : name;
|
||||
}
|
||||
|
||||
std::string program_variable::storage_name() const
|
||||
{
|
||||
return name + (array_size ? "[" + std::to_string(array_size + 1) + "]" : (index != ~0 ? std::to_string(index) : std::string{}));
|
||||
}
|
||||
|
||||
std::string program_variable::to_string() const
|
||||
{
|
||||
return mask.apply_to(to_string_impl());
|
||||
}
|
||||
|
||||
std::string program_variable::to_string()
|
||||
{
|
||||
return mask.symplify().apply_to(to_string_impl());
|
||||
}
|
||||
|
||||
bool program_variable::is_null() const
|
||||
{
|
||||
return name.empty() && constant.type == program_constant_type::none;
|
||||
}
|
||||
|
||||
program_variable::operator bool() const
|
||||
{
|
||||
return !is_null();
|
||||
}
|
||||
|
||||
program_variable& program_variables::add(const program_variable& var)
|
||||
{
|
||||
auto &new_var = m_data[var.storage_name()];
|
||||
new_var = var;
|
||||
|
||||
return new_var;
|
||||
}
|
||||
|
||||
const program_variable& program_variables::operator[](const std::string& name) const
|
||||
{
|
||||
auto found = m_data.find(name);
|
||||
if (found == m_data.end())
|
||||
throw std::logic_error("program_variables: program_variable '" + name + "' not found");
|
||||
|
||||
return found->second;
|
||||
}
|
||||
|
||||
program_variable& program_variables::operator[](const std::string& name)
|
||||
{
|
||||
auto found = m_data.find(name);
|
||||
if (found == m_data.end())
|
||||
throw std::logic_error("program_variables: program_variable '" + name + "' not found");
|
||||
|
||||
return found->second;
|
||||
}
|
||||
|
||||
bool program_variables::exists(const std::string& name) const
|
||||
{
|
||||
return m_data.find(name) != m_data.end();
|
||||
}
|
||||
|
||||
void program_variables::clear()
|
||||
{
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, program_variable>::iterator program_variables::begin()
|
||||
{
|
||||
return m_data.begin();
|
||||
}
|
||||
|
||||
std::unordered_map< std::string, program_variable>::iterator program_variables::end()
|
||||
{
|
||||
return m_data.end();
|
||||
}
|
||||
|
||||
void program_info::clear()
|
||||
{
|
||||
text.clear();
|
||||
vars.clear();
|
||||
}
|
||||
|
||||
void code_builder::add_code_block(size_t index, const std::string& lines, int tab_before, int tab_after, bool to_end)
|
||||
{
|
||||
auto& value = m_entries[index];
|
||||
std::list<code_line> code_lines;
|
||||
|
||||
const auto blocked_lines = fmt::split(lines, "\n", false);
|
||||
if (blocked_lines.size() == 1)
|
||||
{
|
||||
code_lines.push_back(code_line{ tab_before, tab_after, blocked_lines[0] });
|
||||
}
|
||||
else if (blocked_lines.size() > 1)
|
||||
{
|
||||
auto begin = blocked_lines.begin();
|
||||
auto end = blocked_lines.end() - 1;
|
||||
|
||||
code_lines.push_back(code_line{ tab_before, 0, *begin++ });
|
||||
while (begin != end)
|
||||
{
|
||||
code_lines.push_back(code_line{ 0, 0, *begin++ });
|
||||
}
|
||||
|
||||
code_lines.push_back(code_line{ 0, tab_after, blocked_lines.back() });
|
||||
}
|
||||
|
||||
value.code_lines.insert(to_end ? value.code_lines.end() : value.code_lines.begin(), code_lines.begin(), code_lines.end());
|
||||
}
|
||||
|
||||
void code_builder::branch(size_t from, size_t to, const std::string& condition)
|
||||
{
|
||||
if (from < to)
|
||||
{
|
||||
m_entries[from].branch_to.push_back({ to, condition });
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entries[to].branch_from.push_back({ from, condition });
|
||||
}
|
||||
}
|
||||
|
||||
void code_builder::build_branches()
|
||||
{
|
||||
std::vector<std::pair<size_t, size_t>> reserved_blocks;
|
||||
|
||||
auto is_reserved = [&](size_t begin, size_t end)
|
||||
{
|
||||
for (auto &block : reserved_blocks)
|
||||
{
|
||||
if (begin >= block.first && begin < block.second)
|
||||
{
|
||||
if (end < block.first || end > block.second)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto &entry : m_entries)
|
||||
{
|
||||
for (auto &binfo : entry.second.branch_to)
|
||||
{
|
||||
if (is_reserved(entry.first, binfo.index))
|
||||
{
|
||||
throw std::runtime_error("unhandled branch");
|
||||
}
|
||||
|
||||
add_code_block(entry.first, "if (!" + binfo.condition + ")\n{", 0, 1, true);
|
||||
add_code_block(binfo.index, "}", -1, 0, false);
|
||||
|
||||
reserved_blocks.push_back(std::make_pair(entry.first, binfo.index));
|
||||
}
|
||||
|
||||
for (auto &binfo : entry.second.branch_from)
|
||||
{
|
||||
if (is_reserved(entry.first, binfo.index))
|
||||
{
|
||||
throw std::runtime_error("unhandled branch");
|
||||
}
|
||||
|
||||
add_code_block(entry.first, "do\n{", 0, 1, true);
|
||||
add_code_block(binfo.index, "}\nwhile (" + binfo.condition + ");", -1, 0, false);
|
||||
|
||||
reserved_blocks.push_back(std::make_pair(entry.first, binfo.index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string code_builder::build_code() const
|
||||
{
|
||||
std::string result;
|
||||
int tab_count = 0;
|
||||
|
||||
for (auto &entry : m_entries)
|
||||
{
|
||||
for (auto &line : entry.second.code_lines)
|
||||
{
|
||||
tab_count += line.tab_before;
|
||||
|
||||
if (line.value.empty())
|
||||
{
|
||||
result += "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.append(tab_count, '\t') += line.value + "\n";
|
||||
}
|
||||
|
||||
tab_count += line.tab_after;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string code_builder::build()
|
||||
{
|
||||
build_branches();
|
||||
return build_code();
|
||||
}
|
||||
|
||||
program_info& program_decompiler_core::decompile()
|
||||
{
|
||||
info.text = builder.build();
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include "fmt.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum class program_variable_type
|
||||
{
|
||||
none,
|
||||
input,
|
||||
output,
|
||||
constant,
|
||||
texture
|
||||
};
|
||||
|
||||
struct mask_t
|
||||
{
|
||||
std::vector<std::string> swizzles;
|
||||
|
||||
mask_t& add(const std::string& mask);
|
||||
mask_t& symplify();
|
||||
|
||||
private:
|
||||
std::string to_string_impl() const;
|
||||
|
||||
public:
|
||||
std::string to_string() const;
|
||||
std::string to_string();
|
||||
|
||||
std::string apply_to(const std::string& expr) const;
|
||||
static std::string append_brackets_if_needed(const std::string& expr);
|
||||
};
|
||||
|
||||
|
||||
enum class program_constant_type
|
||||
{
|
||||
none,
|
||||
f32,
|
||||
f64,
|
||||
i32,
|
||||
i64
|
||||
};
|
||||
|
||||
struct program_constant
|
||||
{
|
||||
program_constant_type type;
|
||||
|
||||
union swizzle_t
|
||||
{
|
||||
float f32_value;
|
||||
double f64_value;
|
||||
u32 i32_value;
|
||||
u64 i64_value;
|
||||
};
|
||||
|
||||
swizzle_t x, y, z, w;
|
||||
};
|
||||
|
||||
struct program_variable
|
||||
{
|
||||
std::string name;
|
||||
mask_t mask;
|
||||
program_variable_type type;
|
||||
u32 index;
|
||||
u8 size;
|
||||
std::string storage_type;
|
||||
u32 array_size;
|
||||
bool is_neg;
|
||||
bool is_abs;
|
||||
std::string initialization;
|
||||
program_constant constant;
|
||||
|
||||
private:
|
||||
std::string to_string_impl() const;
|
||||
|
||||
public:
|
||||
std::string storage_name() const;
|
||||
std::string to_string() const;
|
||||
std::string to_string();
|
||||
bool is_null() const;
|
||||
explicit operator bool() const;
|
||||
};
|
||||
|
||||
class program_variables
|
||||
{
|
||||
std::unordered_map<std::string, program_variable> m_data;
|
||||
|
||||
public:
|
||||
program_variable& add(const program_variable& var);
|
||||
const program_variable& operator[](const std::string& name) const;
|
||||
program_variable& operator[](const std::string& name);
|
||||
bool exists(const std::string& name) const;
|
||||
|
||||
void clear();
|
||||
|
||||
std::unordered_map<std::string, program_variable>::iterator begin();
|
||||
std::unordered_map<std::string, program_variable>::iterator end();
|
||||
};
|
||||
|
||||
struct program_info
|
||||
{
|
||||
std::string text;
|
||||
program_variables vars;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
class code_builder
|
||||
{
|
||||
struct code_line
|
||||
{
|
||||
int tab_before;
|
||||
int tab_after;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct branch_info
|
||||
{
|
||||
size_t index;
|
||||
std::string condition;
|
||||
};
|
||||
|
||||
struct entry
|
||||
{
|
||||
std::list<branch_info> branch_to;
|
||||
std::list<branch_info> branch_from;
|
||||
std::list<code_line> code_lines;
|
||||
};
|
||||
|
||||
std::map<size_t, entry> m_entries;
|
||||
size_t next_index = 0;
|
||||
|
||||
public:
|
||||
void add_code_block(size_t index, const std::string& lines, int tab_before = 0, int tab_after = 0, bool to_end = true);
|
||||
void branch(size_t from, size_t to, const std::string& condition = {});
|
||||
void build_branches();
|
||||
std::string build_code() const;
|
||||
std::string build();
|
||||
};
|
||||
|
||||
struct program_decompiler_core
|
||||
{
|
||||
code_builder builder;
|
||||
program_info info;
|
||||
|
||||
program_info& decompile();
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace vertex_program
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "rsx_vertex_program_decompiler.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace vertex_program
|
||||
{
|
||||
void decompiler::test()
|
||||
{
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include "rsx_vertex_program.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace vertex_program
|
||||
{
|
||||
class decompiler
|
||||
{
|
||||
public:
|
||||
void test();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{f7aad20d-bcfa-4b17-a178-bd8606b4e1fe}</ProjectGuid>
|
||||
<Keyword>StaticLibrary</Keyword>
|
||||
<ProjectName>rsx_program_decompiler_lib</ProjectName>
|
||||
<RootNamespace>rsx_program_decompiler</RootNamespace>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<OutDir>$(SolutionDir)lib\$(Platform)-$(Configuration)\</OutDir>
|
||||
<TargetName>rsx_program_decompiler</TargetName>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</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" />
|
||||
<ClInclude Include="rsx\rsx_fragment_program_decompiler.h" />
|
||||
<ClInclude Include="rsx\rsx_glsl_fragment_program_decompiler.h" />
|
||||
<ClInclude Include="rsx\rsx_glsl_vertex_program_decompiler.h" />
|
||||
<ClInclude Include="rsx\rsx_program_decompiler.h" />
|
||||
<ClInclude Include="rsx\rsx_vertex_program.h" />
|
||||
<ClInclude Include="rsx\rsx_vertex_program_decompiler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="fmt.cpp" />
|
||||
<ClCompile Include="rsx\rsx_program_decompiler.cpp" />
|
||||
<ClCompile Include="rsx\rsx_vertex_program_decompiler.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="rsx">
|
||||
<UniqueIdentifier>{151c23cf-edbe-4ca4-9c6c-62d197083805}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="rsx\rsx.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_fragment_program.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_fragment_program_decompiler.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_glsl_fragment_program_decompiler.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_glsl_vertex_program_decompiler.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_vertex_program.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_vertex_program_decompiler.h">
|
||||
<Filter>rsx</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rsx\rsx_program_decompiler.h">
|
||||
<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">
|
||||
<Filter>rsx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rsx\rsx_vertex_program_decompiler.cpp">
|
||||
<Filter>rsx</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="fmt.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+87
-1
@@ -1,5 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "builder.h"
|
||||
#include "fmt.h"
|
||||
|
||||
namespace shader_code
|
||||
{
|
||||
@@ -18,8 +18,94 @@ namespace shader_code
|
||||
return to_string();
|
||||
}
|
||||
|
||||
|
||||
builder::writer_t::writer_t()
|
||||
{
|
||||
fill_to(position);
|
||||
}
|
||||
|
||||
builder::writer_t::writer_t(const std::string &string) : writer_t()
|
||||
{
|
||||
code[position] += string;
|
||||
}
|
||||
|
||||
void builder::writer_t::fill_to(std::size_t position)
|
||||
{
|
||||
if (code.size() <= position)
|
||||
{
|
||||
code.resize(position + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void builder::writer_t::before(std::size_t position, const std::string& string)
|
||||
{
|
||||
fill_to(position);
|
||||
code[position] = string + code[position];
|
||||
}
|
||||
|
||||
void builder::writer_t::after(std::size_t position, const std::string& string)
|
||||
{
|
||||
fill_to(position);
|
||||
code[position] += string;
|
||||
}
|
||||
|
||||
void builder::writer_t::lines(const writer_t& writer)
|
||||
{
|
||||
code[position] += writer.build();
|
||||
}
|
||||
|
||||
void builder::writer_t::next()
|
||||
{
|
||||
fill_to(++position);
|
||||
}
|
||||
|
||||
std::string builder::writer_t::finalize() const
|
||||
{
|
||||
std::string result;
|
||||
int lvl = 0;
|
||||
|
||||
for (const std::string &line : fmt::split(build(), "\n", false))
|
||||
{
|
||||
if (line.empty())
|
||||
{
|
||||
result += "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t line_pos = std::string::npos;
|
||||
|
||||
line_pos = std::string::npos;
|
||||
while ((line_pos = line.find('}', line_pos + 1)) != std::string::npos)
|
||||
{
|
||||
--lvl;
|
||||
}
|
||||
|
||||
result += std::string(lvl, '\t') + line + "\n";
|
||||
|
||||
while ((line_pos = line.find('{', line_pos + 1)) != std::string::npos)
|
||||
{
|
||||
++lvl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string builder::writer_t::build() const
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for (const std::string &entry : code)
|
||||
{
|
||||
result += entry;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void builder::writer_t::clear()
|
||||
{
|
||||
code.clear();
|
||||
}
|
||||
}
|
||||
+9
-53
@@ -28,23 +28,10 @@ namespace shader_code
|
||||
std::vector<std::string> code;
|
||||
std::size_t position = 0;
|
||||
|
||||
writer_t()
|
||||
{
|
||||
fill_to(position);
|
||||
}
|
||||
writer_t();
|
||||
writer_t(const std::string &string);
|
||||
|
||||
writer_t(const std::string &string) : writer_t()
|
||||
{
|
||||
lines(string);
|
||||
}
|
||||
|
||||
void fill_to(std::size_t position)
|
||||
{
|
||||
if (code.size() <= position)
|
||||
{
|
||||
code.resize(position + 1);
|
||||
}
|
||||
}
|
||||
void fill_to(std::size_t position);
|
||||
|
||||
template<typename... T>
|
||||
void lines(const T&... exprs)
|
||||
@@ -55,28 +42,9 @@ namespace shader_code
|
||||
}
|
||||
}
|
||||
|
||||
void lines(const std::string& string)
|
||||
{
|
||||
code[position] += string;
|
||||
}
|
||||
|
||||
void before(std::size_t position, const std::string& string)
|
||||
{
|
||||
fill_to(position);
|
||||
code[position] = string + code[position];
|
||||
}
|
||||
|
||||
void after(std::size_t position, const std::string& string)
|
||||
{
|
||||
fill_to(position);
|
||||
code[position] += string;
|
||||
}
|
||||
|
||||
void lines(const writer_t& writer)
|
||||
{
|
||||
lines(writer.build());
|
||||
}
|
||||
|
||||
void before(std::size_t position, const std::string& string);
|
||||
void after(std::size_t position, const std::string& string);
|
||||
void lines(const writer_t& writer);
|
||||
void next();
|
||||
|
||||
template<typename T>
|
||||
@@ -91,22 +59,10 @@ namespace shader_code
|
||||
return{ build() };
|
||||
}
|
||||
|
||||
std::string build() const
|
||||
{
|
||||
std::string result;
|
||||
std::string finalize() const;
|
||||
std::string build() const;
|
||||
|
||||
for (const std::string &entry : code)
|
||||
{
|
||||
result += entry;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
code.clear();
|
||||
}
|
||||
void clear();
|
||||
};
|
||||
};
|
||||
}
|
||||
+127
-116
@@ -5,15 +5,17 @@
|
||||
namespace shader_code
|
||||
{
|
||||
template<typename Language>
|
||||
struct clike_builder : clike_language, builder
|
||||
struct clike_builder : public clike_language, public builder
|
||||
{
|
||||
using language = Language;
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
struct type_helper_t : clike_language::type_t<Type, Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
struct type_helper_t : public clike_language::type_t<Type, Count>
|
||||
{
|
||||
using base = typename clike_language::type_t<Type, Count>;
|
||||
|
||||
protected:
|
||||
template<type_class_t ExprType = Type, int ExprCount = Count>
|
||||
template<clike_language::type_class_t ExprType = Type, int ExprCount = Count>
|
||||
using expression_t = typename clike_language::expression_t<ExprType, ExprCount>;
|
||||
|
||||
public:
|
||||
@@ -27,131 +29,140 @@ namespace shader_code
|
||||
return invoke(expression_t<Type, 1>(native_type_t<Type>::to_string(value)));
|
||||
}
|
||||
|
||||
template<type_class_t FromType>
|
||||
template<clike_language::type_class_t FromType>
|
||||
static expression_t<> ctor(expression_t<FromType> expr)
|
||||
{
|
||||
return invoke(expr);
|
||||
}
|
||||
|
||||
constexpr static const char* name()
|
||||
static constexpr const char* name()
|
||||
{
|
||||
return language::type_name_t<Type, Count>::name;
|
||||
using type_name_t = typename language::type_name_t<Type, Count>;
|
||||
return type_name_t::name;
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename... T>
|
||||
static expression_t<> invoke(T... exprs)
|
||||
{
|
||||
return function_t<clike_language::type_t<Type, Count>, language::type_name_t<Type, Count>>::invoke(exprs...);
|
||||
return function_t<clike_language::type_t<Type, Count>, typename language::type_name_t<Type, Count>>::invoke(exprs...);
|
||||
}
|
||||
};
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
struct type_t;
|
||||
|
||||
template<type_class_t Type>
|
||||
template<clike_language::type_class_t Type>
|
||||
struct type_t<Type, 1> : type_helper_t<Type, 1>
|
||||
{
|
||||
using type_helper_t::ctor;
|
||||
using type_helper_t<Type, 1>::ctor;
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
template<clike_language::type_class_t Type>
|
||||
struct type_t<Type, 2> : type_helper_t<Type, 2>
|
||||
{
|
||||
using type_helper_t::ctor;
|
||||
using base = type_helper_t<Type, 2>;
|
||||
using base::ctor;
|
||||
|
||||
template<type_class_t FromType>
|
||||
static expression_t<> ctor(expression_t<FromType, 1> expr)
|
||||
template<clike_language::type_class_t FromType>
|
||||
static typename base::expression_t<> ctor(typename base::expression_t<FromType, 1> expr)
|
||||
{
|
||||
return invoke(expr);
|
||||
return this->invoke(expr);
|
||||
}
|
||||
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 1> b)
|
||||
static typename base::expression_t<> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 1> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return this->invoke(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
template<clike_language::type_class_t Type>
|
||||
struct type_t<Type, 3> : type_helper_t<Type, 3>
|
||||
{
|
||||
using type_helper_t::ctor;
|
||||
using base = type_helper_t<Type, 3>;
|
||||
using base::ctor;
|
||||
|
||||
template<type_class_t FromType>
|
||||
static expression_t<> ctor(expression_t<FromType, 1> expr)
|
||||
template<clike_language::type_class_t FromType>
|
||||
static typename base::expression_t<> ctor(typename base::expression_t<FromType, 1> expr)
|
||||
{
|
||||
return invoke(expr);
|
||||
return this->invoke(expr);
|
||||
}
|
||||
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 2> b)
|
||||
static typename base::expression_t<Type, 3> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 2> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return this->invoke(a, b);
|
||||
}
|
||||
|
||||
static expression_t<> ctor(expression_t<Type, 2> a, expression_t<Type, 1> b)
|
||||
static typename base::expression_t<Type, 3> ctor(typename base::expression_t<Type, 2> a, typename base::expression_t<Type, 1> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return this->invoke(a, b);
|
||||
}
|
||||
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 1> b, expression_t<Type, 1> c)
|
||||
static typename base::expression_t<Type, 3> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 1> b,
|
||||
typename base::expression_t<Type, 1> c)
|
||||
{
|
||||
return invoke(a, b, c);
|
||||
return this->invoke(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
template<clike_language::type_class_t Type>
|
||||
struct type_t<Type, 4> : type_helper_t<Type, 4>
|
||||
{
|
||||
using type_helper_t::ctor;
|
||||
using base = type_helper_t<Type, 4>;
|
||||
using base::ctor;
|
||||
|
||||
template<type_class_t FromType>
|
||||
static expression_t<> ctor(expression_t<FromType, 1> expr)
|
||||
template<clike_language::type_class_t FromType>
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<FromType, 1> expr)
|
||||
{
|
||||
return invoke(expr);
|
||||
return base::invoke(expr);
|
||||
}
|
||||
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 3> b)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 3> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return base::invoke(a, b);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 3> a, expression_t<Type, 1> b)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 3> a, typename base::expression_t<Type, 1> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return base::invoke(a, b);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 2> a, expression_t<Type, 2> b)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 2> a, typename base::expression_t<Type, 2> b)
|
||||
{
|
||||
return invoke(a, b);
|
||||
return base::invoke(a, b);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 1> b, expression_t<Type, 1> c, expression_t<Type, 1> d)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 1> b,
|
||||
typename base::expression_t<Type, 1> c, typename base::expression_t<Type, 1> d)
|
||||
{
|
||||
return invoke(a, b, c, d);
|
||||
return base::invoke(a, b, c, d);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 2> a, expression_t<Type, 1> b, expression_t<Type, 1> c)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 2> a, typename base::expression_t<Type, 1> b,
|
||||
typename base::expression_t<Type, 1> c)
|
||||
{
|
||||
return invoke(a, b, c);
|
||||
return base::invoke(a, b, c);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 2> b, expression_t<Type, 1> c)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 2> b,
|
||||
typename base::expression_t<Type, 1> c)
|
||||
{
|
||||
return invoke(a, b, c);
|
||||
return base::invoke(a, b, c);
|
||||
}
|
||||
static expression_t<> ctor(expression_t<Type, 1> a, expression_t<Type, 1> b, expression_t<Type, 2> c)
|
||||
static typename base::expression_t<Type, 4> ctor(typename base::expression_t<Type, 1> a, typename base::expression_t<Type, 1> b,
|
||||
typename base::expression_t<Type, 2> c)
|
||||
{
|
||||
return invoke(a, b, c);
|
||||
return base::invoke(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
using sampler1D_t = typename type_t<type_class_t::type_sampler1D, 1>;
|
||||
using sampler2D_t = typename type_t<type_class_t::type_sampler2D, 1>;
|
||||
using sampler3D_t = typename type_t<type_class_t::type_sampler3D, 1>;
|
||||
using sampler1D_t = typename type_t<clike_language::type_class_t::type_sampler1D, 1>;
|
||||
using sampler2D_t = typename type_t<clike_language::type_class_t::type_sampler2D, 1>;
|
||||
using sampler3D_t = typename type_t<clike_language::type_class_t::type_sampler3D, 1>;
|
||||
|
||||
template<size_t Count>
|
||||
using boolean_t = typename type_t<type_class_t::type_bool, Count>;
|
||||
using boolean_t = typename type_t<clike_language::type_class_t::type_bool, Count>;
|
||||
|
||||
template<size_t Count>
|
||||
using integer_t = typename type_t<type_class_t::type_int, Count>;
|
||||
using integer_t = typename type_t<clike_language::type_class_t::type_int, Count>;
|
||||
|
||||
template<size_t Count>
|
||||
using float_point_t = typename type_t<type_class_t::type_float, Count>;
|
||||
using float_point_t = typename type_t<clike_language::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>>;
|
||||
@@ -160,187 +171,187 @@ namespace shader_code
|
||||
|
||||
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);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
}
|
||||
|
||||
static expression_from<float_point_t<4>> texture(const expression_from<sampler2D_t>& texture, const expression_from<float_point_t<2>>& coord)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
}
|
||||
|
||||
static expression_from<float_point_t<4>> texture_lod(const expression_from<sampler2D_t>& texture, const expression_from<float_point_t<2>>& coord, const expression_from<float_point_t<1>>& lod)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture_lod>>::invoke(texture, coord, lod);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture_lod>>::invoke(texture, coord, lod);
|
||||
}
|
||||
|
||||
static expression_from<float_point_t<4>> texture_bias(const expression_from<sampler2D_t>& texture, const expression_from<float_point_t<2>>& coord, const expression_from<float_point_t<1>>& bias)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture_bias>>::invoke(texture, coord, bias);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture_bias>>::invoke(texture, coord, bias);
|
||||
}
|
||||
|
||||
static expression_from<float_point_t<4>> texture_grad(const expression_from<sampler2D_t>& texture, const expression_from<float_point_t<2>>& coord, const expression_from<float_point_t<2>>& ddx, const expression_from<float_point_t<2>>& ddy)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture_grad>>::invoke(texture, coord, ddx, ddy);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture_grad>>::invoke(texture, coord, ddx, ddy);
|
||||
}
|
||||
|
||||
static expression_from<float_point_t<4>> texture(const expression_from<sampler3D_t>& texture, const expression_from<float_point_t<3>>& coord)
|
||||
{
|
||||
return function_t<float_point_t<4>, language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
return function_t<float_point_t<4>, typename language::function_name_t<function_class_t::function_texture>>::invoke(texture, coord);
|
||||
}
|
||||
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> normalize(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> normalize(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_normalize>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_normalize>>::invoke(arg);
|
||||
}
|
||||
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> abs(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> abs(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_abs>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_abs>>::invoke(arg);
|
||||
}
|
||||
|
||||
template<int Count>
|
||||
static expression_from<integer_t<Count>> abs(const expression_t<type_class_t::type_int, Count>& arg)
|
||||
static expression_from<integer_t<Count>> abs(const expression_t<clike_language::type_class_t::type_int, Count>& arg)
|
||||
{
|
||||
return function_t<integer_t<Count>, language::function_name_t<function_class_t::function_abs>>::invoke(arg);
|
||||
return function_t<integer_t<Count>, typename language::function_name_t<function_class_t::function_abs>>::invoke(arg);
|
||||
}
|
||||
|
||||
template<int Count>
|
||||
static expression_from<boolean_t<1>> any(const expression_t<type_class_t::type_bool, Count>& arg)
|
||||
static expression_from<boolean_t<1>> any(const expression_t<clike_language::type_class_t::type_bool, Count>& arg)
|
||||
{
|
||||
return function_t<boolean_t<1>, language::function_name_t<function_class_t::function_any>>::invoke(arg);
|
||||
return function_t<boolean_t<1>, typename language::function_name_t<function_class_t::function_any>>::invoke(arg);
|
||||
}
|
||||
|
||||
template<int Count, typename = std::enable_if_t<(Count > 1)>>
|
||||
static expression_from<boolean_t<1>> all(const expression_t<type_class_t::type_bool, Count>& arg)
|
||||
static expression_from<boolean_t<1>> all(const expression_t<clike_language::type_class_t::type_bool, Count>& arg)
|
||||
{
|
||||
return function_t<boolean_t<1>, language::function_name_t<function_class_t::function_all>>::invoke(arg);
|
||||
return function_t<boolean_t<1>, typename language::function_name_t<function_class_t::function_all>>::invoke(arg);
|
||||
}
|
||||
|
||||
template<int Count, typename = std::enable_if_t<(Count > 1)>>
|
||||
static expression_from<float_point_t<1>> dot(const expression_t<type_class_t::type_float, Count>& a, const expression_t<type_class_t::type_float, Count>& b)
|
||||
static expression_from<float_point_t<1>> dot(const expression_t<clike_language::type_class_t::type_float, Count>& a, const expression_t<clike_language::type_class_t::type_float, Count>& b)
|
||||
{
|
||||
return function_t<float_point_t<1>, language::function_name_t<function_class_t::function_dot>>::invoke(a, b);
|
||||
return function_t<float_point_t<1>, typename language::function_name_t<function_class_t::function_dot>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_t<Type, Count> min(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<type_t<Type, Count>, language::function_name_t<function_class_t::function_min>>::invoke(a, b);
|
||||
return function_t<type_t<Type, Count>, typename language::function_name_t<function_class_t::function_min>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_t<Type, Count> max(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<type_t<Type, Count>, language::function_name_t<function_class_t::function_max>>::invoke(a, b);
|
||||
return function_t<type_t<Type, Count>, typename language::function_name_t<function_class_t::function_max>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> greater(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_greater>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_greater>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> less(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_less>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_less>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> equal(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_equal>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_equal>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> greater_equal(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_greater_equal>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_greater_equal>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> less_equal(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_less_equal>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_less_equal>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
template<clike_language::type_class_t Type, int Count>
|
||||
static expression_from<boolean_t<Count>> not_equal(const expression_t<Type, Count>& a, const expression_t<Type, Count>& b)
|
||||
{
|
||||
return function_t<boolean_t<Count>, language::function_name_t<function_class_t::function_not_equal>>::invoke(a, b);
|
||||
return function_t<boolean_t<Count>, typename language::function_name_t<function_class_t::function_not_equal>>::invoke(a, b);
|
||||
}
|
||||
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> fract(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> fract(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_fract>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_fract>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> floor(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> floor(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_floor>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_floor>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> sin(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> sin(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_sin>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_sin>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> cos(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> cos(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_cos>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_cos>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> clamp(const expression_t<type_class_t::type_float, Count>& a, const expression_t<type_class_t::type_float, 1>& b, const expression_t<type_class_t::type_float, 1>& c)
|
||||
static expression_from<float_point_t<Count>> clamp(const expression_t<clike_language::type_class_t::type_float, Count>& a, const expression_t<clike_language::type_class_t::type_float, 1>& b, const expression_t<clike_language::type_class_t::type_float, 1>& c)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_clamp>>::invoke(a, b, c);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_clamp>>::invoke(a, b, c);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> sqrt(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> sqrt(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_sqrt>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_sqrt>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> rsqrt(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> rsqrt(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_rsqrt>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_rsqrt>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> pow(const expression_t<type_class_t::type_float, Count>& a, const expression_t<type_class_t::type_float, Count>& b)
|
||||
static expression_from<float_point_t<Count>> pow(const expression_t<clike_language::type_class_t::type_float, Count>& a, const expression_t<clike_language::type_class_t::type_float, Count>& b)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_pow>>::invoke(a, b);
|
||||
return function_t<float_point_t<Count>, typename 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)
|
||||
static expression_from<float_point_t<Count>> exp(const expression_t<clike_language::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);
|
||||
return function_t<float_point_t<Count>, typename 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)
|
||||
static expression_from<float_point_t<Count>> log(const expression_t<clike_language::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);
|
||||
return function_t<float_point_t<Count>, typename 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)
|
||||
static expression_from<float_point_t<Count>> exp2(const expression_t<clike_language::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);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_exp2>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> log2(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> log2(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_log2>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_log2>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> ddx(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> ddx(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_ddx>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_ddx>>::invoke(arg);
|
||||
}
|
||||
template<int Count>
|
||||
static expression_from<float_point_t<Count>> ddy(const expression_t<type_class_t::type_float, Count>& arg)
|
||||
static expression_from<float_point_t<Count>> ddy(const expression_t<clike_language::type_class_t::type_float, Count>& arg)
|
||||
{
|
||||
return function_t<float_point_t<Count>, language::function_name_t<function_class_t::function_ddy>>::invoke(arg);
|
||||
return function_t<float_point_t<Count>, typename language::function_name_t<function_class_t::function_ddy>>::invoke(arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "pch.h"
|
||||
#include "clike_language.h"
|
||||
|
||||
namespace shader_code
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace shader_code
|
||||
using expression_from = expression_t<Type::type, Type::count>;
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
struct expression_helper_t : builder::expression_base_t
|
||||
struct expression_helper_t : public builder::expression_base_t
|
||||
{
|
||||
using type = type_t<Type, Count>;
|
||||
|
||||
@@ -244,24 +244,29 @@ namespace shader_code
|
||||
};
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
struct expression_ctors_t : expression_helper_t<Type, Count>
|
||||
struct expression_ctors_t : public expression_helper_t<Type, Count>
|
||||
{
|
||||
using expression_helper_t::expression_helper_t;
|
||||
using base = expression_helper_t<Type, Count>;
|
||||
using base::base;
|
||||
|
||||
expression_ctors_t() = default;
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
struct expression_ctors_t<Type, 1> : expression_helper_t<Type, 1>
|
||||
struct expression_ctors_t<Type, 1> : public expression_helper_t<Type, 1>
|
||||
{
|
||||
using base = expression_helper_t<Type, 1>;
|
||||
|
||||
expression_ctors_t(typename native_type_t<Type>::type value)
|
||||
: expression_helper_t(native_type_t<Type>::to_string(value))
|
||||
: base::expression_helper_t(native_type_t<Type>::to_string(value))
|
||||
{
|
||||
}
|
||||
|
||||
using expression_helper_t::expression_helper_t;
|
||||
using base::base;
|
||||
};
|
||||
|
||||
#define _SWIZZLE_MASK(pos) mask.substr(pos, 1)
|
||||
#define _SWIZZLE_FUNC(Count, Name, ...) expression_t<Type, Count> Name() const { return swizzle(__VA_ARGS__); }
|
||||
#define _SWIZZLE_FUNC(Count, Name, ...) expression_t<Type, Count> Name() const { return base::swizzle(__VA_ARGS__); }
|
||||
|
||||
#define SWIZZLE1(Xn, Xv) _SWIZZLE_FUNC(1, Xn, (Xv))
|
||||
#define SWIZZLE2(Xn, Xv, Yn, Yv) _SWIZZLE_FUNC(2, Xn##Yn, Xv, Yv)
|
||||
@@ -362,15 +367,17 @@ namespace shader_code
|
||||
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
struct expression_swizzle_t : expression_ctors_t<Type, Count>
|
||||
struct expression_swizzle_t : public expression_ctors_t<Type, Count>
|
||||
{
|
||||
using expression_ctors_t::expression_ctors_t;
|
||||
using base = expression_ctors_t<Type, Count>;
|
||||
using base::base;
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
struct expression_swizzle_t<Type, 2> : expression_ctors_t<Type, 2>
|
||||
struct expression_swizzle_t<Type, 2> : public expression_ctors_t<Type, 2>
|
||||
{
|
||||
using expression_ctors_t::expression_ctors_t;
|
||||
using base = expression_ctors_t<Type, 2>;
|
||||
using base::base;
|
||||
|
||||
SWIZZLE1(x, 0)
|
||||
SWIZZLE1(y, 1)
|
||||
@@ -386,9 +393,10 @@ namespace shader_code
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
struct expression_swizzle_t<Type, 3> : expression_ctors_t<Type, 3>
|
||||
struct expression_swizzle_t<Type, 3> : public expression_ctors_t<Type, 3>
|
||||
{
|
||||
using expression_ctors_t::expression_ctors_t;
|
||||
using base = expression_ctors_t<Type, 3>;
|
||||
using base::base;
|
||||
|
||||
SWIZZLE1(x, 0)
|
||||
SWIZZLE1(y, 1)
|
||||
@@ -408,9 +416,10 @@ namespace shader_code
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
struct expression_swizzle_t<Type, 4> : expression_ctors_t<Type, 4>
|
||||
struct expression_swizzle_t<Type, 4> : public expression_ctors_t<Type, 4>
|
||||
{
|
||||
using expression_ctors_t::expression_ctors_t;
|
||||
using base = expression_ctors_t<Type, 4>;
|
||||
using base::base;
|
||||
|
||||
SWIZZLE1(x, 0)
|
||||
SWIZZLE1(y, 1)
|
||||
@@ -434,116 +443,120 @@ namespace shader_code
|
||||
};
|
||||
|
||||
template<type_class_t Type, int Count>
|
||||
struct expression_t : expression_swizzle_t<Type, Count>
|
||||
struct expression_t : public expression_swizzle_t<Type, Count>
|
||||
{
|
||||
using expression_swizzle_t::expression_swizzle_t;
|
||||
using base = typename expression_swizzle_t<Type, Count>;
|
||||
using base::base;
|
||||
|
||||
const expression_t operator -()
|
||||
{
|
||||
if (is_single && text[0] == '-')
|
||||
return expression_t{ text.substr(1), mask };
|
||||
if (this->is_single && this->text[0] == '-')
|
||||
return expression_t{ this->text.substr(1), this->mask };
|
||||
|
||||
return call_operator("-");
|
||||
return this->call_operator("-");
|
||||
}
|
||||
|
||||
const expression_t operator-(const expression_t& rhs) const
|
||||
{
|
||||
if (rhs.is_single && rhs.text[0] == '-')
|
||||
return call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
return this->call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
|
||||
return call_operator("-", rhs);
|
||||
return this->call_operator("-", rhs);
|
||||
}
|
||||
const expression_t operator+(const expression_t& rhs) const
|
||||
{
|
||||
if (rhs.is_single && rhs.text[0] == '-')
|
||||
return call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
return this->call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
|
||||
return call_operator("+", rhs);
|
||||
return this->call_operator("+", rhs);
|
||||
}
|
||||
const expression_t operator/(const expression_t& rhs) const { return call_operator("/", rhs); }
|
||||
const expression_t operator*(const expression_t& rhs) const { return call_operator("*", rhs); }
|
||||
const expression_t operator/(const expression_t& rhs) const { return this->call_operator("/", rhs); }
|
||||
const expression_t operator*(const expression_t& rhs) const { return this->call_operator("*", rhs); }
|
||||
|
||||
expression_t operator-=(const expression_t& rhs) { return call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t& rhs) { return call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t& rhs) { return call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t& rhs) { return call_operator("*=", rhs); }
|
||||
expression_t operator-=(const expression_t& rhs) { return this->call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t& rhs) { return this->call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t& rhs) { return this->call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t& rhs) { return this->call_operator("*=", rhs); }
|
||||
|
||||
expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); }
|
||||
expression_t operator=(const expression_t& rhs) { return this->call_operator("=", rhs); }
|
||||
|
||||
const expression_t operator-(const expression_t<Type, 1>& rhs) const { return call_operator("-", rhs); }
|
||||
const expression_t operator+(const expression_t<Type, 1>& rhs) const { return call_operator("+", rhs); }
|
||||
const expression_t operator/(const expression_t<Type, 1>& rhs) const { return call_operator("/", rhs); }
|
||||
const expression_t operator*(const expression_t<Type, 1>& rhs) const { return call_operator("*", rhs); }
|
||||
const expression_t operator-(const expression_t<Type, 1>& rhs) const { return this->call_operator("-", rhs); }
|
||||
const expression_t operator+(const expression_t<Type, 1>& rhs) const { return this->call_operator("+", rhs); }
|
||||
const expression_t operator/(const expression_t<Type, 1>& rhs) const { return this->call_operator("/", rhs); }
|
||||
const expression_t operator*(const expression_t<Type, 1>& rhs) const { return this->call_operator("*", rhs); }
|
||||
|
||||
expression_t operator-=(const expression_t<Type, 1>& rhs) { return call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t<Type, 1>& rhs) { return call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t<Type, 1>& rhs) { return call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t<Type, 1>& rhs) { return call_operator("*=", rhs); }
|
||||
expression_t operator-=(const expression_t<Type, 1>& rhs) { return this->call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t<Type, 1>& rhs) { return this->call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t<Type, 1>& rhs) { return this->call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t<Type, 1>& rhs) { return this->call_operator("*=", rhs); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct expression_t<type_class_t::type_bool, 1> : expression_swizzle_t<type_class_t::type_bool, 1>
|
||||
struct expression_t<type_class_t::type_bool, 1> : public expression_swizzle_t<type_class_t::type_bool, 1>
|
||||
{
|
||||
using expression_swizzle_t::expression_swizzle_t;
|
||||
using base = expression_swizzle_t<type_class_t::type_bool, 1>;
|
||||
using base::base;
|
||||
|
||||
expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); }
|
||||
expression_t operator=(const expression_t& rhs) { return this->call_operator("=", rhs); }
|
||||
|
||||
const expression_from<boolean_t<1>> operator!() const { return call_operator<boolean_t<1>>("!"); }
|
||||
const expression_from<boolean_t<1>> operator==(const expression_t& rhs) const { return call_operator<boolean_t<1>>("==", rhs); }
|
||||
const expression_from<boolean_t<1>> operator!=(const expression_t& rhs) const { return call_operator<boolean_t<1>>("!=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator!() const { return this->call_operator<boolean_t<1>>("!"); }
|
||||
const expression_from<boolean_t<1>> operator==(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("==", rhs); }
|
||||
const expression_from<boolean_t<1>> operator!=(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("!=", rhs); }
|
||||
};
|
||||
|
||||
template<int Count>
|
||||
struct expression_t<type_class_t::type_bool, Count> : expression_swizzle_t<type_class_t::type_bool, Count>
|
||||
struct expression_t<type_class_t::type_bool, Count> : public expression_swizzle_t<type_class_t::type_bool, Count>
|
||||
{
|
||||
using expression_swizzle_t::expression_swizzle_t;
|
||||
using base = expression_swizzle_t<type_class_t::type_bool, Count>;
|
||||
using base::base;
|
||||
|
||||
expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); }
|
||||
expression_t operator=(const expression_t& rhs) { return this->call_operator("=", rhs); }
|
||||
};
|
||||
|
||||
template<type_class_t Type>
|
||||
struct expression_t<Type, 1> : expression_swizzle_t<Type, 1>
|
||||
struct expression_t<Type, 1> : public expression_swizzle_t<Type, 1>
|
||||
{
|
||||
using expression_swizzle_t::expression_swizzle_t;
|
||||
using base = expression_swizzle_t<Type, 1>;
|
||||
using base::base;
|
||||
|
||||
const expression_t operator -()
|
||||
{
|
||||
if (is_single && text[0] == '-')
|
||||
return expression_t{ text.substr(1), mask };
|
||||
if (this->is_single && this->text[0] == '-')
|
||||
return expression_t{ this->text.substr(1), mask };
|
||||
|
||||
return call_operator("-");
|
||||
return this->call_operator("-");
|
||||
}
|
||||
|
||||
const expression_t operator-(const expression_t& rhs) const
|
||||
{
|
||||
if (rhs.is_single && rhs.text[0] == '-')
|
||||
return call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
return this->call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
|
||||
return call_operator("-", rhs);
|
||||
return this->call_operator("-", rhs);
|
||||
}
|
||||
const expression_t operator+(const expression_t& rhs) const
|
||||
{
|
||||
if (rhs.is_single && rhs.text[0] == '-')
|
||||
return call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
return this->call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask });
|
||||
|
||||
return call_operator("+", rhs);
|
||||
return this->call_operator("+", rhs);
|
||||
}
|
||||
template<int Count> const expression_t<Type, Count> operator/(const expression_t<Type, Count>& rhs) const { return call_operator<type_t<Type, Count>>("/", rhs); }
|
||||
template<int Count> const expression_t<Type, Count> operator*(const expression_t<Type, Count>& rhs) const { return call_operator<type_t<Type, Count>>("*", rhs); }
|
||||
template<int Count> const expression_t<Type, Count> operator/(const expression_t<Type, Count>& rhs) const { return this->call_operator<type_t<Type, Count>>("/", rhs); }
|
||||
template<int Count> const expression_t<Type, Count> operator*(const expression_t<Type, Count>& rhs) const { return this->call_operator<type_t<Type, Count>>("*", rhs); }
|
||||
|
||||
expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); }
|
||||
expression_t operator=(const expression_t& rhs) { return this->call_operator("=", rhs); }
|
||||
|
||||
expression_t operator-=(const expression_t& rhs) { return call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t& rhs) { return call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t& rhs) { return call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t& rhs) { return call_operator("*=", rhs); }
|
||||
expression_t operator-=(const expression_t& rhs) { return this->call_operator("-=", rhs); }
|
||||
expression_t operator+=(const expression_t& rhs) { return this->call_operator("+=", rhs); }
|
||||
expression_t operator/=(const expression_t& rhs) { return this->call_operator("/=", rhs); }
|
||||
expression_t operator*=(const expression_t& rhs) { return this->call_operator("*=", rhs); }
|
||||
|
||||
const expression_from<boolean_t<1>> operator >(const expression_t& rhs) const { return call_operator<boolean_t<1>>(">", rhs); }
|
||||
const expression_from<boolean_t<1>> operator >=(const expression_t& rhs) const { return call_operator<boolean_t<1>>(">=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator <(const expression_t& rhs) const { return call_operator<boolean_t<1>>("<", rhs); }
|
||||
const expression_from<boolean_t<1>> operator <=(const expression_t& rhs) const { return call_operator<boolean_t<1>>("<=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator==(const expression_t& rhs) const { return call_operator<boolean_t<1>>("==", rhs); }
|
||||
const expression_from<boolean_t<1>> operator!=(const expression_t& rhs) const { return call_operator<boolean_t<1>>("!=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator >(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>(">", rhs); }
|
||||
const expression_from<boolean_t<1>> operator >=(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>(">=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator <(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("<", rhs); }
|
||||
const expression_from<boolean_t<1>> operator <=(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("<=", rhs); }
|
||||
const expression_from<boolean_t<1>> operator==(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("==", rhs); }
|
||||
const expression_from<boolean_t<1>> operator!=(const expression_t& rhs) const { return this->call_operator<boolean_t<1>>("!=", rhs); }
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
#include "pch.h"
|
||||
@@ -1 +0,0 @@
|
||||
#pragma once
|
||||
@@ -156,11 +156,13 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="builder.cpp" />
|
||||
<ClCompile Include="clike_language.cpp" />
|
||||
<ClCompile Include="fmt.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="builder.h" />
|
||||
<ClInclude Include="clike_builder.h" />
|
||||
<ClInclude Include="clike_language.h" />
|
||||
<ClInclude Include="fmt.h" />
|
||||
<ClInclude Include="glsl_builder.h" />
|
||||
<ClInclude Include="glsl_language.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,42 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<ClCompile Include="builder.cpp" />
|
||||
<ClCompile Include="clike_language.cpp" />
|
||||
<ClCompile Include="fmt.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="builder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="clike_language.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="builder.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clike_builder.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clike_language.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glsl_builder.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glsl_language.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fmt.h" />
|
||||
<ClInclude Include="builder.h" />
|
||||
<ClInclude Include="clike_builder.h" />
|
||||
<ClInclude Include="clike_language.h" />
|
||||
<ClInclude Include="glsl_builder.h" />
|
||||
<ClInclude Include="glsl_language.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user