Implemented fragment program decompiler

This commit is contained in:
DH
2015-08-04 22:38:01 +03:00
parent adf23d23ae
commit c80c82a380
20 changed files with 2578 additions and 0 deletions

View File

@@ -0,0 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_program_decompiler", "rsx_program_decompiler\rsx_program_decompiler.vcxproj", "{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_program_decompiler_gui", "rsx_program_decompiler_gui\rsx_program_decompiler_gui.vcxproj", "{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}"
ProjectSection(ProjectDependencies) = postProject
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE} = {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|ARM.ActiveCfg = Debug|ARM
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|ARM.Build.0 = Debug|ARM
{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}.Debug|x86.ActiveCfg = Debug|Win32
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x86.Build.0 = Debug|Win32
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|ARM.ActiveCfg = Release|ARM
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|ARM.Build.0 = Release|ARM
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.ActiveCfg = Release|x64
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.Build.0 = Release|x64
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x86.ActiveCfg = Release|Win32
{F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x86.Build.0 = Release|Win32
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|ARM.ActiveCfg = Debug|Win32
{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}.Debug|x86.ActiveCfg = Debug|Win32
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x86.Build.0 = Debug|Win32
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|ARM.ActiveCfg = Release|Win32
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x64.ActiveCfg = Release|x64
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x64.Build.0 = Release|x64
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x86.ActiveCfg = Release|Win32
{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,129 @@
#include "fmt.h"
#include <algorithm>
namespace fmt
{
std::string replace_first(const std::string& src, const std::string& from, const std::string& to)
{
auto pos = src.find(from);
if (pos == std::string::npos)
{
return src;
}
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
}
std::string replace_all(const std::string &src, const std::string& from, const std::string& to)
{
std::string target = src;
for (auto pos = target.find(from); pos != std::string::npos; pos = target.find(from, pos + 1))
{
target = (pos ? target.substr(0, pos) + to : to) + std::string(target.c_str() + pos + from.length());
pos += to.length();
}
return target;
}
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
{
std::vector<std::string> result;
std::size_t cursor_begin = 0;
for (std::size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
{
for (auto &separator : separators)
{
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
{
std::string candidate = source.substr(cursor_begin, cursor_end - cursor_begin);
if (!is_skip_empty || !candidate.empty())
result.push_back(candidate);
cursor_begin = cursor_end + separator.length();
cursor_end = cursor_begin - 1;
break;
}
}
}
if (cursor_begin != source.length())
{
result.push_back(source.substr(cursor_begin));
}
return std::move(result);
}
std::vector<std::string> split(const std::string& source, const std::string& separator, bool is_skip_empty)
{
return split(source, { separator }, is_skip_empty);
}
std::string tolower(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
return source;
}
std::string toupper(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), ::toupper);
return source;
}
std::string escape(std::string source)
{
const std::pair<std::string, std::string> escape_list[] =
{
{ "\\", "\\\\" },
{ "\a", "\\a" },
{ "\b", "\\b" },
{ "\f", "\\f" },
{ "\n", "\\n\n" },
{ "\r", "\\r" },
{ "\t", "\\t" },
{ "\v", "\\v" },
};
source = replace_all(source, escape_list);
for (char c = 0; c < 32; c++)
{
if (c != '\n')
source = replace_all(source, std::string(1, c), Format("\\x%02X", c));
}
return source;
}
std::vector<std::string> string::split(std::initializer_list<std::string> separators, bool is_skip_empty) const
{
return fmt::split(*this, separators, is_skip_empty);
}
string& string::to_lower()
{
return *this = tolower(*this);
}
string string::as_lower() const
{
return tolower(*this);
}
string& string::to_upper()
{
return *this = toupper(*this);
}
string string::as_upper() const
{
return toupper(*this);
}
}

View File

@@ -0,0 +1,361 @@
#pragma once
#include <string>
#include <vector>
#include <cstddef>
#include <functional>
using u8 = std::uint8_t;
using s8 = std::int8_t;
using u16 = std::uint16_t;
using s16 = std::int16_t;
using u32 = std::uint32_t;
using s32 = std::int32_t;
using u64 = std::uint64_t;
using s64 = std::int64_t;
#if defined(_MSC_VER)
#define snprintf _snprintf
#define force_inline __forceinline
#else
#define force_inline inline
#endif
#define safe_buffers
namespace fmt
{
struct empty_t{};
//small wrapper used to deal with bitfields
template<typename T>
T by_value(T x) { return x; }
//wrapper to deal with advance sprintf formating options with automatic length finding
template<typename... Args> std::string Format(const char* fmt, Args... parameters)
{
std::size_t length = 256;
std::string str;
for (;;)
{
std::vector<char> buffptr(length);
#if !defined(_MSC_VER)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
std::size_t printlen = snprintf(buffptr.data(), length, fmt, std::forward<Args>(parameters)...);
#pragma clang diagnostic pop
#else
std::size_t printlen = _snprintf_s(buffptr.data(), length, length - 1, fmt, std::forward<Args>(parameters)...);
#endif
if (printlen < length)
{
str = std::string(buffptr.data(), printlen);
break;
}
length *= 2;
}
return str;
}
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
template<std::size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
{
for (std::size_t pos = 0; pos < src.length(); ++pos)
{
for (std::size_t i = 0; i < list_size; ++i)
{
const std::size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
pos += list[i].second.length() - 1;
break;
}
}
}
return src;
}
template<std::size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
{
for (std::size_t pos = 0; pos < src.length(); ++pos)
{
for (std::size_t i = 0; i < list_size; ++i)
{
const std::size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
pos += list[i].second().length() - 1;
break;
}
}
}
return src;
}
template<typename T, bool is_enum = std::is_enum<T>::value>
struct unveil
{
typedef T result_type;
force_inline static result_type get_value(const T& arg)
{
return arg;
}
};
template<>
struct unveil<char*, false>
{
typedef const char* result_type;
force_inline static result_type get_value(const char* arg)
{
return arg;
}
};
template<std::size_t N>
struct unveil<const char[N], false>
{
typedef const char* result_type;
force_inline static result_type get_value(const char(&arg)[N])
{
return arg;
}
};
template<>
struct unveil<std::string, false>
{
typedef const char* result_type;
force_inline static result_type get_value(const std::string& arg)
{
return arg.c_str();
}
};
template<typename T>
struct unveil<T, true>
{
typedef typename std::underlying_type<T>::type result_type;
force_inline static result_type get_value(const T& arg)
{
return static_cast<result_type>(arg);
}
};
/*
template<typename T, typename T2>
struct unveil<be_t<T, T2>, false>
{
typedef typename unveil<T>::result_type result_type;
force_inline static result_type get_value(const be_t<T, T2>& arg)
{
return unveil<T>::get_value(arg.value());
}
};
*/
template<typename T>
force_inline typename unveil<T>::result_type do_unveil(const T& arg)
{
return unveil<T>::get_value(arg);
}
/*
fmt::format(const char* fmt, args...)
Formatting function with special functionality:
std::string forced to .c_str()
be_t<> forced to .value() (fmt::unveil reverts byte order automatically)
External specializations for fmt::unveil (can be found in another headers):
vm::ps3::ptr (fmt::unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided)
vm::ps3::bptr (fmt::unveil) (vm_ptr.h)
vm::psv::ptr (fmt::unveil) (vm_ptr.h)
vm::ps3::ref (fmt::unveil) (vm_ref.h)
vm::ps3::bref (fmt::unveil) (vm_ref.h)
vm::psv::ref (fmt::unveil) (vm_ref.h)
*/
template<typename... Args> force_inline safe_buffers std::string format(const char* fmt, Args... args)
{
return Format(fmt, do_unveil(args)...);
}
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators = { " ", "\t" }, bool is_skip_empty = true);
std::vector<std::string> split(const std::string& source, const std::string& separator, bool is_skip_empty = true);
template<typename T>
std::string merge(const T& source, const std::string& separator)
{
if (!source.size())
{
return{};
}
std::string result;
auto it = source.begin();
auto end = source.end();
for (--end; it != end; ++it)
{
result += *it + separator;
}
return result + source.back();
}
template<typename T>
std::string merge(std::initializer_list<T> sources, const std::string& separator)
{
if (!sources.size())
{
return{};
}
std::string result;
bool first = true;
for (auto &v : sources)
{
if (first)
{
result = fmt::merge(v, separator);
first = false;
}
else
{
result += separator + fmt::merge(v, separator);
}
}
return result;
}
std::string tolower(std::string source);
std::string toupper(std::string source);
std::string escape(std::string source);
template<typename T, bool use_std_to_string>
struct to_string_impl
{
static std::string func(const T& value)
{
return value.to_string();
}
};
template<typename T, bool use_std_to_string = std::is_arithmetic<T>::value>
std::string to_string(const T& value)
{
return to_string_impl<std::remove_cv_t<T>, use_std_to_string>::func(value);
}
class string : public std::string
{
public:
//using std::string;
string() = default;
template<typename T>
string(const T& value) : std::string(to_string(value))
{
}
string(std::size_t count, char ch) : std::string(count, ch)
{
}
template<typename T>
string& operator = (const T& rhs)
{
std::string::operator=(to_string(rhs));
return *this;
}
template<typename T>
string operator + (const T& rhs) const
{
return to_string(*this) + to_string(rhs);
}
template<typename T>
string& operator += (const T& rhs)
{
std::string::operator+=(to_string(rhs));
return *this;
}
std::vector<std::string> split(std::initializer_list<std::string> separators = { " ", "\t" }, bool is_skip_empty = true) const;
string& to_lower();
string as_lower() const;
string& to_upper();
string as_upper() const;
};
template<typename T>
struct to_string_impl<T, true>
{
static std::string func(const T& value)
{
return std::to_string(value);
}
};
template<bool use_std_to_string>
struct to_string_impl<std::string, use_std_to_string>
{
static const std::string& func(const std::string& value)
{
return value;
}
};
template<bool use_std_to_string>
struct to_string_impl<string, use_std_to_string>
{
static const std::string& func(const string& value)
{
return value;
}
};
template<bool use_std_to_string>
struct to_string_impl<char*, use_std_to_string>
{
static std::string func(const char* value)
{
return value;
}
};
template<bool use_std_to_string, std::size_t N>
struct to_string_impl<char[N], use_std_to_string>
{
static std::string func(const char(&value)[N])
{
return value;
}
};
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "rsx_glsl_fragment_program_decompiler.h"
#include "rsx_glsl_vertex_program_decompiler.h"

