1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 11:13:19 +01:00

Implemented binary fragment program disassembler

This commit is contained in:
O1L 2015-02-22 18:47:12 +04:00
parent bdad5ef745
commit e84f356a29
15 changed files with 1273 additions and 452 deletions

View File

@ -0,0 +1,477 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "CgBinaryProgram.h"
#include "Emu/RSX/RSXFragmentProgram.h"
void CgBinaryDisasm::AddCodeAsm(const std::string& code)
{
std::string op_name = "";
if (dst.dest_reg == 63)
{
m_dst_reg_name = fmt::format("RC%s, ", GetMask().c_str());
op_name = rsx_fp_op_names[m_opcode] + "XC";
}
else
{
m_dst_reg_name = fmt::format("%s%d%s, ", dst.fp16 ? "H" : "R", dst.dest_reg, GetMask().c_str());
op_name = rsx_fp_op_names[m_opcode] + std::string(dst.fp16 ? "H" : "R");
}
switch (m_opcode)
{
case RSX_FP_OPCODE_BRK:
case RSX_FP_OPCODE_CAL:
case RSX_FP_OPCODE_FENCT:
case RSX_FP_OPCODE_FENCB:
case RSX_FP_OPCODE_IFE:
case RSX_FP_OPCODE_KIL:
case RSX_FP_OPCODE_LOOP:
case RSX_FP_OPCODE_NOP:
case RSX_FP_OPCODE_REP:
case RSX_FP_OPCODE_RET: m_dst_reg_name = ""; break;
default: break;
}
m_arb_shader += (op_name + " " + m_dst_reg_name + FormatDisAsm(code) + ";" + "\n");
}
std::string CgBinaryDisasm::GetMask()
{
std::string ret;
static const char dst_mask[4] =
{
'x', 'y', 'z', 'w'
};
if (dst.mask_x) ret += dst_mask[0];
if (dst.mask_y) ret += dst_mask[1];
if (dst.mask_z) ret += dst_mask[2];
if (dst.mask_w) ret += dst_mask[3];
return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret);
}
std::string CgBinaryDisasm::AddRegDisAsm(u32 index, int fp16)
{
return std::string(fp16 ? "H" : "R") + std::to_string(index);
}
std::string CgBinaryDisasm::AddConstDisAsm()
{
u32* data = (u32*)&m_buffer[m_offset + m_size + 4 * sizeof(u32)];
m_step = 2 * 4 * sizeof(u32);
const u32 x = GetData(data[0]);
const u32 y = GetData(data[1]);
const u32 z = GetData(data[2]);
const u32 w = GetData(data[3]);
char buf[1024];
sprintf(buf, "{0x%08x(%g), 0x%08x(%g), 0x%08x(%g), 0x%08x(%g)}", x, (float&)x, y, (float&)y, z, (float&)z, w, (float&)w);
return fmt::format(buf);
}
std::string CgBinaryDisasm::AddTexDisAsm()
{
return (std::string("TEX") + std::to_string(dst.tex_num));
}
std::string CgBinaryDisasm::GetCondDisAsm()
{
static const char f[4] = { 'x', 'y', 'z', 'w' };
std::string swizzle, cond;
swizzle += f[src0.cond_swizzle_x];
swizzle += f[src0.cond_swizzle_y];
swizzle += f[src0.cond_swizzle_z];
swizzle += f[src0.cond_swizzle_w];
if (swizzle == "xxxx") swizzle = "x";
if (swizzle == "yyyy") swizzle = "y";
if (swizzle == "zzzz") swizzle = "z";
if (swizzle == "wwww") swizzle = "w";
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
if (src0.exec_if_gr && src0.exec_if_eq)
{
cond = "GE";
}
else if (src0.exec_if_lt && src0.exec_if_eq)
{
cond = "LE";
}
else if (src0.exec_if_gr && src0.exec_if_lt)
{
cond = "NE";
}
else if (src0.exec_if_gr)
{
cond = "GT";
}
else if (src0.exec_if_lt)
{
cond = "LT";
}
else if (src0.exec_if_eq)
{
cond = "FL";
}
else
{
cond = "TR";
}
return cond + swizzle;
}
std::string CgBinaryDisasm::FormatDisAsm(const std::string& code)
{
const std::pair<std::string, std::function<std::string()>> repl_list[] =
{
{ "$$", []() -> std::string { return "$"; } },
{ "$0", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm<SRC0>), this, src0) },
{ "$1", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm<SRC1>), this, src1) },
{ "$2", std::bind(std::mem_fn(&CgBinaryDisasm::GetSrcDisAsm<SRC2>), this, src2) },
{ "$t", std::bind(std::mem_fn(&CgBinaryDisasm::AddTexDisAsm), this) },
{ "$m", std::bind(std::mem_fn(&CgBinaryDisasm::GetMask), this) },
{ "$cond", std::bind(std::mem_fn(&CgBinaryDisasm::GetCondDisAsm), this) },
{ "$c", std::bind(std::mem_fn(&CgBinaryDisasm::AddConstDisAsm), this) }
};
return fmt::replace_all(code, repl_list);
}
template<typename T> std::string CgBinaryDisasm::GetSrcDisAsm(T src)
{
std::string ret;
switch (src.reg_type)
{
case 0: //tmp
ret += AddRegDisAsm(src.tmp_reg_index, src.fp16);
break;
case 1: //input
{
static const std::string reg_table[] =
{
"WPOS", "COL0", "COL1", "FOGC", "TEX0",
"TEX1", "TEX2", "TEX3", "TEX4", "TEX5",
"TEX6", "TEX7", "TEX8", "TEX9", "SSA"
};
const std::string perspective_correction = src2.perspective_corr ? "g" : "f";
const std::string input_attr_reg = reg_table[dst.src_attr_reg_num];
switch (dst.src_attr_reg_num)
{
case 0x00: ret += reg_table[0]; break;
default:
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
{
ret += fmt::format("%s[%s]", perspective_correction.c_str(), input_attr_reg.c_str());
}
else
{
LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num));
}
break;
}
}
break;
case 2: //const
ret += AddConstDisAsm();
break;
default:
LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type));
break;
}
static const char f[4] = { 'x', 'y', 'z', 'w' };
std::string swizzle = "";
swizzle += f[src.swizzle_x];
swizzle += f[src.swizzle_y];
swizzle += f[src.swizzle_z];
swizzle += f[src.swizzle_w];
if (swizzle == "xxxx") swizzle = "x";
if (swizzle == "yyyy") swizzle = "y";
if (swizzle == "zzzz") swizzle = "z";
if (swizzle == "wwww") swizzle = "w";
if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
if (src.neg) ret = "-" + ret;
return ret;
}
void CgBinaryDisasm::TaskFP()
{
m_size = 0;
u32* data = (u32*)&m_buffer[m_offset];
assert((m_buffer_size - m_offset) % sizeof(u32) == 0);
for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++)
{
data[i] = re32(data[i]);
}
enum
{
FORCE_NONE,
FORCE_SCT,
FORCE_SCB
};
int forced_unit = FORCE_NONE;
while (true)
{
for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
finded != m_end_offsets.end();
finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
{
m_end_offsets.erase(finded);
m_arb_shader += "ENDIF;\n";
}
for (auto finded = std::find(m_loop_end_offsets.begin(), m_loop_end_offsets.end(), m_size);
finded != m_loop_end_offsets.end();
finded = std::find(m_loop_end_offsets.begin(), m_loop_end_offsets.end(), m_size))
{
m_loop_end_offsets.erase(finded);
m_arb_shader += "ENDLOOP;\n";
}
for (auto finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
finded != m_else_offsets.end();
finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
{
m_else_offsets.erase(finded);
m_arb_shader += "ELSE;\n";
}
dst.HEX = GetData(data[0]);
src0.HEX = GetData(data[1]);
src1.HEX = GetData(data[2]);
src2.HEX = GetData(data[3]);
m_step = 4 * sizeof(u32);
m_opcode = dst.opcode | (src1.opcode_is_branch << 6);
auto SCT = [&]()
{
switch (m_opcode)
{
case RSX_FP_OPCODE_ADD: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DIV: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DIVSQ: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP2: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP3: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP4: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP2A: AddCodeAsm("$0, $1, $2"); break;
case RSX_FP_OPCODE_MAD: AddCodeAsm("$0, $1, $2"); break;
case RSX_FP_OPCODE_MAX: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_MIN: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_MOV: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_MUL: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_RCP: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_RSQ: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_SEQ: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SFL: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SGE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SGT: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SLE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SLT: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SNE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_STR: AddCodeAsm("$0, $1"); break;
default:
return false;
}
return true;
};
auto SCB = [&]()
{
switch (m_opcode)
{
case RSX_FP_OPCODE_ADD: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_COS: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_DP2: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP3: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP4: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_DP2A: AddCodeAsm("$0, $1, $2"); break;
case RSX_FP_OPCODE_DST: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_REFL: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_EX2: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_FLR: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_FRC: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_LIT: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_LIF: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_LRP: AddCodeAsm("# WARNING"); break;
case RSX_FP_OPCODE_LG2: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_MAD: AddCodeAsm("$0, $1, $2"); break;
case RSX_FP_OPCODE_MAX: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_MIN: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_MOV: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_MUL: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_PK2: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_PK4: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_PK16: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_PKB: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_PKG: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_SEQ: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SFL: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SGE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SGT: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SIN: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_SLE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SLT: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_SNE: AddCodeAsm("$0, $1"); break;
case RSX_FP_OPCODE_STR: AddCodeAsm("$0, $1"); break;
default:
return false;
}
return true;
};
auto TEX_SRB = [&]()
{
switch (m_opcode)
{
case RSX_FP_OPCODE_DDX: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_DDY: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_NRM: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_BEM: AddCodeAsm("# WARNING"); break;
case RSX_FP_OPCODE_TEX: AddCodeAsm("$0, $t"); break;
case RSX_FP_OPCODE_TEXBEM: AddCodeAsm("# WARNING"); break;
case RSX_FP_OPCODE_TXP: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_TXPBEM: AddCodeAsm("# WARNING"); break;
case RSX_FP_OPCODE_TXD: AddCodeAsm("$0, $1, $t"); break;
case RSX_FP_OPCODE_TXB: AddCodeAsm("$0, $t"); break;
case RSX_FP_OPCODE_TXL: AddCodeAsm("$0, $t"); break;
case RSX_FP_OPCODE_UP2: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_UP4: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_UP16: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_UPB: AddCodeAsm("$0"); break;
case RSX_FP_OPCODE_UPG: AddCodeAsm("$0"); break;
default:
return false;
}
return true;
};
auto SIP = [&]()
{
switch (m_opcode)
{
case RSX_FP_OPCODE_BRK: AddCodeAsm("$cond"); break;
case RSX_FP_OPCODE_CAL: AddCodeAsm("$cond"); break;
case RSX_FP_OPCODE_FENCT: AddCodeAsm(""); break;
case RSX_FP_OPCODE_FENCB: AddCodeAsm(""); break;
case RSX_FP_OPCODE_IFE:
{
m_else_offsets.push_back(src1.else_offset << 2);
m_end_offsets.push_back(src2.end_offset << 2);
AddCodeAsm("($cond)");
}
break;
case RSX_FP_OPCODE_LOOP:
{
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
AddCodeAsm(fmt::Format("{ %u, %u, %u }", src1.end_counter, src1.init_counter, src1.increment));
}
else
{
m_loop_end_offsets.push_back(src2.end_offset << 2);
AddCodeAsm(fmt::Format("{ %u, %u, %u }", src1.end_counter, src1.init_counter, src1.increment));
}
}
break;
case RSX_FP_OPCODE_REP:
{
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
m_arb_shader += "# RSX_FP_OPCODE_REP_1\n";
}
else
{
m_end_offsets.push_back(src2.end_offset << 2);
m_arb_shader += "# RSX_FP_OPCODE_REP_2\n";
}
}
break;
case RSX_FP_OPCODE_RET: AddCodeAsm("$cond"); break;
default:
return false;
}
return true;
};
switch (m_opcode)
{
case RSX_FP_OPCODE_NOP: AddCodeAsm(""); break;
case RSX_FP_OPCODE_KIL: AddCodeAsm("$cond"); break;
default:
if (forced_unit == FORCE_NONE)
{
if (SIP()) break;
if (SCT()) break;
if (TEX_SRB()) break;
if (SCB()) break;
}
else if (forced_unit == FORCE_SCT)
{
forced_unit = FORCE_NONE;
if (SCT()) break;
}
else if (forced_unit == FORCE_SCB)
{
forced_unit = FORCE_NONE;
if (SCB()) break;
}
LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", m_opcode, forced_unit);
break;
}
m_size += m_step;
if (dst.end)
{
m_arb_shader.pop_back();
m_arb_shader += " # last inctruction\nEND\n";
break;
}
assert(m_step % sizeof(u32) == 0);
data += m_step / sizeof(u32);
}
}

