#include "stdafx.h" #include "GLFragmentProgram.h" void GLFragmentDecompilerThread::AddCode(std::string code, bool append_mask) { if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; const std::string mask = GetMask().c_str(); std::string cond = ""; if(!src0.exec_if_gr || !src0.exec_if_lt || !src0.exec_if_eq) { static const char f[4] = {'x', 'y', 'z', 'w'}; std::string swizzle = ""; 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(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 = std::string("if(all(" + cond + "(" + AddCond(dst.no_dest) + "." + swizzle +", vec4(0, 0, 0, 0)))) "); //ConLog.Error("cond! [eq: %d gr: %d lt: %d] (%s)", src0.exec_if_eq, src0.exec_if_gr, src0.exec_if_lt, cond); //Emu.Pause(); //return; } if(src1.scale) { switch(src1.scale) { case 1: code = "(" + code + " * 2)"; break; case 2: code = "(" + code + " * 4)"; break; case 3: code = "(" + code + " * 8)"; break; case 5: code = "(" + code + " / 2)"; break; case 6: code = "(" + code + " / 4)"; break; case 7: code = "(" + code + " / 8)"; break; default: ConLog.Error("Bad scale: %d", src1.scale); Emu.Pause(); break; } } if(dst.saturate) { code = "clamp(" + code + ", 0.0, 1.0)"; } code = cond + (dst.set_cond ? m_parr.AddParam(PARAM_NONE , "vec4", std::string(dst.fp16 ? "hc" : "rc") + std::to_string(src0.cond_reg_index)) : AddReg(dst.dest_reg, dst.fp16)) + mask + " = " + code + (append_mask ? mask : ""); main += "\t" + code + ";\n"; } std::string GLFragmentDecompilerThread::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 GLFragmentDecompilerThread::AddReg(u32 index, int fp16) { if(index >= 2 && index <= 4) { return m_parr.AddParam(PARAM_OUT, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), (fp16) ? -1 : (index - 1)); } return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)"); //return m_parr.AddParam((index >= 2 && index <= 4) ? PARAM_OUT : PARAM_NONE, "vec4", // std::string(fp16 ? "h" : "r") + std::to_string(index), (fp16 || !index) ? -1 : ((index >= 2 && index <= 4) ? (index - 1) : -1)); } bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) { return m_parr.HasParam((index >= 2 && index <= 4) ? PARAM_OUT : PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index)); } std::string GLFragmentDecompilerThread::AddCond(int fp16) { return m_parr.AddParam(PARAM_NONE , "vec4", std::string(fp16 ? "hc" : "rc") + std::to_string(src0.cond_mod_reg_index)); } std::string GLFragmentDecompilerThread::AddConst() { mem32_ptr_t data(m_addr + m_size + m_offset); m_offset += 4 * 4; u32 x = GetData(data[0]); u32 y = GetData(data[1]); u32 z = GetData(data[2]); u32 w = GetData(data[3]); return m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("fc") + std::to_string(m_size + 4 * 4), 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)); } 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", "col0", "col1", "fogc", "tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7" }; 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 { ConLog.Error("Bad src reg num: %d", dst.src_attr_reg_num); ret += m_parr.AddParam(PARAM_IN, "vec4", "unk"); Emu.Pause(); } break; } } break; case 2: //const ret += AddConst(); break; default: ConLog.Error("Bad src type %d", src.reg_type); Emu.Pause(); 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(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() { //main += wxString::Format("\tgl_FragColor = %c0;\n", m_ctrl & 0x40 ? 'r' : 'h'); main += "\t" + m_parr.AddParam(PARAM_OUT, "vec4", "ocol", 0) + " = " + (m_ctrl & 0x40 ? "r0" : "h0") + ";\n"; if(m_ctrl & 0xe) main += "\tgl_FragDepth = r1.z;\n"; std::string p = ""; for(u32 i=0; iIsAlive()) { m_decompiler_thread->Stop(); } delete m_decompiler_thread; m_decompiler_thread = nullptr; } Delete(); } void GLShaderProgram::Decompile(RSXShaderProgram& prog) { #if 0 FragmentDecompilerThread(shader, parr, addr).Entry(); #else 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 GLFragmentDecompilerThread(shader, parr, prog.addr, prog.size, prog.ctrl); m_decompiler_thread->Start(); #endif } void GLShaderProgram::Compile() { if(id) glDeleteShader(id); id = glCreateShader(GL_FRAGMENT_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 shader: %s", buf); delete[] buf; } ConLog.Write(shader.c_str()); Emu.Pause(); } //else ConLog.Write("Shader compiled successfully!"); } void GLShaderProgram::Delete() { for(u32 i=0; i