View File

@@ -0,0 +1,211 @@
#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 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 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 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 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"
};
}
}

View File

@@ -0,0 +1,8 @@
#include "rsx_fragment_program_decompiler.h"
namespace rsx
{
namespace fragment_program
{
}
}

View File

@@ -0,0 +1,437 @@
#pragma once
#include "rsx_fragment_program.h"
#include "rsx_program_decompiler.h"
#include <unordered_set>
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> struct src {};
struct texture {};
struct addr {};
struct cond {};
template<typename T> struct arg {};
union ucode_data
{
struct
{
OPDEST dst;
SRC0 src0;
SRC1 src1;
SRC2 src2;
};
u32 data[4];
};
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>> >;
using ADD = instruction < opcode::ADD, H | C, dest<4>, arg<src<0, 4>> >;
using MAD = instruction < opcode::MAD, H | C, dest<4>, arg<src<0, 4>>, arg<src<2, 4>> >;
using DP3 = instruction < opcode::DP3, H | C, dest<3>, arg<src<0, 3>>, arg<src<1, 3>> >;
using DP4 = instruction < opcode::DP4, H | C, dest<4>, arg<src<0, 4>>, arg<src<1, 4>> >;
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> > >;
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>>, arg<src<1, 2>> >;
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::LOOP, 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, H >;
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)
{
}
};
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;
public:
int code_line_index = 0;
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>
struct expand_arg_t<src<index, count>>
{
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;
};
switch (index)
{
case 0: get_data_from(src0); break;
case 1: get_data_from(src1); break;
case 2: get_data_from(src2); break;
}
variable.name = is_fp16 ? "H" : "R";
bool need_declare = true;
switch (type)
{
case 0: //temporary register
variable.type = program_variable_type::none;
break;
case 1: //input register
variable.index = dst.src_attr_reg_num;
variable.type = program_variable_type::input;
break;
case 2: //constant
need_declare = false;
decompiler.is_next_constant = true;
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 (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();
}
};
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;
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<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;
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];
result.mask.add(swizzle);
return info.vars.add(result);
}
template<typename T>
program_variable arg()
{
return expand_arg_t<T>::impl(*this);
}
program_variable update_condition()
{
program_variable result = {};
result.name = "CC";
result.index = ucode.src0.cond_mod_reg_index;
result.size = 4;
return info.vars.add(result);
}
program_variable execution_condition()
{
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;
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)
{
program_decompiler_core::builder.add_code_block(code_line_index, code_line);
}
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));
}
void unknown_instruction()
{
}
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
};
code_line_index = 0;
for (u32 i = 0; i < ucode_size; ++i)
{
ucode = ucode_ptr[i];
ucode.data[0] = (ucode.data[0] << 16) | (ucode.data[0] >> 16);
ucode.data[1] = (ucode.data[1] << 16) | (ucode.data[1] >> 16);
ucode.data[2] = (ucode.data[2] << 16) | (ucode.data[2] >> 16);
ucode.data[3] = (ucode.data[3] << 16) | (ucode.data[3] >> 16);
const u32 opcode = ucode.dst.opcode | (ucode.src1.opcode_is_branch << 6);
auto function = instructions[opcode];
if (function)
{
function(*this);
code_line_index++;
}
else
{
unknown_instruction();
}
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(code_line_index, function_end(), -1, 0);
builder.add_code_block(code_line_index, end);
info.text = builder.build();
return info;
}
};
}
}