View File

@ -0,0 +1,367 @@
#pragma once
#include <sstream>
#include "Utilities/rFile.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/RSX/GL/GLVertexProgram.h"
#include "Emu/RSX/GL/GLFragmentProgram.h"
typedef be_t<u32> CGprofile;
typedef be_t<s32> CGbool;
typedef be_t<u32> CGresource;
typedef be_t<u32> CGenum;
typedef be_t<u32> CGtype;
typedef be_t<u32> CgBinaryOffset;
typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset;
typedef CgBinaryOffset CgBinaryFloatOffset;
typedef CgBinaryOffset CgBinaryStringOffset;
typedef CgBinaryOffset CgBinaryParameterOffset;
// a few typedefs
typedef struct CgBinaryParameter CgBinaryParameter;
typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant;
typedef struct CgBinaryVertexProgram CgBinaryVertexProgram;
typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram;
typedef struct CgBinaryProgram CgBinaryProgram;
// fragment programs have their constants embedded in the microcode
struct CgBinaryEmbeddedConstant
{
be_t<u32> ucodeCount; // occurances
be_t<u32> ucodeOffset[1]; // offsets that need to be patched follow
};
// describe a binary program parameter (CgParameter is opaque)
struct CgBinaryParameter
{
CGtype type; // cgGetParameterType()
CGresource res; // cgGetParameterResource()
CGenum var; // cgGetParameterVariability()
be_t<s32> resIndex; // cgGetParameterResourceIndex()
CgBinaryStringOffset name; // cgGetParameterName()
CgBinaryFloatOffset defaultValue; // default constant value
CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information
CgBinaryStringOffset semantic; // cgGetParameterSemantic()
CGenum direction; // cgGetParameterDirection()
be_t<s32> paramno; // 0..n: cgGetParameterIndex() -1: globals
CGbool isReferenced; // cgIsParameterReferenced()
CGbool isShared; // cgIsParameterShared()
};
// attributes needed for vshaders
struct CgBinaryVertexProgram
{
be_t<u32> instructionCount; // #instructions
be_t<u32> instructionSlot; // load address (indexed reads!)
be_t<u32> registerCount; // R registers count
be_t<u32> attributeInputMask; // attributes vs reads from
be_t<u32> attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits)
be_t<u32> userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL)
};
typedef enum
{
CgBinaryPTTNone = 0,
CgBinaryPTT2x16 = 1,
CgBinaryPTT1x32 = 2
} CgBinaryPartialTexType;
// attributes needed for pshaders
struct CgBinaryFragmentProgram
{
be_t<u32> instructionCount; // #instructions
be_t<u32> attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits)
be_t<u32> partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType
be_t<u16> texCoordsInputMask; // tex coords used by frag prog. (tex<n> is bit n)
be_t<u16> texCoords2D; // tex coords that are 2d (tex<n> is bit n)
be_t<u16> texCoordsCentroid; // tex coords that are centroid (tex<n> is bit n)
u8 registerCount; // R registers count
u8 outputFromH0; // final color from R0 or H0
u8 depthReplace; // fp generated z epth value
u8 pixelKill; // fp uses kill operations
};
struct CgBinaryProgram
{
// vertex/pixel shader identification (BE/LE as well)
CGprofile profile;
// binary revision (used to verify binary and driver structs match)
be_t<u32> binaryFormatRevision;
// total size of this struct including profile and totalSize field
be_t<u32> totalSize;
// parameter usually queried using cgGet[First/Next]LeafParameter
be_t<u32> parameterCount;
CgBinaryParameterOffset parameterArray;
// depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct
CgBinaryOffset program;
// raw ucode data
be_t<u32> ucodeSize;
CgBinaryOffset ucode;
// variable length data follows
u8 data[1];
};
class CgBinaryDisasm
{
private:
std::string m_path; // used for FP decompiler thread, delete this later
u8* m_buffer;
size_t m_buffer_size;
std::string m_arb_shader;
std::string m_glsl_shader;
std::string m_dst_reg_name;
// FP members
u32 m_offset;
u32 m_opcode;
u32 m_step;
u32 m_size;
std::vector<u32> m_end_offsets;
std::vector<u32> m_else_offsets;
std::vector<u32> m_loop_end_offsets;
// VP members
static const size_t m_max_instr_count = 512;
size_t m_instr_count;
std::vector<u32> m_data;
public:
std::string GetArbShader() const { return m_arb_shader; }
std::string GetGlslShader() const { return m_glsl_shader; }
// FP functions
std::string GetMask();
void AddCodeAsm(const std::string& code);
std::string AddRegDisAsm(u32 index, int fp16);
std::string AddConstDisAsm();
std::string AddTexDisAsm();
std::string FormatDisAsm(const std::string& code);
std::string GetCondDisAsm();
template<typename T> std::string GetSrcDisAsm(T src);
CgBinaryDisasm(const std::string& path)
: m_path(path)
, m_buffer(nullptr)
, m_buffer_size(0)
, m_offset(0)
, m_opcode(0)
, m_step(0)
, m_size(0)
, m_arb_shader("")
, m_dst_reg_name("")
{
rFile f(path);
if (!f.IsOpened())
return;
m_buffer_size = f.Length();
m_buffer = new u8[m_buffer_size];
f.Read(m_buffer, m_buffer_size);
f.Close();
m_arb_shader += fmt::format("Loading... [%s]\n", path.c_str());
}
~CgBinaryDisasm()
{
delete[] m_buffer;
}
std::string GetCgParamType(u32 type) const
{
switch (type)
{
case 1045: return "float";
case 1046:
case 1047:
case 1048: return fmt::format("float%d", type - 1044);
case 1064: return "float4x4";
case 1066: return "sampler2D";
case 1069: return "samplerCUBE";
default: return fmt::format("!UnkCgType(%d)", type);
}
}
std::string GetCgParamName(u32 offset) const
{
std::stringstream str_stream;
std::string name = "";
while (m_buffer[offset] != 0)
{
str_stream << m_buffer[offset];
offset++;
}
name += str_stream.str();
return name;
}
std::string GetCgParamRes(u32 offset) const
{
// LOG_WARNING(GENERAL, "GetCgParamRes offset 0x%x", offset);
// TODO
return "";
}
std::string GetCgParamSemantic(u32 offset) const
{
std::stringstream str_stream;
std::string semantic = "";
while (m_buffer[offset] != 0)
{
str_stream << m_buffer[offset];
offset++;
}
semantic += str_stream.str();
return semantic;
}
std::string GetCgParamValue(u32 offset, u32 end_offset) const
{
std::string offsets = "offsets:";
u32 num = 0;
offset += 6;
while (offset < end_offset)
{
offsets += fmt::format(" %d,", m_buffer[offset] << 8 | m_buffer[offset + 1]);
offset += 4;
num++;
}
if (num > 4)
return "";
offsets.pop_back();
return fmt::format("num %d ", num) + offsets;
}
template<typename T>
T& GetCgRef(const u32 offset)
{
return reinterpret_cast<T&>(m_buffer[offset]);
}
void BuildShaderBody()
{
GLParamArray param_array;
auto& prog = GetCgRef<CgBinaryProgram>(0);
if (prog.profile == 7004)
{
auto& fprog = GetCgRef<CgBinaryFragmentProgram>(prog.program);
m_arb_shader += "\n";
m_arb_shader += fmt::format("# binaryFormatRevision 0x%x\n", (u32)prog.binaryFormatRevision);
m_arb_shader += fmt::format("# profile sce_fp_rsx\n");
m_arb_shader += fmt::format("# parameterCount %d\n", (u32)prog.parameterCount);
m_arb_shader += fmt::format("# instructionCount %d\n", (u32)fprog.instructionCount);
m_arb_shader += fmt::format("# attributeInputMask 0x%x\n", (u32)fprog.attributeInputMask);
m_arb_shader += fmt::format("# registerCount %d\n\n", (u32)fprog.registerCount);
CgBinaryParameterOffset offset = prog.parameterArray;
for (u32 i = 0; i < (u32)prog.parameterCount; i++)
{
auto& fparam = GetCgRef<CgBinaryParameter>(offset);
std::string param_type = GetCgParamType(fparam.type) + " ";
std::string param_name = GetCgParamName(fparam.name) + " ";
std::string param_res = GetCgParamRes(fparam.res) + " ";
std::string param_semantic = GetCgParamSemantic(fparam.semantic) + " ";
std::string param_const = GetCgParamValue(fparam.embeddedConst, fparam.name);
m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n";
offset += sizeof(CgBinaryParameter);
}
m_arb_shader += "\n";
m_offset = prog.ucode;
TaskFP();
// reload binary data in the virtual memory, temporary solution
{
u32 ptr;
{
rFile f(m_path);
if (!f.IsOpened())
return;
size_t size = f.Length();
vm::ps3::init();
ptr = vm::alloc(size);
f.Read(vm::get_ptr(ptr), size);
f.Close();
}
auto& vmprog = vm::get_ref<CgBinaryProgram>(ptr);
auto& vmfprog = vm::get_ref<CgBinaryFragmentProgram>(ptr + vmprog.program);
u32 size;
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
GLFragmentDecompilerThread(m_glsl_shader, param_array, ptr + vmprog.ucode, size, ctrl).Task();
vm::close();
}
}
else
{
auto& vprog = GetCgRef<CgBinaryVertexProgram>(prog.program);
m_arb_shader += "\n";
m_arb_shader += fmt::format("# binaryFormatRevision 0x%x\n", (u32)prog.binaryFormatRevision);
m_arb_shader += fmt::format("# profile sce_vp_rsx\n");
m_arb_shader += fmt::format("# parameterCount %d\n", (u32)prog.parameterCount);
m_arb_shader += fmt::format("# instructionCount %d\n", (u32)vprog.instructionCount);
m_arb_shader += fmt::format("# registerCount %d\n", (u32)vprog.registerCount);
m_arb_shader += fmt::format("# attributeInputMask 0x%x\n", (u32)vprog.attributeInputMask);
m_arb_shader += fmt::format("# attributeOutputMask 0x%x\n\n", (u32)vprog.attributeOutputMask);
CgBinaryParameterOffset offset = prog.parameterArray;
for (u32 i = 0; i < (u32)prog.parameterCount; i++)
{
auto& vparam = GetCgRef<CgBinaryParameter>(offset);
std::string param_type = GetCgParamType(vparam.type) + " ";
std::string param_name = GetCgParamName(vparam.name) + " ";
std::string param_res = GetCgParamRes(vparam.res) + " ";
std::string param_semantic = GetCgParamSemantic(vparam.semantic) + " ";
std::string param_const = GetCgParamValue(vparam.embeddedConst, vparam.name);
m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n";
offset += sizeof(CgBinaryParameter);
}
m_arb_shader += "\n";
m_offset = prog.ucode;
u32* vdata = (u32*)&m_buffer[m_offset];
assert((m_buffer_size - m_offset) % sizeof(u32) == 0);
for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++)
{
vdata[i] = re32(vdata[i]);
}
for (u32 i = 0; i < prog.ucodeSize / sizeof(u32); i++)
{
m_data.push_back(vdata[i]);
}
//TaskVP();
GLVertexDecompilerThread(m_data, m_glsl_shader, param_array).Task();
}
}
u32 GetData(const u32 d) const { return d << 16 | d >> 16; }
void TaskFP();
//void TaskVP(); // TODO
};

