#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(); 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]; 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 = "if(all(" + cond + "(" + AddCond(dst.no_dest) + swizzle + ", vec4(0.0)))) "; } 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", fmt::by_value(src1.scale)); Emu.Pause(); break; } } if(dst.saturate) { code = "clamp(" + code + ", 0.0, 1.0)"; } std::string dest; if(dst.no_dest) { if(dst.set_cond) { dest = m_parr.AddParam(PARAM_NONE , "vec4", std::string(dst.fp16 ? "hc" : "rc") + std::to_string(src0.cond_reg_index)); } } else { dest = AddReg(dst.dest_reg, dst.fp16); } code = cond + (dest.length() ? dest + 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, 0.0, 0.0, 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() { std::string name = std::string("fc") + std::to_string(m_size + 4 * 4); if(m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) { return name; } 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", 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)); } 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", 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: ConLog.Error("Bad src type %d", fmt::by_value(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 += fmt::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::Wait() { if(m_decompiler_thread && m_decompiler_thread->IsAlive()) { m_decompiler_thread->Join(); } } void GLShaderProgram::Decompile(RSXShaderProgram& prog) { GLFragmentDecompilerThread decompiler(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); decompiler.Task(); } void GLShaderProgram::DecompileAsync(RSXShaderProgram& 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 GLFragmentDecompilerThread(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); m_decompiler_thread->Start(); } void GLShaderProgram::Compile() { if (m_id) glDeleteShader(m_id); m_id = glCreateShader(GL_FRAGMENT_SHADER); const char* str = m_shader.c_str(); const int strlen = m_shader.length(); glShaderSource(m_id, 1, &str, &strlen); glCompileShader(m_id); GLint compileStatus = GL_FALSE; glGetShaderiv(m_id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call if (compileStatus != GL_TRUE) // If the shader failed to compile... { GLint infoLength; glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log if (infoLength > 0) { GLsizei len; char* buf = new char[infoLength]; // Buffer to store infoLog glGetShaderInfoLog(m_id, infoLength, &len, buf); // Retrieve the shader info log into our buffer ConLog.Error("Failed to compile shader: %s", buf); // Write log to the console delete[] buf; } ConLog.Write(m_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 } } void GLShaderProgram::Delete() { for (u32 i = 0; i