View File

@@ -0,0 +1,383 @@
#pragma once
#include "rsx_program_decompiler.h"
#include "rsx_fragment_program_decompiler.h"
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;
}
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) + "]") : std::to_string(var.second.index)) + ";\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";
arg.type = program_variable_type::constant;
return arg;
}
__forceinline static std::string variable_to_string(const program_variable& arg)
{
fmt::string result = arg;
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 + "() {";
}
__forceinline static std::string function_end()
{
return "}";
}
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",
"ddx", "ddy", "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::ADD:
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::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;
}
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? let it be unimplemented, atm
throw std::runtime_error("fragment program decompiler: unimplemented precision.");
}
switch (dec->ucode.src1.scale)
{
case 0: break;
case 1: value = "(" + value + " * 2.0)"; break;
case 2: value = "(" + value + " * 4.0)"; break;
case 3: value = "(" + value + " * 8.0)"; break;
case 5: value = "(" + value + " / 2.0)"; break;
case 6: value = "(" + value + " / 4.0)"; break;
case 7: value = "(" + value + " / 8.0)"; break;
default:
throw std::runtime_error("fragment program decompiler: unimplemented scale.");
}
if (dec->ucode.dst.saturate)
{
value += "clamp(" + value + ", 0, 1)";
}
}
std::string result;
program_variable dst = dec->dst<flags, count>();
program_variable update_condition;
bool do_update_condition = false;
if ((flags & C) && dec->ucode.dst.set_cond)
{
update_condition = dec->update_condition();
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();
mask_t update_mask;
update_mask.add(dst.mask.to_string());
update_mask.add(execution_condition.mask.to_string());
update_mask.add(fmt::string("xyzw").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 = "==";
fmt::string update_mask_string = update_mask.to_string();
if (update_mask_string.empty())
update_mask_string = "xyzw";
std::string last_condition_group;
std::string last_line;
for (char _mask : update_mask_string)
{
const std::string mask(1, _mask);
const std::string dot_mask = "." + mask;
auto channel_execution_condition = execution_condition;
std::string channel_execution_condition_mask = channel_execution_condition.mask.add(mask).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";
last_condition_group = channel_execution_condition_mask;
last_line.clear();
}
std::string channel_dst_string;
if (dst)
{
auto channel_dst = dst;
channel_dst.mask.add(mask);
channel_dst_string = channel_dst.to_string();
std::string line = "\t" + channel_dst_string + " = " + value + dot_mask + ";\n";
if (last_line == line)
{
continue;
}
result += line;
last_line = line;
}
if (do_update_condition)
{
std::string cond_value = (dst ? channel_dst_string : value) + dot_mask;
result += "\t" + update_condition.to_string() + dot_mask + " = " + cond_value + ";\n";
}
}
if (!last_condition_group.empty())
result += "}\n";
}
return result;
}
static std::string finalyze(decompiler *dec)
{
std::string result = "\nvoid main() {\n";
result += "\tlabel0();\n";
struct destination_info
{
std::string name;
bool is_need_declare;
};
struct source_info
{
std::size_t r_register;
std::size_t h_register;
};
const source_info color_source_registers[] =
{
{ 0, 0 },
{ 2, 4 },
{ 3, 6 },
{ 4, 8 }
};
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].r_register : color_source_registers[i].h_register;
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 >;
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "rsx_vertex_program_decompiler.h"
namespace rsx
{
namespace vertex_program
{
using glsl_decompiler = decompiler;
}
}