View File

@ -5,118 +5,6 @@
struct GLFragmentDecompilerThread : public ThreadBase struct GLFragmentDecompilerThread : public ThreadBase
{ {
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
};
} dst;
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;
};
} src0;
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
};
} src1;
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;
};
} src2;
std::string main; std::string main;
std::string& m_shader; std::string& m_shader;
GLParamArray& m_parr; GLParamArray& m_parr;

View File

@ -4,184 +4,8 @@
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include <set> #include <set>
enum sca_opcode
{
RSX_SCA_OPCODE_NOP = 0x00,
RSX_SCA_OPCODE_MOV = 0x01,
RSX_SCA_OPCODE_RCP = 0x02,
RSX_SCA_OPCODE_RCC = 0x03,
RSX_SCA_OPCODE_RSQ = 0x04,
RSX_SCA_OPCODE_EXP = 0x05,
RSX_SCA_OPCODE_LOG = 0x06,
RSX_SCA_OPCODE_LIT = 0x07,
RSX_SCA_OPCODE_BRA = 0x08,
RSX_SCA_OPCODE_BRI = 0x09,
RSX_SCA_OPCODE_CAL = 0x0a,
RSX_SCA_OPCODE_CLI = 0x0b,
RSX_SCA_OPCODE_RET = 0x0c,
RSX_SCA_OPCODE_LG2 = 0x0d,
RSX_SCA_OPCODE_EX2 = 0x0e,
RSX_SCA_OPCODE_SIN = 0x0f,
RSX_SCA_OPCODE_COS = 0x10,
RSX_SCA_OPCODE_BRB = 0x11,
RSX_SCA_OPCODE_CLB = 0x12,
RSX_SCA_OPCODE_PSH = 0x13,
RSX_SCA_OPCODE_POP = 0x14,
};
enum vec_opcode
{
RSX_VEC_OPCODE_NOP = 0x00,
RSX_VEC_OPCODE_MOV = 0x01,
RSX_VEC_OPCODE_MUL = 0x02,
RSX_VEC_OPCODE_ADD = 0x03,
RSX_VEC_OPCODE_MAD = 0x04,
RSX_VEC_OPCODE_DP3 = 0x05,
RSX_VEC_OPCODE_DPH = 0x06,
RSX_VEC_OPCODE_DP4 = 0x07,
RSX_VEC_OPCODE_DST = 0x08,
RSX_VEC_OPCODE_MIN = 0x09,
RSX_VEC_OPCODE_MAX = 0x0a,
RSX_VEC_OPCODE_SLT = 0x0b,
RSX_VEC_OPCODE_SGE = 0x0c,
RSX_VEC_OPCODE_ARL = 0x0d,
RSX_VEC_OPCODE_FRC = 0x0e,
RSX_VEC_OPCODE_FLR = 0x0f,
RSX_VEC_OPCODE_SEQ = 0x10,
RSX_VEC_OPCODE_SFL = 0x11,
RSX_VEC_OPCODE_SGT = 0x12,
RSX_VEC_OPCODE_SLE = 0x13,
RSX_VEC_OPCODE_SNE = 0x14,
RSX_VEC_OPCODE_STR = 0x15,
RSX_VEC_OPCODE_SSG = 0x16,
RSX_VEC_OPCODE_TEX = 0x19,
};
struct GLVertexDecompilerThread : public ThreadBase struct GLVertexDecompilerThread : public ThreadBase
{ {
union D0
{
u32 HEX;
struct
{
u32 addr_swz : 2;
u32 mask_w : 2;
u32 mask_z : 2;
u32 mask_y : 2;
u32 mask_x : 2;
u32 cond : 3;
u32 cond_test_enable : 1;
u32 cond_update_enable_0 : 1;
u32 dst_tmp : 6;
u32 src0_abs : 1;
u32 src1_abs : 1;
u32 src2_abs : 1;
u32 addr_reg_sel_1 : 1;
u32 cond_reg_sel_1 : 1;
u32 staturate : 1;
u32 index_input : 1;
u32 : 1;
u32 cond_update_enable_1 : 1;
u32 vec_result : 1;
u32 : 1;
};
} d0;
union D1
{
u32 HEX;
struct
{
u32 src0h : 8;
u32 input_src : 4;
u32 const_src : 10;
u32 vec_opcode : 5;
u32 sca_opcode : 5;
};
} d1;
union D2
{
u32 HEX;
struct
{
u32 src2h : 6;
u32 src1 : 17;
u32 src0l : 9;
};
struct
{
u32 iaddrh : 6;
u32 : 26;
};
} d2;
union D3
{
u32 HEX;
struct
{
u32 end : 1;
u32 index_const : 1;
u32 dst : 5;
u32 sca_dst_tmp : 6;
u32 vec_writemask_w : 1;
u32 vec_writemask_z : 1;
u32 vec_writemask_y : 1;
u32 vec_writemask_x : 1;
u32 sca_writemask_w : 1;
u32 sca_writemask_z : 1;
u32 sca_writemask_y : 1;
u32 sca_writemask_x : 1;
u32 src2l : 11;
};
struct
{
u32 : 29;
u32 iaddrl : 3;
};
} d3;
union SRC
{
union
{
u32 HEX;
struct
{
u32 src0l : 9;
u32 src0h : 8;
};
struct
{
u32 src1 : 17;
};
struct
{
u32 src2l : 11;
u32 src2h : 6;
};
};
struct
{
u32 reg_type : 2;
u32 tmp_src : 6;
u32 swz_w : 2;
u32 swz_z : 2;
u32 swz_y : 2;
u32 swz_x : 2;
u32 neg : 1;
};
} src[3];
struct FuncInfo struct FuncInfo
{ {
u32 offset; u32 offset;

View File

@ -71,6 +71,139 @@ enum
RSX_FP_OPCODE_RET = 0x45, // Return RSX_FP_OPCODE_RET = 0x45, // Return
}; };
static 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
};
} dst;
static 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;
};
} src0;
static 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
};
} src1;
static 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;
};
} src2;
static const char* rsx_fp_input_attr_regs[] =
{
"WPOS", "COL0", "COL1", "FOGC", "TEX0",
"TEX1", "TEX2", "TEX3", "TEX4", "TEX5",
"TEX6", "TEX7", "TEX8", "TEX9", "SSA"
};
static const std::string rsx_fp_op_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"
};
struct RSXFragmentProgram struct RSXFragmentProgram
{ {
u32 size; u32 size;

View File

@ -1,5 +1,195 @@
#pragma once #pragma once
enum sca_opcode
{
RSX_SCA_OPCODE_NOP = 0x00,
RSX_SCA_OPCODE_MOV = 0x01,
RSX_SCA_OPCODE_RCP = 0x02,
RSX_SCA_OPCODE_RCC = 0x03,
RSX_SCA_OPCODE_RSQ = 0x04,
RSX_SCA_OPCODE_EXP = 0x05,
RSX_SCA_OPCODE_LOG = 0x06,
RSX_SCA_OPCODE_LIT = 0x07,
RSX_SCA_OPCODE_BRA = 0x08,
RSX_SCA_OPCODE_BRI = 0x09,
RSX_SCA_OPCODE_CAL = 0x0a,
RSX_SCA_OPCODE_CLI = 0x0b,
RSX_SCA_OPCODE_RET = 0x0c,
RSX_SCA_OPCODE_LG2 = 0x0d,
RSX_SCA_OPCODE_EX2 = 0x0e,
RSX_SCA_OPCODE_SIN = 0x0f,
RSX_SCA_OPCODE_COS = 0x10,
RSX_SCA_OPCODE_BRB = 0x11,
RSX_SCA_OPCODE_CLB = 0x12,
RSX_SCA_OPCODE_PSH = 0x13,
RSX_SCA_OPCODE_POP = 0x14
};
enum vec_opcode
{
RSX_VEC_OPCODE_NOP = 0x00,
RSX_VEC_OPCODE_MOV = 0x01,
RSX_VEC_OPCODE_MUL = 0x02,
RSX_VEC_OPCODE_ADD = 0x03,
RSX_VEC_OPCODE_MAD = 0x04,
RSX_VEC_OPCODE_DP3 = 0x05,
RSX_VEC_OPCODE_DPH = 0x06,
RSX_VEC_OPCODE_DP4 = 0x07,
RSX_VEC_OPCODE_DST = 0x08,
RSX_VEC_OPCODE_MIN = 0x09,
RSX_VEC_OPCODE_MAX = 0x0a,
RSX_VEC_OPCODE_SLT = 0x0b,
RSX_VEC_OPCODE_SGE = 0x0c,
RSX_VEC_OPCODE_ARL = 0x0d,
RSX_VEC_OPCODE_FRC = 0x0e,
RSX_VEC_OPCODE_FLR = 0x0f,
RSX_VEC_OPCODE_SEQ = 0x10,
RSX_VEC_OPCODE_SFL = 0x11,
RSX_VEC_OPCODE_SGT = 0x12,
RSX_VEC_OPCODE_SLE = 0x13,
RSX_VEC_OPCODE_SNE = 0x14,
RSX_VEC_OPCODE_STR = 0x15,
RSX_VEC_OPCODE_SSG = 0x16,
RSX_VEC_OPCODE_TEX = 0x19
};
static union D0
{
u32 HEX;
struct
{
u32 addr_swz : 2;
u32 mask_w : 2;
u32 mask_z : 2;
u32 mask_y : 2;
u32 mask_x : 2;
u32 cond : 3;
u32 cond_test_enable : 1;
u32 cond_update_enable_0 : 1;
u32 dst_tmp : 6;
u32 src0_abs : 1;
u32 src1_abs : 1;
u32 src2_abs : 1;
u32 addr_reg_sel_1 : 1;
u32 cond_reg_sel_1 : 1;
u32 staturate : 1;
u32 index_input : 1;
u32 : 1;
u32 cond_update_enable_1 : 1;
u32 vec_result : 1;
u32 : 1;
};
} d0;
static union D1
{
u32 HEX;
struct
{
u32 src0h : 8;
u32 input_src : 4;
u32 const_src : 10;
u32 vec_opcode : 5;
u32 sca_opcode : 5;
};
} d1;
static union D2
{
u32 HEX;
struct
{
u32 src2h : 6;
u32 src1 : 17;
u32 src0l : 9;
};
struct
{
u32 iaddrh : 6;
u32 : 26;
};
} d2;
static union D3
{
u32 HEX;
struct
{
u32 end : 1;
u32 index_const : 1;
u32 dst : 5;
u32 sca_dst_tmp : 6;
u32 vec_writemask_w : 1;
u32 vec_writemask_z : 1;
u32 vec_writemask_y : 1;
u32 vec_writemask_x : 1;
u32 sca_writemask_w : 1;
u32 sca_writemask_z : 1;
u32 sca_writemask_y : 1;
u32 sca_writemask_x : 1;
u32 src2l : 11;
};
struct
{
u32 : 29;
u32 iaddrl : 3;
};
} d3;
static union SRC
{
union
{
u32 HEX;
struct
{
u32 src0l : 9;
u32 src0h : 8;
};
struct
{
u32 src1 : 17;
};
struct
{
u32 src2l : 11;
u32 src2h : 6;
};
};
struct
{
u32 reg_type : 2;
u32 tmp_src : 6;
u32 swz_w : 2;
u32 swz_z : 2;
u32 swz_y : 2;
u32 swz_x : 2;
u32 neg : 1;
};
} src[3];
static const std::string rsx_vp_sca_op_names[] =
{
"NOP", "MOV", "RCP", "RCC", "RSQ", "EXP", "LOG",
"LIT", "BRA", "BRI", "CAL", "CLI", "RET", "LG2",
"EX2", "SIN", "COS", "BRB", "CLB", "PSH", "POP"
};
static const std::string rsx_vp_vec_op_names[] =
{
"NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DPH", "DP4",
"DST", "MIN", "MAX", "SLT", "SGE", "ARL", "FRC", "FLR",
"SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", "TEX"
};
struct RSXVertexProgram struct RSXVertexProgram
{ {
std::vector<u32> data; std::vector<u32> data;

58
rpcs3/Gui/CgDisasm.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "stdafx_gui.h"
#include "CgDisasm.h"
#include "Emu/System.h"
#include "Emu/RSX/CgBinaryProgram.h"
BEGIN_EVENT_TABLE(CgDisasm, wxFrame)
EVT_SIZE(CgDisasm::OnSize)
END_EVENT_TABLE()
CgDisasm::CgDisasm(wxWindow* parent)
: wxFrame(parent, wxID_ANY, "Cg Disasm", wxDefaultPosition, wxSize(640, 480))
{
wxMenuBar* menubar = new wxMenuBar();
wxMenu* menu_general = new wxMenu();
menubar->Append(menu_general, "&Open");
menu_general->Append(id_open_file, "Open &Cg binary program");
wxNotebook* nb_cg = new wxNotebook(this, wxID_ANY);
wxPanel* p_cg_disasm = new wxPanel(nb_cg, wxID_ANY);
wxPanel* p_glsl_shader = new wxPanel(nb_cg, wxID_ANY);
nb_cg->AddPage(p_cg_disasm, wxT("ASM"));
nb_cg->AddPage(p_glsl_shader, wxT("GLSL"));
m_disasm_text = new wxTextCtrl(p_cg_disasm, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(620, 395), wxTE_MULTILINE | wxNO_BORDER | wxTE_READONLY | wxTE_RICH2);
m_glsl_text = new wxTextCtrl(p_glsl_shader, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(620, 395), wxTE_MULTILINE | wxNO_BORDER | wxTE_READONLY | wxTE_RICH2);
SetMenuBar(menubar);
Bind(wxEVT_MENU, &CgDisasm::OpenCg, this, id_open_file);
}
void CgDisasm::OpenCg(wxCommandEvent& event)
{
wxFileDialog ctrl(this, L"Select Cg program object", wxEmptyString, wxEmptyString,
"Cg program objects (*.fpo;*.vpo)|*.fpo;*.vpo"
"|All files (*.*)|*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (ctrl.ShowModal() == wxID_CANCEL)
{
return;
}
CgBinaryDisasm disasm(fmt::ToUTF8(ctrl.GetPath()));
disasm.BuildShaderBody();
*m_disasm_text << disasm.GetArbShader();
*m_glsl_text << disasm.GetGlslShader();
}
void CgDisasm::OnSize(wxSizeEvent& event)
{
m_disasm_text->SetSize(GetSize().x - 20, GetSize().y - 85);
m_glsl_text->SetSize(GetSize().x - 20, GetSize().y - 85);
event.Skip();
}

22
rpcs3/Gui/CgDisasm.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <wx/wx.h>
enum CgDisasmIds
{
id_open_file
};
class CgDisasm : public wxFrame
{
private:
wxTextCtrl* m_disasm_text;
wxTextCtrl* m_glsl_text;
DECLARE_EVENT_TABLE();
public:
CgDisasm(wxWindow* parent);
void OpenCg(wxCommandEvent& event);
virtual void OnSize(wxSizeEvent& event);
};

View File

@ -22,6 +22,7 @@
#include "Gui/RSXDebugger.h" #include "Gui/RSXDebugger.h"
#include "Gui/MemoryStringSearcher.h" #include "Gui/MemoryStringSearcher.h"
#include "Gui/LLEModulesManager.h" #include "Gui/LLEModulesManager.h"
#include "Gui/CgDisasm.h"
#include <wx/dynlib.h> #include <wx/dynlib.h>
@ -53,8 +54,9 @@ enum IDs
id_tools_memory_viewer, id_tools_memory_viewer,
id_tools_rsx_debugger, id_tools_rsx_debugger,
id_tools_string_search, id_tools_string_search,
id_tools_cg_disasm,
id_help_about, id_help_about,
id_update_dbg, id_update_dbg
}; };
wxString GetPaneName() wxString GetPaneName()
@ -111,6 +113,7 @@ MainFrame::MainFrame()
menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false); menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false);
menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false); menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false);
menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false); menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false);
menu_tools->Append(id_tools_cg_disasm, "&Cg Disasm")->Enable();
wxMenu* menu_help = new wxMenu(); wxMenu* menu_help = new wxMenu();
menubar->Append(menu_help, "&Help"); menubar->Append(menu_help, "&Help");
@ -151,6 +154,7 @@ MainFrame::MainFrame()
Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer); Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer);
Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger); Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger);
Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search); Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search);
Bind(wxEVT_MENU, &MainFrame::OpenCgDisasm, this, id_tools_cg_disasm);
Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about); Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about);
@ -722,6 +726,11 @@ void MainFrame::OpenStringSearch(wxCommandEvent& WXUNUSED(event))
(new MemoryStringSearcher(this)) -> Show(); (new MemoryStringSearcher(this)) -> Show();
} }
void MainFrame::OpenCgDisasm(wxCommandEvent& WXUNUSED(event))
{
(new CgDisasm(this))->Show();
}
void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event)) void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event))
{ {
AboutDialog(this).ShowModal(); AboutDialog(this).ShowModal();

View File

@ -46,7 +46,7 @@ private:
void OpenMemoryViewer(wxCommandEvent& evt); void OpenMemoryViewer(wxCommandEvent& evt);
void OpenRSXDebugger(wxCommandEvent& evt); void OpenRSXDebugger(wxCommandEvent& evt);
void OpenStringSearch(wxCommandEvent& evt); void OpenStringSearch(wxCommandEvent& evt);
void OpenFnIdGenerator(wxCommandEvent& evt); void OpenCgDisasm(wxCommandEvent& evt);
void AboutDialogHandler(wxCommandEvent& event); void AboutDialogHandler(wxCommandEvent& event);
void UpdateUI(wxCommandEvent& event); void UpdateUI(wxCommandEvent& event);
void OnKeyDown(wxKeyEvent& event); void OnKeyDown(wxKeyEvent& event);

View File

@ -37,6 +37,7 @@
<ClCompile Include="..\Utilities\SSemaphore.cpp" /> <ClCompile Include="..\Utilities\SSemaphore.cpp" />
<ClCompile Include="..\Utilities\StrFmt.cpp" /> <ClCompile Include="..\Utilities\StrFmt.cpp" />
<ClCompile Include="..\Utilities\Thread.cpp" /> <ClCompile Include="..\Utilities\Thread.cpp" />
<ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSpursSpu.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellSpursSpu.cpp" />
<ClCompile Include="Crypto\aes.cpp" /> <ClCompile Include="Crypto\aes.cpp" />
<ClCompile Include="Crypto\ec.cpp" /> <ClCompile Include="Crypto\ec.cpp" />
@ -409,6 +410,7 @@
<ClInclude Include="Emu\Memory\Memory.h" /> <ClInclude Include="Emu\Memory\Memory.h" />
<ClInclude Include="Emu\Memory\MemoryBlock.h" /> <ClInclude Include="Emu\Memory\MemoryBlock.h" />
<ClInclude Include="Emu\Memory\atomic_type.h" /> <ClInclude Include="Emu\Memory\atomic_type.h" />
<ClInclude Include="Emu\RSX\CgBinaryProgram.h" />
<ClInclude Include="Emu\RSX\GCM.h" /> <ClInclude Include="Emu\RSX\GCM.h" />
<ClInclude Include="Emu\RSX\GL\GLBuffers.h" /> <ClInclude Include="Emu\RSX\GL\GLBuffers.h" />
<ClInclude Include="Emu\RSX\GL\GLFragmentProgram.h" /> <ClInclude Include="Emu\RSX\GL\GLFragmentProgram.h" />

View File

@ -854,6 +854,9 @@
<ClCompile Include="Emu\ARMv7\Modules\psv_cond.cpp"> <ClCompile Include="Emu\ARMv7\Modules\psv_cond.cpp">
<Filter>Emu\CPU\ARMv7\Objects</Filter> <Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp">
<Filter>Emu\GPU\RSX</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -1519,5 +1522,8 @@
<ClInclude Include="Emu\ARMv7\Modules\psv_cond.h"> <ClInclude Include="Emu\ARMv7\Modules\psv_cond.h">
<Filter>Emu\CPU\ARMv7\Objects</Filter> <Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\RSX\CgBinaryProgram.h">
<Filter>Emu\GPU\RSX</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -43,163 +43,6 @@ Rpcs3App* TheApp;
std::string simplify_path(const std::string& path, bool is_dir); std::string simplify_path(const std::string& path, bool is_dir);
typedef be_t<uint> CGprofile;
typedef int CGbool;
typedef be_t<uint> CGresource;
typedef be_t<uint> CGenum;
typedef be_t<uint> CGtype;
typedef be_t<unsigned int> CgBinaryOffset;
typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset;
typedef CgBinaryOffset CgBinaryFloatOffset;
typedef CgBinaryOffset CgBinaryStringOffset;
typedef CgBinaryOffset CgBinaryParameterOffset;
// a few typedefs
typedef struct CgBinaryParameter CgBinaryParameter;
typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant;
typedef struct CgBinaryVertexProgram CgBinaryVertexProgram;
typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram;
typedef struct CgBinaryProgram CgBinaryProgram;
// fragment programs have their constants embedded in the microcode
struct CgBinaryEmbeddedConstant
{
be_t<unsigned int> ucodeCount; // occurances
be_t<unsigned int> ucodeOffset[1]; // offsets that need to be patched follow
};
// describe a binary program parameter (CgParameter is opaque)
struct CgBinaryParameter
{
CGtype type; // cgGetParameterType()
CGresource res; // cgGetParameterResource()
CGenum var; // cgGetParameterVariability()
be_t<int> resIndex; // cgGetParameterResourceIndex()
CgBinaryStringOffset name; // cgGetParameterName()
CgBinaryFloatOffset defaultValue; // default constant value
CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information
CgBinaryStringOffset semantic; // cgGetParameterSemantic()
CGenum direction; // cgGetParameterDirection()
be_t<int> paramno; // 0..n: cgGetParameterIndex() -1: globals
CGbool isReferenced; // cgIsParameterReferenced()
CGbool isShared; // cgIsParameterShared()
};
// attributes needed for vshaders
struct CgBinaryVertexProgram
{
be_t<unsigned int> instructionCount; // #instructions
be_t<unsigned int> instructionSlot; // load address (indexed reads!)
be_t<unsigned int> registerCount; // R registers count
be_t<unsigned int> attributeInputMask; // attributes vs reads from
be_t<unsigned int> attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits)
be_t<unsigned int> userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL)
};
typedef enum {
CgBinaryPTTNone = 0,
CgBinaryPTT2x16 = 1,
CgBinaryPTT1x32 = 2,
} CgBinaryPartialTexType;
// attributes needed for pshaders
struct CgBinaryFragmentProgram
{
be_t<unsigned int> instructionCount; // #instructions
be_t<unsigned int> attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits)
be_t<unsigned int> partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType
be_t<unsigned short> texCoordsInputMask; // tex coords used by frag prog. (tex<n> is bit n)
be_t<unsigned short> texCoords2D; // tex coords that are 2d (tex<n> is bit n)
be_t<unsigned short> texCoordsCentroid; // tex coords that are centroid (tex<n> is bit n)
unsigned char registerCount; // R registers count
unsigned char outputFromH0; // final color from R0 or H0
unsigned char depthReplace; // fp generated z epth value
unsigned char pixelKill; // fp uses kill operations
};
#include "Emu/RSX/GL/GLFragmentProgram.h"
#include "Emu/RSX/GL/GLVertexProgram.h"
// defines a binary program -- *all* address/offsets are relative to the begining of CgBinaryProgram
struct CgBinaryProgram
{
// vertex/pixel shader identification (BE/LE as well)
CGprofile profile;
// binary revision (used to verify binary and driver structs match)
be_t<unsigned int> binaryFormatRevision;
// total size of this struct including profile and totalSize field!
be_t<unsigned int> totalSize;
// parameter usually queried using cgGet[First/Next]LeafParameter
be_t<unsigned int> parameterCount;
CgBinaryParameterOffset parameterArray;
// depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct
CgBinaryOffset program;
// raw ucode data
be_t<unsigned int> ucodeSize;
CgBinaryOffset ucode;
// variable length data follows
unsigned char data[1];
};
void compile_shader(std::string path)
{
ShaderVar var("r0.yz.x");
var.symplify();
LOG_ERROR(GENERAL, var.get().c_str());
u32 ptr;
{
wxFile f(path);
if (!f.IsOpened())
return;
size_t size = f.Length();
vm::ps3::init();
ptr = vm::alloc(size);
f.Read(vm::get_ptr(ptr), size);
f.Close();
}
CgBinaryProgram& prog = vm::get_ref<CgBinaryProgram>(ptr);
LOG_ERROR(GENERAL, "%d - 0x%x", (u32)prog.profile, (u32)prog.binaryFormatRevision);
std::string shader;
GLParamArray param_array;
u32 size;
if (prog.profile == 7004)
{
CgBinaryFragmentProgram& fprog = vm::get_ref<CgBinaryFragmentProgram>(ptr + prog.program);
u32 ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0);
GLFragmentDecompilerThread(shader, param_array, ptr + prog.ucode, size, ctrl).Task();
}
else
{
CgBinaryVertexProgram& vprog = vm::get_ref<CgBinaryVertexProgram>(ptr + prog.program);
std::vector<u32> data;
be_t<u32>* vdata = vm::get_ptr<be_t<u32>>(ptr + prog.ucode);
for (u32 i = 0; i < prog.ucodeSize; ++i, ++vdata)
{
data.push_back(vdata[i]);
}
GLVertexDecompilerThread(data, shader, param_array).Task();
}
LOG_ERROR(GENERAL, shader.c_str());
vm::close();
}
bool Rpcs3App::OnInit() bool Rpcs3App::OnInit()
{ {
static const wxCmdLineEntryDesc desc[] static const wxCmdLineEntryDesc desc[]
@ -314,9 +157,6 @@ bool Rpcs3App::OnInit()
OnArguments(parser); OnArguments(parser);
//compile_shader("compile_shader0.spo");
//compile_shader("compile_shader1.spo");
return true; return true;
} }

