From df794b88b092386c840152718037ad123652f485 Mon Sep 17 00:00:00 2001 From: vlj Date: Tue, 19 May 2015 19:43:22 +0200 Subject: [PATCH] GL: Use decompiler common class --- rpcs3/Emu/RSX/CgBinaryProgram.h | 2 +- rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp | 728 ++++----------------- rpcs3/Emu/RSX/GL/GLFragmentProgram.h | 66 +- rpcs3/Emu/RSX/GL/GLShaderParam.h | 228 ------- rpcs3/Emu/RSX/GL/GLVertexProgram.cpp | 868 ++++--------------------- rpcs3/Emu/RSX/GL/GLVertexProgram.h | 93 +-- rpcs3/emucore.vcxproj | 1 - rpcs3/emucore.vcxproj.filters | 3 - 8 files changed, 317 insertions(+), 1672 deletions(-) delete mode 100644 rpcs3/Emu/RSX/GL/GLShaderParam.h diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h index ff64e96e94..185c0002d6 100644 --- a/rpcs3/Emu/RSX/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -273,7 +273,7 @@ public: void BuildShaderBody() { - GLParamArray param_array; + ParamArray param_array; auto& prog = GetCgRef(0); diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index f203f3be05..1bd5616c5a 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -4,332 +4,93 @@ #include "Emu/System.h" #include "GLFragmentProgram.h" -void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask) +std::string GLFragmentDecompilerThread::getFloatTypeName(size_t elementCount) { - if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; - - switch (src1.scale) + switch (elementCount) { - case 0: break; - case 1: code = "(" + code + " * 2.0)"; break; - case 2: code = "(" + code + " * 4.0)"; break; - case 3: code = "(" + code + " * 8.0)"; break; - case 5: code = "(" + code + " / 2.0)"; break; - case 6: code = "(" + code + " / 4.0)"; break; - case 7: code = "(" + code + " / 8.0)"; break; - default: - LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale)); - Emu.Pause(); - break; - } - - if (dst.saturate) - { - code = "clamp(" + code + ", 0.0, 1.0)"; - } - - code += (append_mask ? "$m" : ""); - - if (dst.no_dest) - { - if (dst.set_cond) - { - AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";"); - } - else - { - AddCode("$ifcond " + code + ";"); - } - - return; - } - - std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m"; - - AddCodeCond(Format(dest), code); - //AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); - - if (dst.set_cond) - { - AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";"); + abort(); + case 1: + return "float"; + case 2: + return "vec2"; + case 3: + return "vec3"; + case 4: + return "vec4"; } } -void GLFragmentDecompilerThread::AddCode(const std::string& code) +std::string GLFragmentDecompilerThread::getFunction(FUNCTION f) { - main.append(m_code_level, '\t') += Format(code) + "\n"; -} - -std::string GLFragmentDecompilerThread::GetMask() -{ - std::string ret; - - static const char dst_mask[4] = + switch (f) { - '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 GLFragmentDecompilerThread::AddReg(u32 index, int fp16) -{ - return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)"); -} - -bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) -{ - return m_parr.HasParam(PARAM_NONE, "vec4", - std::string(fp16 ? "h" : "r") + std::to_string(index)); -} - -std::string GLFragmentDecompilerThread::AddCond() -{ - return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index)); -} - -std::string GLFragmentDecompilerThread::AddConst() -{ - std::string name = std::string("fc") + std::to_string(m_size + 4 * 4); - if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) - { - return name; - } - - auto data = vm::ptr::make(m_addr + m_size + 4 * sizeof(u32)); - - m_offset = 2 * 4 * sizeof(u32); - u32 x = 0;//GetData(data[0]); - u32 y = 0;//GetData(data[1]); - u32 z = 0;//GetData(data[2]); - u32 w = 0;//GetData(data[3]); - return m_parr.AddParam(PARAM_UNIFORM, "vec4", name, - std::string("vec4(") + std::to_string((float&)x) + ", " + std::to_string((float&)y) - + ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")"); -} - -std::string GLFragmentDecompilerThread::AddTex() -{ - return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("tex") + std::to_string(dst.tex_num)); -} - -std::string GLFragmentDecompilerThread::Format(const std::string& code) -{ - const std::pair> repl_list[] = - { - { "$$", []() -> std::string { return "$"; } }, - { "$0", [this]{ return GetSRC(src0); } }, - { "$1", [this]{ return GetSRC(src1); } }, - { "$2", [this]{ return GetSRC(src2); } }, - { "$t", [this]{ return AddTex(); } }, - { "$m", [this]{ return GetMask(); } }, - - { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } - }, - - { "$cond", [this]{ return GetCond(); } }, - { "$c", [this]{ return AddConst(); } } - }; - - return fmt::replace_all(code, repl_list); -} - -std::string GLFragmentDecompilerThread::GetCond() -{ - if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) - { - return "true"; - } - else if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) - { - return "false"; - } - - 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]; - swizzle = swizzle == "xyzw" ? "" : "." + swizzle; - - if (src0.exec_if_gr && src0.exec_if_eq) - { - cond = "greaterThanEqual"; - } - else if (src0.exec_if_lt && src0.exec_if_eq) - { - cond = "lessThanEqual"; - } - else if (src0.exec_if_gr && src0.exec_if_lt) - { - cond = "notEqual"; - } - else if (src0.exec_if_gr) - { - cond = "greaterThan"; - } - else if (src0.exec_if_lt) - { - cond = "lessThan"; - } - else //if(src0.exec_if_eq) - { - cond = "equal"; - } - - return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))"; -} - -void GLFragmentDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) -{ - if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) - { - AddCode(dst + " = " + src + ";"); - return; - } - - if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) - { - AddCode("//" + dst + " = " + src + ";"); - return; - } - - 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]; - swizzle = swizzle == "xyzw" ? "" : "." + swizzle; - - if (src0.exec_if_gr && src0.exec_if_eq) - { - cond = "greaterThanEqual"; - } - else if (src0.exec_if_lt && src0.exec_if_eq) - { - cond = "lessThanEqual"; - } - else if (src0.exec_if_gr && src0.exec_if_lt) - { - cond = "notEqual"; - } - else if (src0.exec_if_gr) - { - cond = "greaterThan"; - } - else if (src0.exec_if_lt) - { - cond = "lessThan"; - } - else //if(src0.exec_if_eq) - { - cond = "equal"; - } - - cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))"; - - ShaderVar dst_var(dst); - dst_var.symplify(); - - //const char *c_mask = f; - - if (dst_var.swizzles[0].length() == 1) - { - AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); - } - else - { - for (int i = 0; i < dst_var.swizzles[0].length(); ++i) - { - AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); - } - } -} - -template std::string GLFragmentDecompilerThread::GetSRC(T src) -{ - std::string ret; - - switch (src.reg_type) - { - case 0: //tmp - ret += AddReg(src.tmp_reg_index, src.fp16); - break; - - case 1: //input - { - static const std::string reg_table[] = - { - "gl_Position", - "diff_color", "spec_color", - "fogc", - "tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8", "tc9", - "ssa" - }; - - 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 += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]); - } - else - { - LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num)); - ret += m_parr.AddParam(PARAM_IN, "vec4", "unk"); - Emu.Pause(); - } - break; - } - } - break; - - case 2: //const - ret += AddConst(); - break; - default: - LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type)); - Emu.Pause(); - break; + abort(); + case FUNCTION::FUNCTION_DP2: + return "vec4(dot($0.xy, $1.xy))"; + case FUNCTION::FUNCTION_DP2A: + return ""; + case FUNCTION::FUNCTION_DP3: + return "vec4(dot($0.xyz, $1.xyz))"; + case FUNCTION::FUNCTION_DP4: + return "vec4(dot($0, $1))"; + case FUNCTION::FUNCTION_SFL: + return "vec4(0., 0., 0., 0.)"; + case FUNCTION::FUNCTION_STR: + return "vec4(1., 1., 1., 1.)"; + case FUNCTION::FUNCTION_FRACT: + return "fract($0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE: + return "texture($t, $0.xy)"; + case FUNCTION::FUNCTION_DFDX: + return "dFdx($0)"; + case FUNCTION::FUNCTION_DFDY: + return "dFdy($0)"; } - - 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 (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; - - if (src.abs) ret = "abs(" + ret + ")"; - if (src.neg) ret = "-" + ret; - - return ret; } -std::string GLFragmentDecompilerThread::BuildCode() +std::string GLFragmentDecompilerThread::saturate(const std::string & code) +{ + return "clamp(" + code + ", 0., 1.)"; +} + +std::string GLFragmentDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) +{ + switch (f) + { + case COMPARE::FUNCTION_SEQ: + return "equal(" + Op0 + ", " + Op1 + ")"; + case COMPARE::FUNCTION_SGE: + return "greaterThanEqual(" + Op0 + ", " + Op1 + ")"; + case COMPARE::FUNCTION_SGT: + return "greaterThan(" + Op0 + ", " + Op1 + ")"; + case COMPARE::FUNCTION_SLE: + return "lessThanEqual(" + Op0 + ", " + Op1 + ")"; + case COMPARE::FUNCTION_SLT: + return "lessThan(" + Op0 + ", " + Op1 + ")"; + case COMPARE::FUNCTION_SNE: + return "notEqual(" + Op0 + ", " + Op1 + ")"; + } +} + + +void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS) +{ + OS << "#version 420" << std::endl; +} + +void GLFragmentDecompilerThread::insertIntputs(std::stringstream & OS) +{ + for (ParamType PT : m_parr.params[PF_PARAM_IN]) + { + for (ParamItem PI : PT.items) + OS << "in " << PT.type << " " << PI.name << ";" << std::endl; + } +} + +void GLFragmentDecompilerThread::insertOutputs(std::stringstream & OS) { - //main += fmt::Format("\tgl_FragColor = %c0;\n", m_ctrl & 0x40 ? 'r' : 'h'); const std::pair table[] = { { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, @@ -340,280 +101,70 @@ std::string GLFragmentDecompilerThread::BuildCode() for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) { - if (m_parr.HasParam(PARAM_NONE, "vec4", table[i].second)) - AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";"); + if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second)) + OS << "out vec4 " << table[i].first << ";" << std::endl; + } +} + +void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) +{ + for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (PT.type != "sampler2D") + continue; + for (ParamItem PI : PT.items) + OS << "uniform " << PT.type << " " << PI.name << ";" << std::endl; + } - if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n"; + for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (PT.type == "sampler2D") + continue; + for (ParamItem PI : PT.items) + OS << "uniform " << PT.type << " " << PI.name << ";" << std::endl; + } +} - std::string p; +void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) +{ + OS << "void main ()" << std::endl; + OS << "{" << std::endl; - for (auto& param : m_parr.params) { - p += param.Format(); + for (ParamType PT : m_parr.params[PF_PARAM_NONE]) + { + for (ParamItem PI : PT.items) + { + OS << " " << PT.type << " " << PI.name; + if (!PI.value.empty()) + OS << " = " << PI.value; + OS << ";" << std::endl; + } + } +} + +void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) +{ + const std::pair table[] = + { + { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, + }; + + for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) + { + if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second)) + OS << " " << table[i].first << " = " << table[i].second << ";" << std::endl; } - return std::string("#version 420\n" - "\n" - + p + "\n" - "void main()\n{\n" + main + "}\n"); + OS << "};" << std::endl; } void GLFragmentDecompilerThread::Task() { - auto data = vm::ptr::make(m_addr); - m_size = 0; - m_location = 0; - m_loop_count = 0; - m_code_level = 1; - - enum - { - FORCE_NONE, - FORCE_SCT, - FORCE_SCB, - }; - - int forced_unit = FORCE_NONE; - - while (true) - { - for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); - found != m_end_offsets.end(); - found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size)) - { - m_end_offsets.erase(found); - m_code_level--; - AddCode("}"); - m_loop_count--; - } - - for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size); - found != m_else_offsets.end(); - found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size)) - { - m_else_offsets.erase(found); - m_code_level--; - AddCode("}"); - AddCode("else"); - AddCode("{"); - m_code_level++; - } - - dst.HEX = GetData(data[0]); - src0.HEX = GetData(data[1]); - src1.HEX = GetData(data[2]); - src2.HEX = GetData(data[3]); - - m_offset = 4 * sizeof(u32); - - const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); - - auto SCT = [&]() - { - switch (opcode) - { - case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; - case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); break; - case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; - case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; - case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; - case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; - case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; - case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; - case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; - case RSX_FP_OPCODE_MOV: SetDst("$0"); break; - case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; - case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break; - case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; - case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; - case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; - case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; - case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; - case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; - case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; - - default: - return false; - } - - return true; - }; - - auto SCB = [&]() - { - switch (opcode) - { - case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; - case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); break; - case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; - case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; - case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; - case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; - case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; - case RSX_FP_OPCODE_REFL: LOG_ERROR(RSX, "Unimplemented SCB instruction: REFL"); break; // TODO: Is this in the right category? - case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); break; - case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; - case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; - case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); break; // TODO: Is this in the right category? - case RSX_FP_OPCODE_LG2: SetDst("log2($0.xxxx)"); break; - case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; - case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; - case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; - case RSX_FP_OPCODE_MOV: SetDst("$0"); break; - case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; - case RSX_FP_OPCODE_PK2: SetDst("packSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) - case RSX_FP_OPCODE_PK4: SetDst("packSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) - case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break; - case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break; - case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break; - case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; - case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; - case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; - case RSX_FP_OPCODE_SIN: SetDst("sin($0.xxxx)"); break; - case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; - case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; - case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; - - default: - return false; - } - - return true; - }; - - auto TEX_SRB = [&]() - { - switch (opcode) - { - case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; - case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; - case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break; - case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); break; - case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; - case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); break; - case RSX_FP_OPCODE_TXP: SetDst("textureProj($t, $0.xyz, $1.x)"); break; //TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478) and The Simpsons Arcade Game (NPUB30563)) - case RSX_FP_OPCODE_TXPBEM: SetDst("textureProj($t, $0.xyz, $1.x)"); break; - case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break; - case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); break; - case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); break; - case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) - case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) - case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break; - case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break; - case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break; - - default: - return false; - } - - return true; - }; - - auto SIP = [&]() - { - switch (opcode) - { - case RSX_FP_OPCODE_BRK: SetDst("break"); break; - case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break; - case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break; - case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break; - case RSX_FP_OPCODE_IFE: - AddCode("if($cond)"); - if (src2.end_offset != src1.else_offset) - m_else_offsets.push_back(src1.else_offset << 2); - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - break; - case RSX_FP_OPCODE_LOOP: - if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - case RSX_FP_OPCODE_REP: - if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - case RSX_FP_OPCODE_RET: SetDst("return"); break; - - default: - return false; - } - - return true; - }; - - switch (opcode) - { - case RSX_FP_OPCODE_NOP: break; - case RSX_FP_OPCODE_KIL: SetDst("discard", false); 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)", opcode, forced_unit); - break; - } - - m_size += m_offset; - - if (dst.end) break; - - assert(m_offset % sizeof(u32) == 0); - data += m_offset / sizeof(u32); - } - - // flush m_code_level - m_code_level = 1; - m_shader = BuildCode(); - main.clear(); -// m_parr.params.clear(); + m_shader = Decompile(); } GLFragmentProgram::GLFragmentProgram() @@ -651,6 +202,14 @@ void GLFragmentProgram::Decompile(RSXFragmentProgram& prog) { GLFragmentDecompilerThread decompiler(shader, parr, prog.addr, prog.size, prog.ctrl); decompiler.Task(); + for (const ParamType& PT : decompiler.m_parr.params[PF_PARAM_UNIFORM]) + { + for (const ParamItem PI : PT.items) + { + size_t offset = atoi(PI.name.c_str() + 2); + FragmentConstantOffsetCache.push_back(offset); + } + } } void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog) @@ -707,25 +266,10 @@ void GLFragmentProgram::Compile() LOG_NOTICE(RSX, shader.c_str()); // Log the text of the shader that failed to compile Emu.Pause(); // Pause the emulator, we can't really continue from here } - for (const GLParamType& PT : parr.params) - { - if (PT.flag != PARAM_UNIFORM) continue; - for (const GLParamItem PI : PT.items) - { - size_t offset = atoi(PI.name.c_str() + 2); - FragmentConstantOffsetCache.push_back(offset); - } - } } void GLFragmentProgram::Delete() { - for (auto& param : parr.params) { - param.items.clear(); - param.type.clear(); - } - - parr.params.clear(); shader.clear(); if (id) diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index 3430e85a39..7b16b5974d 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -1,56 +1,34 @@ #pragma once -#include "GLShaderParam.h" +#include "../Common/FragmentProgramDecompiler.h" #include "Emu/RSX/RSXFragmentProgram.h" #include "Utilities/Thread.h" +#include "OpenGL.h" -struct GLFragmentDecompilerThread : public ThreadBase +struct GLFragmentDecompilerThread : public ThreadBase, public FragmentProgramDecompiler { - std::string main; std::string& m_shader; - GLParamArray& m_parr; - u32 m_addr; - u32& m_size; - u32 m_const_index; - u32 m_offset; - u32 m_location; - u32 m_ctrl; - u32 m_loop_count; - int m_code_level; - std::vector m_end_offsets; - std::vector m_else_offsets; - - GLFragmentDecompilerThread(std::string& shader, GLParamArray& parr, u32 addr, u32& size, u32 ctrl) - : ThreadBase("Fragment Shader Decompiler Thread") + ParamArray& m_parrDummy; +public: + GLFragmentDecompilerThread(std::string& shader, ParamArray& parr, u32 addr, u32& size, u32 ctrl) + : ThreadBase("Fragment Shader Decompiler Thread"), FragmentProgramDecompiler(addr, size, ctrl) , m_shader(shader) - , m_parr(parr) - , m_addr(addr) - , m_size(size) - , m_const_index(0) - , m_location(0) - , m_ctrl(ctrl) - { - m_size = 0; - } + , m_parrDummy(parr) + {} - std::string GetMask(); + void Task(); - void SetDst(std::string code, bool append_mask = true); - void AddCode(const std::string& code); - std::string AddReg(u32 index, int fp16); - bool HasReg(u32 index, int fp16); - std::string AddCond(); - std::string AddConst(); - std::string AddTex(); - std::string Format(const std::string& code); +protected: + virtual std::string getFloatTypeName(size_t elementCount) override; + virtual std::string getFunction(FUNCTION) override; + virtual std::string saturate(const std::string &code) override; + virtual std::string compareFunction(COMPARE, const std::string&, const std::string&) override; - void AddCodeCond(const std::string& dst, const std::string& src); - std::string GetCond(); - template std::string GetSRC(T src); - std::string BuildCode(); - - virtual void Task(); - - u32 GetData(const u32 d) const { return d << 16 | d >> 16; } + virtual void insertHeader(std::stringstream &OS) override; + virtual void insertIntputs(std::stringstream &OS) override; + virtual void insertOutputs(std::stringstream &OS) override; + virtual void insertConstants(std::stringstream &OS) override; + virtual void insertMainStart(std::stringstream &OS) override; + virtual void insertMainEnd(std::stringstream &OS) override; }; /** Storage for an Fragment Program in the process of of recompilation. @@ -62,7 +40,7 @@ public: GLFragmentProgram(); ~GLFragmentProgram(); - GLParamArray parr; + ParamArray parr; u32 id; std::string shader; std::vector FragmentConstantOffsetCache; diff --git a/rpcs3/Emu/RSX/GL/GLShaderParam.h b/rpcs3/Emu/RSX/GL/GLShaderParam.h deleted file mode 100644 index c30e283ab7..0000000000 --- a/rpcs3/Emu/RSX/GL/GLShaderParam.h +++ /dev/null @@ -1,228 +0,0 @@ -#pragma once -#include "OpenGL.h" - -enum GLParamFlag -{ - PARAM_IN, - PARAM_OUT, - PARAM_UNIFORM, - PARAM_CONST, - PARAM_NONE, -}; - -struct GLParamItem -{ - std::string name; - std::string location; - std::string value; - - GLParamItem(const std::string& _name, int _location, const std::string& _value = "") - : name(_name) - , value(_value) - { - if (_location > -1) - location = "layout (location = " + std::to_string(_location) + ") "; - else - location = ""; - } -}; - -struct GLParamType -{ - const GLParamFlag flag; - std::string type; - std::vector items; - - GLParamType(const GLParamFlag _flag, const std::string& _type) - : flag(_flag) - , type(_type) - { - } - - bool SearchName(const std::string& name) - { - for (u32 i = 0; i params; - - GLParamType* SearchParam(const std::string& type) - { - for (u32 i = 0; iSearchName(name); - } - - std::string AddParam(const GLParamFlag flag, std::string type, const std::string& name, const std::string& value) - { - type = GetParamFlag(flag) + type; - GLParamType* t = SearchParam(type); - - if (t) - { - if (!t->SearchName(name)) t->items.emplace_back(name, -1, value); - } - else - { - const u32 num = params.size(); - params.emplace_back(flag, type); - params[num].items.emplace_back(name, -1, value); - } - - return name; - } - - std::string AddParam(const GLParamFlag flag, std::string type, const std::string& name, int location = -1) - { - type = GetParamFlag(flag) + type; - GLParamType* t = SearchParam(type); - - if (t) - { - if (!t->SearchName(name)) t->items.emplace_back(name, location); - } - else - { - const u32 num = params.size(); - params.emplace_back(flag, type); - params[num].items.emplace_back(name, location); - } - - return name; - } -}; - -class ShaderVar -{ -public: - std::string name; - std::vector swizzles; - - ShaderVar() = default; - ShaderVar(const std::string& var) - { - auto var_blocks = fmt::split(var, { "." }); - - if (var_blocks.size() == 0) - { - assert(0); - } - - name = var_blocks[0]; - - if (var_blocks.size() == 1) - { - swizzles.push_back("xyzw"); - } - else - { - swizzles = std::vector(var_blocks.begin() + 1, var_blocks.end()); - } - } - - int get_vector_size() const - { - return swizzles[swizzles.size() - 1].length(); - } - - ShaderVar& symplify() - { - std::unordered_map swizzle; - - static std::unordered_map pos_to_swizzle = - { - { 0, 'x' }, - { 1, 'y' }, - { 2, 'z' }, - { 3, 'w' } - }; - - for (auto &i : pos_to_swizzle) - { - swizzle[i.second] = swizzles[0].length() > i.first ? swizzles[0][i.first] : 0; - } - - for (int i = 1; i < swizzles.size(); ++i) - { - std::unordered_map new_swizzle; - - for (auto &sw : pos_to_swizzle) - { - new_swizzle[sw.second] = swizzle[swizzles[i].length() <= sw.first ? '\0' : swizzles[i][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 get() const - { - if (swizzles.size() == 1 && swizzles[0] == "xyzw") - { - return name; - } - - return name + "." + fmt::merge({ swizzles }, "."); - } -}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index 291fc4d6e7..32475e2600 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -4,765 +4,174 @@ #include "GLVertexProgram.h" -std::string GLVertexDecompilerThread::GetMask(bool is_sca) +std::string GLVertexDecompilerThread::getFloatTypeName(size_t elementCount) { - std::string ret; - - if (is_sca) + switch (elementCount) { - 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 (isSca ? 0x1f : 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) - LOG_ERROR(RSX, fmt::Format("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; + abort(); + case 1: + return "float"; + case 2: + return "vec2"; + case 3: + return "vec3"; + case 4: + return "vec4"; } - - return ret; } -std::string GLVertexDecompilerThread::GetSRC(const u32 n) +std::string GLVertexDecompilerThread::getFunction(FUNCTION f) { - static const std::string reg_table[] = + switch (f) { - "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 < (sizeof(reg_table) / sizeof(reg_table[0]))) - { - ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src); - } - else - { - LOG_ERROR(RSX, "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: - LOG_ERROR(RSX, fmt::Format("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 + ")"; - } - - 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; - } - else 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 + ";"); - - AddCodeCond(Format(dest), value); -} - -std::string GLVertexDecompilerThread::GetFunc() -{ - std::string name = "func$a"; - - for (const auto& func : m_funcs) { - if (func.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::GetTex() -{ - return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0)); -} - -std::string GLVertexDecompilerThread::Format(const std::string& code) -{ - const std::pair> repl_list[] = - { - { "$$", []() -> std::string { return "$"; } }, - { "$0", [this]{ return GetSRC(0); } }, - { "$1", [this]{ return GetSRC(1); } }, - { "$2", [this]{ return GetSRC(2); } }, - { "$s", [this]{ return GetSRC(2); } }, - { "$am", [this]{ return AddAddrMask(); } }, - { "$a", [this]{ return AddAddrReg(); } }, - { "$t", [this]{ return GetTex(); } }, - { "$fa", [this]{ return std::to_string(GetAddr()); } }, - { "$f()", [this]{ return GetFunc(); } }, - - { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } - }, - - { "$cond", [this]{ return GetCond(); } } - }; - - 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()); -} - -void GLVertexDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) -{ - enum - { - lt = 0x1, - eq = 0x2, - gt = 0x4, - }; - - - if (!d0.cond_test_enable || d0.cond == (lt | gt | eq)) - { - AddCode(dst + " = " + src + ";"); - return; - } - - if (d0.cond == 0) - { - AddCode("//" + dst + " = " + src + ";"); - return; - } - - 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; - - std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str()); - - ShaderVar dst_var(dst); - dst_var.symplify(); - - //const char *c_mask = f; - - if (dst_var.swizzles[0].length() == 1) - { - AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); - } - else - { - for (int i = 0; i < dst_var.swizzles[0].length(); ++i) - { - AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); - } + abort(); + case FUNCTION::FUNCTION_DP2: + return "vec4(dot($0.xy, $1.xy))"; + case FUNCTION::FUNCTION_DP2A: + return ""; + case FUNCTION::FUNCTION_DP3: + return "vec4(dot($0.xyz, $1.xyz))"; + case FUNCTION::FUNCTION_DP4: + return "vec4(dot($0, $1))"; + case FUNCTION::FUNCTION_SFL: + return "vec4(0., 0., 0., 0.)"; + case FUNCTION::FUNCTION_STR: + return "vec4(1., 1., 1., 1.)"; + case FUNCTION::FUNCTION_FRACT: + return "fract($0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE: + return "texture($t, $0.xy)"; + case FUNCTION::FUNCTION_DFDX: + return "dFdx($0)"; + case FUNCTION::FUNCTION_DFDY: + return "dFdy($0)"; } } - -std::string GLVertexDecompilerThread::AddAddrMask() +std::string GLVertexDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) { - 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& inputs) +{ + for (const ParamType PT : inputs) { - std::string name; - bool need_declare; - std::string src_reg; - std::string src_reg_mask; - bool need_cast; - }; + for (const ParamItem &PI : PT.items) + OS << "layout(location = " << PI.location << ") in " << PT.type << " " << PI.name << ";" << std::endl; + } +} - static const reg_info reg_table[] = +void GLVertexDecompilerThread::insertConstants(std::stringstream & OS, const std::vector & constants) +{ + for (const ParamType PT : constants) { - { "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 } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15. - }; + for (const ParamItem &PI : PT.items) + OS << "uniform " << PT.type << " " << PI.name << ";" << std::endl; + } +} - std::string f; +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 } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15. +}; + +void GLVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::vector & outputs) +{ 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"; - } - } + if (m_parr.HasParam(PF_PARAM_NONE, "vec4", i.src_reg) && i.need_declare) + OS << "out vec4 " << i.name << ";" << std::endl; } - - std::string p; - - for (auto& param : m_parr.params) { - p += param.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; iopen_scopes++; - - AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); - AddCode("{"); - m_cur_instr->open_scopes++; - } - - for (u32 i = 0; i < m_instr_count; ++i) - { - m_cur_instr = &m_instructions[i]; - - d0.HEX = m_data[i * 4 + 0]; - d1.HEX = m_data[i * 4 + 1]; - d2.HEX = m_data[i * 4 + 2]; - d3.HEX = m_data[i * 4 + 3]; - - 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 (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end())) - { - m_cur_instr->close_scopes++; - AddCode("}"); - AddCode(""); - - AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); - AddCode("{"); - m_cur_instr->open_scopes++; - } - - if (!d1.sca_opcode && !d1.vec_opcode) - { - AddCode("//nop"); - } - - switch (d1.sca_opcode) - { - case RSX_SCA_OPCODE_NOP: break; - case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break; - case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break; - case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; - case RSX_SCA_OPCODE_RSQ: SetDSTSca("inversesqrt(abs($s))"); break; - case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break; - case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break; - case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break; - case RSX_SCA_OPCODE_BRA: - { - AddCode("$if ($cond)"); - AddCode("{"); - m_cur_instr->open_scopes++; - AddCode("jump_position = $a$am;"); - AddCode("continue;"); - m_cur_instr->close_scopes++; - AddCode("}"); - } - break; - /* This triggers opengl driver lost connection error code 7 - case RSX_SCA_OPCODE_BRI: // works differently (BRI o[1].x(TR) L0;) - { - uint jump_position; - - if (is_has_BRA) - { - jump_position = GetAddr(); - } - else - { - int addr = GetAddr(); - - jump_position = 0; - for (auto pos : m_jump_lvls) - { - if (addr == pos) - break; - - ++jump_position; - } - } - - AddCode("$ifcond "); - AddCode("{"); - m_cur_instr->open_scopes++; - AddCode(fmt::Format("jump_position = %u;", jump_position)); - AddCode("continue;"); - m_cur_instr->close_scopes++; - AddCode("}"); - } - break; - */ - case RSX_SCA_OPCODE_CAL: - // works same as BRI - AddCode("$ifcond $f(); //CAL"); - break; - case RSX_SCA_OPCODE_CLI: - // works same as BRI - AddCode("$ifcond $f(); //CLI"); - break; - case RSX_SCA_OPCODE_RET: - // works like BRI but shorter (RET o[1].x(TR);) - AddCode("$ifcond return;"); - break; - case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break; - case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break; - case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break; - case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break; - case RSX_SCA_OPCODE_BRB: - // works differently (BRB o[1].x !b0, L0;) - LOG_ERROR(RSX, "Unimplemented sca_opcode BRB"); - break; - case RSX_SCA_OPCODE_CLB: break; - // works same as BRB - LOG_ERROR(RSX, "Unimplemented sca_opcode CLB"); - break; - case RSX_SCA_OPCODE_PSH: break; - // works differently (PSH o[1].x A0;) - LOG_ERROR(RSX, "Unimplemented sca_opcode PSH"); - break; - case RSX_SCA_OPCODE_POP: break; - // works differently (POP o[1].x;) - LOG_ERROR(RSX, "Unimplemented sca_opcode POP"); - break; - - default: - AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode))); - LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)); - Emu.Pause(); - break; - } - - switch (d1.vec_opcode) - { - case RSX_VEC_OPCODE_NOP: break; - case RSX_VEC_OPCODE_MOV: SetDSTVec("$0"); break; - case RSX_VEC_OPCODE_MUL: SetDSTVec("($0 * $1)"); break; - case RSX_VEC_OPCODE_ADD: SetDSTVec("($0 + $2)"); break; - case RSX_VEC_OPCODE_MAD: SetDSTVec("($0 * $1 + $2)"); break; - case RSX_VEC_OPCODE_DP3: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; - case RSX_VEC_OPCODE_DPH: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; - case RSX_VEC_OPCODE_DP4: SetDSTVec("vec4(dot($0, $1))"); break; - case RSX_VEC_OPCODE_DST: SetDSTVec("vec4(distance($0, $1))"); break; - case RSX_VEC_OPCODE_MIN: SetDSTVec("min($0, $1)"); break; - case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break; - case RSX_VEC_OPCODE_SLT: SetDSTVec("vec4(lessThan($0, $1))"); break; - case RSX_VEC_OPCODE_SGE: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; - case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $a = ivec4($0)$am;"); break; - case RSX_VEC_OPCODE_FRC: SetDSTVec("fract($0)"); break; - case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break; - case RSX_VEC_OPCODE_SEQ: SetDSTVec("vec4(equal($0, $1))"); break; - case RSX_VEC_OPCODE_SFL: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; - case RSX_VEC_OPCODE_SGT: SetDSTVec("vec4(greaterThan($0, $1))"); break; - case RSX_VEC_OPCODE_SLE: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; - case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break; - case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; - case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break; - case RSX_VEC_OPCODE_TXL: SetDSTVec("texture($t, $0.xy)"); break; - - default: - AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); - LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)); - Emu.Pause(); - break; - } - } - - if (is_has_BRA || !m_jump_lvls.empty()) - { - m_cur_instr = &m_instructions[m_instr_count - 1]; - m_cur_instr->close_scopes++; - AddCode("}"); - AddCode("break;"); - m_cur_instr->close_scopes++; - AddCode("}"); - } - - m_shader = BuildCode(); - - m_jump_lvls.clear(); - m_body.clear(); - if (m_funcs.size() > 2) - { - m_funcs.erase(m_funcs.begin() + 2, m_funcs.end()); - } + m_shader = Decompile(); } GLVertexProgram::GLVertexProgram() @@ -859,7 +268,6 @@ void GLVertexProgram::Compile() void GLVertexProgram::Delete() { - parr.params.clear(); shader.clear(); if (id) diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.h b/rpcs3/Emu/RSX/GL/GLVertexProgram.h index 70848d93bf..d9664a9ede 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.h +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.h @@ -1,83 +1,30 @@ #pragma once -#include "GLShaderParam.h" +#include "../Common/VertexProgramDecompiler.h" #include "Emu/RSX/RSXVertexProgram.h" #include "Utilities/Thread.h" -#include +#include "OpenGL.h" -struct GLVertexDecompilerThread : public ThreadBase +struct GLVertexDecompilerThread : public ThreadBase, public VertexProgramDecompiler { - struct FuncInfo + std::string &m_shader; +protected: + virtual std::string getFloatTypeName(size_t elementCount) override; + virtual std::string getFunction(FUNCTION) override; + virtual std::string compareFunction(COMPARE, const std::string&, const std::string&) override; + + virtual void insertHeader(std::stringstream &OS) override; + virtual void insertInputs(std::stringstream &OS, const std::vector &inputs) override; + virtual void insertConstants(std::stringstream &OS, const std::vector &constants) override; + virtual void insertOutputs(std::stringstream &OS, const std::vector &outputs) override; + virtual void insertMainStart(std::stringstream &OS) override; + virtual void insertMainEnd(std::stringstream &OS) override; +public: + GLVertexDecompilerThread(std::vector& data, std::string& shader, ParamArray& parr) + : ThreadBase("Vertex Shader Decompiler Thread"), VertexProgramDecompiler(data), m_shader(shader) { - u32 offset; - std::string name; - }; - - struct Instruction - { - std::vector body; - int open_scopes; - int close_scopes; - int put_close_scopes; - int do_count; - - void reset() - { - body.clear(); - put_close_scopes = open_scopes = close_scopes = do_count = 0; - } - }; - - static const size_t m_max_instr_count = 512; - Instruction m_instructions[m_max_instr_count]; - Instruction* m_cur_instr; - size_t m_instr_count; - - std::set m_jump_lvls; - std::vector m_body; - std::vector m_funcs; - - //wxString main; - std::string& m_shader; - std::vector& m_data; - GLParamArray& m_parr; - - GLVertexDecompilerThread(std::vector& data, std::string& shader, GLParamArray& parr) - : ThreadBase("Vertex Shader Decompiler Thread") - , m_data(data) - , m_shader(shader) - , m_parr(parr) - { - m_funcs.emplace_back(); - m_funcs[0].offset = 0; - m_funcs[0].name = "main"; - m_funcs.emplace_back(); - m_funcs[1].offset = 0; - m_funcs[1].name = "func0"; - //m_cur_func->body = "\tgl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n"; } - std::string GetMask(bool is_sca); - std::string GetVecMask(); - std::string GetScaMask(); - std::string GetDST(bool is_sca = false); - std::string GetSRC(const u32 n); - std::string GetFunc(); - std::string GetTex(); - std::string GetCond(); - std::string AddAddrMask(); - std::string AddAddrReg(); - u32 GetAddr(); - std::string Format(const std::string& code); - - void AddCodeCond(const std::string& dst, const std::string& src); - void AddCode(const std::string& code); - void SetDST(bool is_sca, std::string value); - void SetDSTVec(const std::string& code); - void SetDSTSca(const std::string& code); - std::string BuildFuncBody(const FuncInfo& func); - std::string BuildCode(); - - virtual void Task(); + virtual void Task() override; }; class GLVertexProgram @@ -86,7 +33,7 @@ public: GLVertexProgram(); ~GLVertexProgram(); - GLParamArray parr; + ParamArray parr; u32 id; std::string shader; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 030d9c7e45..3086d22c45 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -430,7 +430,6 @@ - diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 6f4766907f..678ef1cd18 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1345,9 +1345,6 @@ Emu\GPU\RSX\GL - - Emu\GPU\RSX\GL - Emu\GPU\RSX\GL