View File

@@ -0,0 +1,284 @@
#include "rsx_program_decompiler.h"
#include "fmt.h"
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 program_variable::to_string_impl() const
{
if (array_size)
return name + "[" + std::to_string(index) + "]";
return name + std::to_string(index);
}
std::string program_variable::append_dot_if_not_empty(const std::string& string) const
{
return string.empty() ? std::string{} : "." + string;
};
std::string program_variable::storage_name() const
{
return name + (array_size ? "[" + std::to_string(array_size + 1) + "]" : std::to_string(index));
}
std::string program_variable::to_string() const
{
return to_string_impl() + append_dot_if_not_empty(mask.to_string());
}
std::string program_variable::to_string()
{
return to_string_impl() + append_dot_if_not_empty(mask.to_string());
}
bool program_variable::is_null() const
{
return name.empty();
}
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;
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;
}
}

View File

@@ -0,0 +1,120 @@
#pragma once
#include <vector>
#include <map>
#include <unordered_map>
#include "fmt.h"
namespace rsx
{
enum class program_variable_type
{
none,
input,
output,
constant
};
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();
};
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;
private:
std::string to_string_impl() const;
std::string append_dot_if_not_empty(const std::string& string) 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();
};
}

View File

@@ -0,0 +1,8 @@
#pragma once
namespace rsx
{
namespace vertex_program
{
}
}