View File

@ -166,6 +166,7 @@
<ClCompile Include="Emu\Cell\PPUProgramCompiler.cpp" /> <ClCompile Include="Emu\Cell\PPUProgramCompiler.cpp" />
<ClCompile Include="Emu\Io\XInput\XInputPadHandler.cpp" /> <ClCompile Include="Emu\Io\XInput\XInputPadHandler.cpp" />
<ClCompile Include="Gui\AutoPauseManager.cpp" /> <ClCompile Include="Gui\AutoPauseManager.cpp" />
<ClCompile Include="Gui\CgDisasm.cpp" />
<ClCompile Include="Gui\CompilerELF.cpp" /> <ClCompile Include="Gui\CompilerELF.cpp" />
<ClCompile Include="Gui\ConLogFrame.cpp" /> <ClCompile Include="Gui\ConLogFrame.cpp" />
<ClCompile Include="Gui\Debugger.cpp" /> <ClCompile Include="Gui\Debugger.cpp" />
@ -205,6 +206,7 @@
<ClInclude Include="Emu\Io\XInput\XInputPadHandler.h" /> <ClInclude Include="Emu\Io\XInput\XInputPadHandler.h" />
<ClInclude Include="Gui\AboutDialog.h" /> <ClInclude Include="Gui\AboutDialog.h" />
<ClInclude Include="Gui\AutoPauseManager.h" /> <ClInclude Include="Gui\AutoPauseManager.h" />
<ClInclude Include="Gui\CgDisasm.h" />
<ClInclude Include="Gui\CompilerELF.h" /> <ClInclude Include="Gui\CompilerELF.h" />
<ClInclude Include="Gui\ConLogFrame.h" /> <ClInclude Include="Gui\ConLogFrame.h" />
<ClInclude Include="Gui\Debugger.h" /> <ClInclude Include="Gui\Debugger.h" />

View File

@ -96,6 +96,9 @@
<ClCompile Include="Gui\MemoryStringSearcher.cpp"> <ClCompile Include="Gui\MemoryStringSearcher.cpp">
<Filter>Gui</Filter> <Filter>Gui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Gui\CgDisasm.cpp">
<Filter>Gui</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="rpcs3.rc" /> <ResourceCompile Include="rpcs3.rc" />
@ -194,8 +197,8 @@
<ClInclude Include="Gui\LLEModulesManager.h"> <ClInclude Include="Gui\LLEModulesManager.h">
<Filter>Gui</Filter> <Filter>Gui</Filter>
</ClInclude> </ClInclude>
<ClCompile Include="git-version.h"> <ClInclude Include="Gui\CgDisasm.h">
<Filter>Gui</Filter> <Filter>Gui</Filter>
</ClCompile> </ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>