mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
move module initialization into a module manager, still has some issues like stopping not working and debug crashing add #idef 0 to modules that aren't in the windows project don't double initialize and don't de-initialize for now, since many modules don't expect it and it leads to many errors remove duplicate module lists for empty modules and implemented ones, make Module non-copyable but movable add secondary project, no real use for it now add some memleak config to the emucore and add asmjit path to rpcs3 small rebase error fixed to get it to compile again add filters for emucore re-add the module manager and static file WIP commit, linker errors abound some more abstraction layer stuff fix the remaining linker errors, re-enable platform specific mouse, pad and keyboard handlers rebasing fix memset undefined and re() usage of se_t before declaration Add wxGUI define by default for cmake builds fix copy constructors of Datetime header fix copy constructors of other wx interface classes remove static declarations of global variables make wxGLCanvas constructor non-ambiguous even with wx2.8. compat mode, fix wrong std::exception constructor calls remove duplicate definition for FromUTF8 and ToUTF8 temp changes
671 lines
16 KiB
C++
671 lines
16 KiB
C++
#include "stdafx.h"
|
|
#include "Emu/ConLog.h"
|
|
#include "Emu/Memory/Memory.h"
|
|
#include "Emu/System.h"
|
|
|
|
#include "GLVertexProgram.h"
|
|
|
|
std::string GLVertexDecompilerThread::GetMask(bool is_sca)
|
|
{
|
|
std::string ret;
|
|
|
|
if(is_sca)
|
|
{
|
|
if(d3.sca_writemask_x) ret += "x";
|
|
if(d3.sca_writemask_y) ret += "y";
|
|
if(d3.sca_writemask_z) ret += "z";
|
|
if(d3.sca_writemask_w) ret += "w";
|
|
}
|
|
else
|
|
{
|
|
if(d3.vec_writemask_x) ret += "x";
|
|
if(d3.vec_writemask_y) ret += "y";
|
|
if(d3.vec_writemask_z) ret += "z";
|
|
if(d3.vec_writemask_w) ret += "w";
|
|
}
|
|
|
|
return ret.empty() || ret == "xyzw" ? "" : ("." + ret);
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetVecMask()
|
|
{
|
|
return GetMask(false);
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetScaMask()
|
|
{
|
|
return GetMask(true);
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetDST(bool isSca)
|
|
{
|
|
std::string ret;
|
|
|
|
switch(d3.dst)
|
|
{
|
|
case 0x1f:
|
|
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
|
|
break;
|
|
|
|
default:
|
|
if (d3.dst > 15)
|
|
ConLog.Error("dst index out of range: %u", d3.dst);
|
|
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)");
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetSRC(const u32 n)
|
|
{
|
|
static const std::string reg_table[] =
|
|
{
|
|
"in_pos", "in_weight", "in_normal",
|
|
"in_diff_color", "in_spec_color",
|
|
"in_fog",
|
|
"in_point_size", "in_7",
|
|
"in_tc0", "in_tc1", "in_tc2", "in_tc3",
|
|
"in_tc4", "in_tc5", "in_tc6", "in_tc7"
|
|
};
|
|
|
|
std::string ret;
|
|
|
|
switch(src[n].reg_type)
|
|
{
|
|
case 1: //temp
|
|
ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src));
|
|
break;
|
|
case 2: //input
|
|
if (d1.input_src < SARRSIZEOF(reg_table))
|
|
{
|
|
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src);
|
|
}
|
|
else
|
|
{
|
|
ConLog.Error("Bad input src num: %d", fmt::by_value(d1.input_src));
|
|
ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src);
|
|
}
|
|
break;
|
|
case 3: //const
|
|
m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]"));
|
|
ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]";
|
|
break;
|
|
|
|
default:
|
|
ConLog.Error("Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type));
|
|
Emu.Pause();
|
|
break;
|
|
}
|
|
|
|
static const std::string f = "xyzw";
|
|
|
|
std::string swizzle;
|
|
|
|
swizzle += f[src[n].swz_x];
|
|
swizzle += f[src[n].swz_y];
|
|
swizzle += f[src[n].swz_z];
|
|
swizzle += f[src[n].swz_w];
|
|
|
|
if(swizzle != f) ret += '.' + swizzle;
|
|
|
|
bool abs;
|
|
|
|
switch(n)
|
|
{
|
|
case 0: abs = d0.src0_abs; break;
|
|
case 1: abs = d0.src1_abs; break;
|
|
case 2: abs = d0.src2_abs; break;
|
|
}
|
|
|
|
if(abs) ret = "abs(" + ret + ")";
|
|
if(src[n].neg) ret = "-" + ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
|
|
{
|
|
if(d0.cond == 0) return;
|
|
|
|
enum
|
|
{
|
|
lt = 0x1,
|
|
eq = 0x2,
|
|
gt = 0x4,
|
|
};
|
|
|
|
std::string mask = GetMask(is_sca);
|
|
|
|
value += mask;
|
|
|
|
if(is_sca && d0.vec_result)
|
|
{
|
|
value = "vec4(" + value + ")" + mask;
|
|
}
|
|
|
|
if(d0.staturate)
|
|
{
|
|
value = "clamp(" + value + ", 0.0, 1.0)";
|
|
}
|
|
|
|
std::string dest;
|
|
|
|
if (d0.cond_update_enable_0 && d0.cond_update_enable_1)
|
|
{
|
|
dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask + " = ";
|
|
}
|
|
|
|
if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
|
|
{
|
|
dest += GetDST(is_sca) + mask + " = ";
|
|
}
|
|
|
|
std::string code;
|
|
|
|
if (d0.cond_test_enable)
|
|
code += "$ifcond ";
|
|
|
|
code += dest + value;
|
|
|
|
AddCode(code + ";");
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetFunc()
|
|
{
|
|
std::string name = "func$a";
|
|
|
|
for(uint i=0; i<m_funcs.size(); ++i)
|
|
{
|
|
if(m_funcs[i].name.compare(name) == 0)
|
|
return name + "()";
|
|
}
|
|
|
|
m_funcs.emplace_back();
|
|
FuncInfo &idx = m_funcs.back();
|
|
idx.offset = GetAddr();
|
|
idx.name = name;
|
|
|
|
return name + "()";
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::Format(const std::string& code)
|
|
{
|
|
const std::pair<std::string, std::function<std::string()>> repl_list[] =
|
|
{
|
|
{ "$$", []() -> std::string { return "$"; } },
|
|
{ "$0", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetSRC), this, 0) },
|
|
{ "$1", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetSRC), this, 1) },
|
|
{ "$2", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetSRC), this, 2) },
|
|
{ "$s", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetSRC), this, 2) },
|
|
{ "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) },
|
|
{ "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) },
|
|
|
|
{ "$fa", [this]()->std::string {return std::to_string(GetAddr()); } },
|
|
{ "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) },
|
|
{ "$ifcond ", [this]() -> std::string
|
|
{
|
|
const std::string& cond = GetCond();
|
|
if (cond == "true") return "";
|
|
return "if(" + cond + ") ";
|
|
}
|
|
},
|
|
{ "$cond", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetCond), this) }
|
|
};
|
|
|
|
return fmt::replace_all(code, repl_list);
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::GetCond()
|
|
{
|
|
enum
|
|
{
|
|
lt = 0x1,
|
|
eq = 0x2,
|
|
gt = 0x4,
|
|
};
|
|
|
|
if (d0.cond == 0) return "false";
|
|
if (d0.cond == (lt | gt | eq)) return "true";
|
|
|
|
static const char* cond_string_table[(lt | gt | eq) + 1] =
|
|
{
|
|
"error",
|
|
"lessThan",
|
|
"equal",
|
|
"lessThanEqual",
|
|
"greaterThan",
|
|
"notEqual",
|
|
"greaterThanEqual",
|
|
"error"
|
|
};
|
|
|
|
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
|
|
|
std::string swizzle;
|
|
swizzle += f[d0.mask_x];
|
|
swizzle += f[d0.mask_y];
|
|
swizzle += f[d0.mask_z];
|
|
swizzle += f[d0.mask_w];
|
|
|
|
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
|
|
|
|
return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str());
|
|
}
|
|
|
|
|
|
std::string GLVertexDecompilerThread::AddAddrMask()
|
|
{
|
|
static const char f[] = { 'x', 'y', 'z', 'w' };
|
|
return std::string(".") + f[d0.addr_swz];
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::AddAddrReg()
|
|
{
|
|
static const char f[] = { 'x', 'y', 'z', 'w' };
|
|
return m_parr.AddParam(PARAM_NONE, "ivec4", "a" + std::to_string(d0.addr_reg_sel_1), "ivec4(0)") + AddAddrMask();
|
|
}
|
|
|
|
u32 GLVertexDecompilerThread::GetAddr()
|
|
{
|
|
return (d2.iaddrh << 3) | d3.iaddrl;
|
|
}
|
|
|
|
void GLVertexDecompilerThread::AddCode(const std::string& code)
|
|
{
|
|
m_body.push_back(Format(code) + ";");
|
|
m_cur_instr->body.push_back(Format(code));
|
|
}
|
|
|
|
void GLVertexDecompilerThread::SetDSTVec(const std::string& code)
|
|
{
|
|
SetDST(false, code);
|
|
}
|
|
|
|
void GLVertexDecompilerThread::SetDSTSca(const std::string& code)
|
|
{
|
|
SetDST(true, code);
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::BuildFuncBody(const FuncInfo& func)
|
|
{
|
|
std::string result;
|
|
|
|
for(uint i=func.offset; i<m_body.size(); ++i)
|
|
{
|
|
if(i != func.offset)
|
|
{
|
|
uint call_func = -1;
|
|
for(uint j=0; j<m_funcs.size(); ++j)
|
|
{
|
|
if(m_funcs[j].offset == i)
|
|
{
|
|
call_func = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(call_func != -1)
|
|
{
|
|
result += '\t' + m_funcs[call_func].name + "();\n";
|
|
break;
|
|
}
|
|
}
|
|
|
|
result += '\t' + m_body[i] + '\n';
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string GLVertexDecompilerThread::BuildCode()
|
|
{
|
|
struct reg_info
|
|
{
|
|
std::string name;
|
|
bool need_declare;
|
|
std::string src_reg;
|
|
std::string src_reg_mask;
|
|
bool need_cast;
|
|
};
|
|
|
|
static const reg_info reg_table[] =
|
|
{
|
|
{ "gl_Position", false, "dst_reg0", "", false },
|
|
{ "diff_color", true, "dst_reg1", "", false },
|
|
{ "spec_color", true, "dst_reg2", "", false },
|
|
{ "front_diff_color", true, "dst_reg3", "", false },
|
|
{ "front_spec_color", true, "dst_reg4", "", false },
|
|
{ "fogc", true, "dst_reg5", ".x", true },
|
|
{ "gl_ClipDistance[0]", false, "dst_reg5", ".y", false },
|
|
{ "gl_ClipDistance[1]", false, "dst_reg5", ".z", false },
|
|
{ "gl_ClipDistance[2]", false, "dst_reg5", ".w", false },
|
|
{ "gl_PointSize", false, "dst_reg6", ".x", false },
|
|
{ "gl_ClipDistance[3]", false, "dst_reg6", ".y", false },
|
|
{ "gl_ClipDistance[4]", false, "dst_reg6", ".z", false },
|
|
{ "gl_ClipDistance[5]", false, "dst_reg6", ".w", false },
|
|
{ "tc0", true, "dst_reg7", "", false },
|
|
{ "tc1", true, "dst_reg8", "", false },
|
|
{ "tc2", true, "dst_reg9", "", false },
|
|
{ "tc3", true, "dst_reg10", "", false },
|
|
{ "tc4", true, "dst_reg11", "", false },
|
|
{ "tc5", true, "dst_reg12", "", false },
|
|
{ "tc6", true, "dst_reg13", "", false },
|
|
{ "tc7", true, "dst_reg14", "", false },
|
|
{ "tc8", true, "dst_reg15", "", false },
|
|
{ "tc9", true, "dst_reg6", "", false }
|
|
};
|
|
|
|
std::string f;
|
|
|
|
for (auto &i : reg_table)
|
|
{
|
|
if (m_parr.HasParam(PARAM_NONE, "vec4", i.src_reg))
|
|
{
|
|
if (i.need_declare)
|
|
{
|
|
m_parr.AddParam(PARAM_OUT, "vec4", i.name);
|
|
}
|
|
|
|
if (i.need_cast)
|
|
{
|
|
f += "\t" + i.name + " = vec4(" + i.src_reg + i.src_reg_mask + ");\n";
|
|
}
|
|
else
|
|
{
|
|
f += "\t" + i.name + " = " + i.src_reg + i.src_reg_mask + ";\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string p;
|
|
|
|
for (u32 i = 0; i<m_parr.params.size(); ++i)
|
|
{
|
|
p += m_parr.params[i].Format();
|
|
}
|
|
|
|
std::string fp;
|
|
|
|
for (int i = m_funcs.size() - 1; i>0; --i)
|
|
{
|
|
fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str());
|
|
}
|
|
|
|
f = fmt::Format("void %s()\n{\n\t%s();\n%s\tgl_Position = gl_Position * scaleOffsetMat;\n}\n",
|
|
m_funcs[0].name.c_str(), m_funcs[1].name.c_str(), f.c_str());
|
|
|
|
std::string main_body;
|
|
for (uint i = 0, lvl = 1; i < m_instr_count; i++)
|
|
{
|
|
lvl -= m_instructions[i].close_scopes;
|
|
if (lvl < 1) lvl = 1;
|
|
//assert(lvl >= 1);
|
|
for (uint j = 0; j < m_instructions[i].put_close_scopes; ++j)
|
|
{
|
|
--lvl;
|
|
if (lvl < 1) lvl = 1;
|
|
main_body.append(lvl, '\t') += "}\n";
|
|
}
|
|
|
|
for (uint j = 0; j < m_instructions[i].do_count; ++j)
|
|
{
|
|
main_body.append(lvl, '\t') += "do\n";
|
|
main_body.append(lvl, '\t') += "{\n";
|
|
lvl++;
|
|
}
|
|
|
|
for (uint j = 0; j < m_instructions[i].body.size(); ++j)
|
|
{
|
|
main_body.append(lvl, '\t') += m_instructions[i].body[j] + "\n";
|
|
}
|
|
|
|
lvl += m_instructions[i].open_scopes;
|
|
}
|
|
|
|
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str());
|
|
|
|
for(uint i=2; i<m_funcs.size(); ++i)
|
|
{
|
|
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[i].name.c_str(), BuildFuncBody(m_funcs[i]).c_str());
|
|
}
|
|
|
|
static const std::string& prot =
|
|
"#version 330\n"
|
|
"\n"
|
|
"uniform mat4 scaleOffsetMat = mat4(1.0);\n"
|
|
"%s\n"
|
|
"%s\n"
|
|
"%s";
|
|
|
|
return fmt::Format(prot, p.c_str(), fp.c_str(), f.c_str());
|
|
}
|
|
|
|
void GLVertexDecompilerThread::Task()
|
|
{
|
|
m_parr.params.clear();
|
|
m_instr_count = 0;
|
|
|
|
for (int i = 0; i < m_max_instr_count; ++i)
|
|
m_instructions[i].reset();
|
|
|
|
for (u32 i = 0; m_instr_count < m_max_instr_count; m_instr_count++)
|
|
{
|
|
m_cur_instr = &m_instructions[m_instr_count];
|
|
|
|
d0.HEX = m_data[i++];
|
|
d1.HEX = m_data[i++];
|
|
d2.HEX = m_data[i++];
|
|
d3.HEX = m_data[i++];
|
|
|
|
src[0].src0l = d2.src0l;
|
|
src[0].src0h = d1.src0h;
|
|
src[1].src1 = d2.src1;
|
|
src[2].src2l = d3.src2l;
|
|
src[2].src2h = d2.src2h;
|
|
|
|
if(!d1.sca_opcode && !d1.vec_opcode)
|
|
{
|
|
m_body.push_back("//nop");
|
|
}
|
|
|
|
switch(d1.sca_opcode)
|
|
{
|
|
case 0x00: break; // NOP
|
|
case 0x01: SetDSTSca("$s"); break; // MOV
|
|
case 0x02: SetDSTSca("(1.0 / $s)"); break; // RCP
|
|
case 0x03: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; // RCC
|
|
case 0x04: SetDSTSca("inversesqrt(abs($s))"); break; // RSQ
|
|
case 0x05: SetDSTSca("exp($s)"); break; // EXP
|
|
case 0x06: SetDSTSca("log($s)"); break; // LOG
|
|
case 0x07: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0 ? exp2($s.w * log2($s.y)) : 0.0), 1.0)"); break; // LIT
|
|
//case 0x08: break; // BRA
|
|
case 0x09: // BRI : works differently (BRI o[1].x(TR) L0;)
|
|
//AddCode("$ifcond { $f(); return; }");
|
|
if (GetAddr() > m_instr_count)
|
|
{
|
|
AddCode("if(!$cond)");
|
|
AddCode("{");
|
|
m_cur_instr->open_scopes++;
|
|
m_instructions[GetAddr()].put_close_scopes++;
|
|
}
|
|
else
|
|
{
|
|
AddCode("} while ($cond);");
|
|
m_cur_instr->close_scopes++;
|
|
m_instructions[GetAddr()].do_count++;
|
|
}
|
|
break;
|
|
//case 0x0a: AddCode("$ifcond $f(); //CAL"); break; // CAL : works same as BRI
|
|
case 0x0b: AddCode("$ifcond $f(); //CLI"); break; // CLI : works same as BRI
|
|
case 0x0c: AddCode("$ifcond return;"); break; // RET : works like BRI but shorter (RET o[1].x(TR);)
|
|
case 0x0d: SetDSTSca("log2($s)"); break; // LG2
|
|
case 0x0e: SetDSTSca("exp2($s)"); break; // EX2
|
|
case 0x0f: SetDSTSca("sin($s)"); break; // SIN
|
|
case 0x10: SetDSTSca("cos($s)"); break; // COS
|
|
//case 0x11: break; // BRB : works differently (BRB o[1].x !b0, L0;)
|
|
//case 0x12: break; // CLB : works same as BRB
|
|
//case 0x13: break; // PSH : works differently (PSH o[1].x A0;)
|
|
//case 0x14: break; // POP : works differently (POP o[1].x;)
|
|
|
|
default:
|
|
m_body.push_back(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
|
|
ConLog.Error("Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode));
|
|
Emu.Pause();
|
|
break;
|
|
}
|
|
|
|
switch(d1.vec_opcode)
|
|
{
|
|
case 0x00: break; //NOP
|
|
case 0x01: SetDSTVec("$0"); break; //MOV
|
|
case 0x02: SetDSTVec("($0 * $1)"); break; //MUL
|
|
case 0x03: SetDSTVec("($0 + $2)"); break; //ADD
|
|
case 0x04: SetDSTVec("($0 * $1 + $2)"); break; //MAD
|
|
case 0x05: SetDSTVec("vec2(dot($0.xyz, $1.xyz), 0.0).xxxx"); break; //DP3
|
|
case 0x06: SetDSTVec("vec2(dot(vec4($0.xyz, 1.0), $1), 0.0).xxxx"); break; //DPH
|
|
case 0x07: SetDSTVec("vec2(dot($0, $1), 0.0).xxxx"); break; //DP4
|
|
case 0x08: SetDSTVec("vec2(distance($0, $1), 0.0).xxxx"); break; //DST
|
|
case 0x09: SetDSTVec("min($0, $1)"); break; //MIN
|
|
case 0x0a: SetDSTVec("max($0, $1)"); break; //MAX
|
|
case 0x0b: SetDSTVec("vec4(lessThan($0, $1))"); break; //SLT
|
|
case 0x0c: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; //SGE
|
|
case 0x0d: AddCode("$ifcond $a = ivec4($0)$am;"); break; //ARL
|
|
case 0x0e: SetDSTVec("fract($0)"); break; //FRC
|
|
case 0x0f: SetDSTVec("floor($0)"); break; //FLR
|
|
case 0x10: SetDSTVec("vec4(equal($0, $1))"); break; //SEQ
|
|
case 0x11: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; //SFL
|
|
case 0x12: SetDSTVec("vec4(greaterThan($0, $1))"); break; //SGT
|
|
case 0x13: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; //SLE
|
|
case 0x14: SetDSTVec("vec4(notEqual($0, $1))"); break; //SNE
|
|
case 0x15: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; //STR
|
|
case 0x16: SetDSTVec("sign($0)"); break; //SSG
|
|
|
|
default:
|
|
m_body.push_back(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)));
|
|
ConLog.Error("Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode));
|
|
Emu.Pause();
|
|
break;
|
|
}
|
|
|
|
if(d3.end)
|
|
{
|
|
m_instr_count++;
|
|
|
|
if(i < m_data.size())
|
|
ConLog.Error("Program end before buffer end.");
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_shader = BuildCode();
|
|
|
|
m_body.clear();
|
|
if (m_funcs.size() > 2)
|
|
{
|
|
m_funcs.erase(m_funcs.begin()+2, m_funcs.end());
|
|
}
|
|
}
|
|
|
|
GLVertexProgram::GLVertexProgram()
|
|
: m_decompiler_thread(nullptr)
|
|
, id(0)
|
|
{
|
|
}
|
|
|
|
GLVertexProgram::~GLVertexProgram()
|
|
{
|
|
if(m_decompiler_thread)
|
|
{
|
|
Wait();
|
|
if(m_decompiler_thread->IsAlive())
|
|
{
|
|
m_decompiler_thread->Stop();
|
|
}
|
|
|
|
delete m_decompiler_thread;
|
|
m_decompiler_thread = nullptr;
|
|
}
|
|
|
|
Delete();
|
|
}
|
|
|
|
void GLVertexProgram::Wait()
|
|
{
|
|
if(m_decompiler_thread && m_decompiler_thread->IsAlive())
|
|
{
|
|
m_decompiler_thread->Join();
|
|
}
|
|
}
|
|
|
|
void GLVertexProgram::Decompile(RSXVertexProgram& prog)
|
|
{
|
|
GLVertexDecompilerThread(prog.data, shader, parr);
|
|
}
|
|
|
|
void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog)
|
|
{
|
|
if (m_decompiler_thread)
|
|
{
|
|
Wait();
|
|
if (m_decompiler_thread->IsAlive())
|
|
{
|
|
m_decompiler_thread->Stop();
|
|
}
|
|
|
|
delete m_decompiler_thread;
|
|
m_decompiler_thread = nullptr;
|
|
}
|
|
|
|
m_decompiler_thread = new GLVertexDecompilerThread(prog.data, shader, parr);
|
|
m_decompiler_thread->Start();
|
|
}
|
|
|
|
void GLVertexProgram::Compile()
|
|
{
|
|
if(id) glDeleteShader(id);
|
|
|
|
id = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
const char* str = shader.c_str();
|
|
const int strlen = shader.length();
|
|
|
|
glShaderSource(id, 1, &str, &strlen);
|
|
glCompileShader(id);
|
|
|
|
GLint r = GL_FALSE;
|
|
glGetShaderiv(id, GL_COMPILE_STATUS, &r);
|
|
if(r != GL_TRUE)
|
|
{
|
|
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r);
|
|
|
|
if(r)
|
|
{
|
|
char* buf = new char[r+1];
|
|
GLsizei len;
|
|
memset(buf, 0, r+1);
|
|
glGetShaderInfoLog(id, r, &len, buf);
|
|
ConLog.Error("Failed to compile vertex shader: %s", buf);
|
|
delete[] buf;
|
|
}
|
|
|
|
ConLog.Write(shader);
|
|
Emu.Pause();
|
|
}
|
|
//else ConLog.Write("Vertex shader compiled successfully!");
|
|
|
|
}
|
|
|
|
void GLVertexProgram::Delete()
|
|
{
|
|
parr.params.clear();
|
|
shader.clear();
|
|
|
|
if(id)
|
|
{
|
|
glDeleteShader(id);
|
|
id = 0;
|
|
}
|
|
}
|