View File

@@ -0,0 +1,13 @@
#include "rsx_vertex_program_decompiler.h"
#include <iostream>
namespace rsx
{
namespace vertex_program
{
void decompiler::test()
{
std::cout << __FUNCTION__ << std::endl;
}
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "rsx_vertex_program.h"
namespace rsx
{
namespace vertex_program
{
class decompiler
{
public:
void test();
};
}
}

View File

@@ -0,0 +1,232 @@
<?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</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>true</RunCodeAnalysis>
<OutDir>$(SolutionDir)lib\</OutDir>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
<OutDir>$(SolutionDir)lib\</OutDir>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
<OutDir>$(SolutionDir)lib\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
<OutDir>$(SolutionDir)lib\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
<OutDir>$(SolutionDir)lib\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
<OutDir>$(SolutionDir)lib\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<EnablePREfast>true</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="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_fragment_program_decompiler.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>

View File

@@ -0,0 +1,47 @@
<?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" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="rsx\rsx_program_decompiler.cpp">
<Filter>rsx</Filter>
</ClCompile>
<ClCompile Include="rsx\rsx_fragment_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>

View File

@@ -0,0 +1,57 @@
#include <rsx/rsx.h>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <functional>
template<typename DecompilerType>
int process(const std::string& path)
{
if (auto &file_stream = std::ifstream{ path, std::ios::binary })
{
u32 buffer[512 * 4];
u32 size = file_stream.read((char*)buffer, sizeof(buffer)).gcount();
auto info = DecompilerType{ buffer, size }.decompile();
std::cout << info.text;
return 0;
}
return -3;
}
const std::unordered_map<std::string, std::function<int(const std::string&)>> g_profiles =
{
{ "fp_glsl", process<rsx::fragment_program::glsl_decompiler> },
//{ "vp_glsl", process<rsx::vertex_program::glsl_decompiler> }
};
void help()
{
std::cout << "usage: [profile] <path to ucode>" << std::endl;
std::cout << "supported profiles: ";
for (auto &profile : g_profiles)
{
std::cout << profile.first << " ";
}
std::cout << std::endl;
}
int main(int argc, char** argv)
{
if (argc != 3)
{
help();
return -1;
}
auto found = g_profiles.find(std::string(argv[1]).substr(1));
if (found == g_profiles.end())
{
help();
return -2;
}
return found->second(argv[2]);
}

View File

@@ -0,0 +1,182 @@
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>rsx_program_decompiler_gui</RootNamespace>
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</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|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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)lib\;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)rsx_program_decompiler\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)bin\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)lib\;$(LibraryPath)</LibraryPath>
<OutDir>$(SolutionDir)bin\</OutDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<IncludePath>$(SolutionDir)rsx_program_decompiler\;$(IncludePath)</IncludePath>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<OutDir>$(SolutionDir)bin\</OutDir>
<LibraryPath>$(SolutionDir)lib\;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)rsx_program_decompiler\;$(IncludePath)</IncludePath>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>tmp\$(Platform)\$(Configuration)\</IntDir>
<LibraryPath>$(SolutionDir)lib\;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)rsx_program_decompiler\;$(IncludePath)</IncludePath>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="rsx_program_decompiler_gui.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="rsx_program_decompiler_gui.cpp" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-fp_glsl transform_program.ucode &gt;out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>-fp_glsl transform_program.ucode &gt;out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>-fp_glsl transform_program.ucode &gt;out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>-fp_glsl transform_program.ucode &gt;out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
</Project>