#include "stdafx.h" #include "FragmentProgram.h" void FragmentDecompilerThread::AddCode(wxString code) { if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; wxString cond = wxEmptyString; if(!src0.exec_if_gr || !src0.exec_if_lt || !src0.exec_if_eq) { if(src0.exec_if_gr) { cond = ">"; } else if(src0.exec_if_lt) { cond = "<"; } else if(src0.exec_if_eq) { cond = "="; } if(src0.exec_if_eq) { cond += "="; } else { if(src0.exec_if_gr && src0.exec_if_lt) { cond = "!="; } } } if(cond.Len()) { static const char f[4] = {'x', 'y', 'z', 'w'}; wxString swizzle = wxEmptyString; swizzle += f[src0.cond_swizzle_x]; swizzle += f[src0.cond_swizzle_y]; swizzle += f[src0.cond_swizzle_z]; swizzle += f[src0.cond_swizzle_w]; cond = wxString::Format("if(rc.%s %s 0.0) ", swizzle, cond); //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 ? AddCond(dst.fp16) : AddReg(dst.dest_reg, dst.fp16)) + GetMask() + " = " + code + GetMask(); main += "\t" + code + ";\n"; } wxString FragmentDecompilerThread::GetMask() { wxString ret = wxEmptyString; static const char dst_mask[2][4] = { {'x', 'y', 'z', 'w'}, {'r', 'g', 'b', 'a'} }; if(dst.mask_x) ret += dst_mask[dst.dest_reg == 0][0]; if(dst.mask_y) ret += dst_mask[dst.dest_reg == 0][1]; if(dst.mask_z) ret += dst_mask[dst.dest_reg == 0][2]; if(dst.mask_w) ret += dst_mask[dst.dest_reg == 0][3]; return ret.IsEmpty() || strncmp(ret, dst_mask[dst.dest_reg == 0], 4) == 0 ? wxEmptyString : ("." + ret); } wxString FragmentDecompilerThread::AddReg(u32 index, int fp16) { //if(!index) return "gl_FragColor"; return m_parr.AddParam((index || fp16) ? PARAM_NONE : PARAM_OUT, "vec4", wxString::Format((fp16 ? "h%d" : "r%d"), index), (index || fp16) ? -1 : 0); } wxString FragmentDecompilerThread::AddCond(int fp16) { return m_parr.AddParam(PARAM_NONE , "vec4", (fp16 ? "hc" : "rc"), -1); } wxString FragmentDecompilerThread::AddConst() { mem32_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("vec4", wxString::Format("fc%d", m_const_index++), wxString::Format("vec4(%f, %f, %f, %f)", (float&)x, (float&)y, (float&)z, (float&)w)); } wxString FragmentDecompilerThread::AddTex() { return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", wxString::Format("tex%d", dst.tex_num)); } template wxString FragmentDecompilerThread::GetSRC(T src) { wxString ret = wxEmptyString; bool is_color = src.reg_type == 0 || (src.reg_type == 1 && dst.src_attr_reg_num >= 1 && dst.src_attr_reg_num <= 3); switch(src.reg_type) { case 0: //tmp ret += AddReg(src.tmp_reg_index, src.fp16); break; case 1: //input { static const wxString 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 < WXSIZEOF(reg_table)) { 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_pos[4] = {'x', 'y', 'z', 'w'}; static const char f_col[4] = {'r', 'g', 'b', 'a'}; const char *f = is_color ? f_col : f_pos; wxString swizzle = wxEmptyString; swizzle += f[src.swizzle_x]; swizzle += f[src.swizzle_y]; swizzle += f[src.swizzle_z]; swizzle += f[src.swizzle_w]; if(strncmp(swizzle, f, 4) != 0) ret += "." + swizzle; if(src.abs) ret = "abs(" + ret + ")"; if(src.neg) ret = "-" + ret; return ret; } wxString FragmentDecompilerThread::BuildCode() { wxString p = wxEmptyString; for(u32 i=0; iIsAlive()) { m_decompiler_thread->Stop(); } delete m_decompiler_thread; m_decompiler_thread = nullptr; } Delete(); } void ShaderProgram::Decompile() { #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 FragmentDecompilerThread(shader, parr, addr, size); m_decompiler_thread->Start(); #endif } void ShaderProgram::Compile() { if(id) glDeleteShader(id); id = glCreateShader(GL_FRAGMENT_SHADER); const char* str = shader.c_str(); const int strlen = shader.Len(); 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); Emu.Pause(); } //else ConLog.Write("Shader compiled successfully!"); } void ShaderProgram::Delete() { for(u32 i=0; i