diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 9125b4a43a..acc50fb558 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -3236,11 +3236,58 @@ private: } void FRES(u32 frd, u32 frb, bool rc) { - if(CPU.FPR[frb] == 0.0) CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPR[frd] = static_cast(1.0f/CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; + double res; + + if(_fpclass(CPU.FPR[frb]) >= _FPCLASS_NZ) + { + res = static_cast(1.0 / CPU.FPR[frb]); + if(FPRdouble::IsINF(res) && CPU.FPR[frb] != 0.0) + { + if(res > 0.0) + { + (u64&)res = 0x47EFFFFFE0000000ULL; + } + else + { + (u64&)res = 0xC7EFFFFFE0000000ULL; + } + } + } + else + { + u64 v = CPU.FPR[frb]; + + if(v == 0ULL) + { + v = 0x7FF0000000000000ULL; + } + else if(v == 0x8000000000000000ULL) + { + v = 0xFFF0000000000000ULL; + } + else if(FPRdouble::IsNaN(CPU.FPR[frb])) + { + v = 0x7FF8000000000000ULL; + } + else if(CPU.FPR[frb] < 0.0) + { + v = 0x8000000000000000ULL; + } + else + { + v = 0ULL; + } + + res = (double&)v; + } + + if(CPU.FPR[frb] == 0.0) + { + CPU.SetFPSCRException(FPSCR_ZX); + } + + CPU.FPR[frd] = res; + if(rc) UNK("fres.");//CPU.UpdateCR1(CPU.FPR[frd]); } void FMULS(u32 frd, u32 fra, u32 frc, bool rc) @@ -3339,7 +3386,9 @@ private: } void FCMPU(u32 crfd, u32 fra, u32 frb) { - if((CPU.FPSCR.FPRF = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb])) == 1) + int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); + + if(cmp_res == CR_SO) { if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) { @@ -3347,7 +3396,8 @@ private: } } - CPU.SetCR(crfd, CPU.FPSCR.FPRF); + CPU.FPSCR.FPRF = cmp_res; + CPU.SetCR(crfd, cmp_res); } void FRSP(u32 frd, u32 frb, bool rc) { @@ -3467,20 +3517,44 @@ private: } void FDIV(u32 frd, u32 fra, u32 frb, bool rc) { - if(FPRdouble::IsINF(CPU.FPR[fra]) == 0.0 && CPU.FPR[frb] == 0.0) + double res; + + if(FPRdouble::IsNaN(CPU.FPR[fra])) { - CPU.FPSCR.VXZDZ = 1; + res = CPU.FPR[fra]; } - else if(FPRdouble::IsINF(CPU.FPR[fra]) && FPRdouble::IsINF(CPU.FPR[frb])) + else if(FPRdouble::IsNaN(CPU.FPR[frb])) { - CPU.FPSCR.VXIDI = 1; + res = CPU.FPR[frb]; } - else if(CPU.FPR[fra] != 0.0 && CPU.FPR[frb] == 0.0) + else { - CPU.SetFPSCRException(FPSCR_ZX); + if(CPU.FPR[frb] == 0.0) + { + if(CPU.FPR[fra] == 0.0) + { + CPU.FPSCR.VXZDZ = 1; + res = FPR_NAN; + } + else + { + res = CPU.FPR[fra] / CPU.FPR[frb]; + } + + CPU.SetFPSCRException(FPSCR_ZX); + } + else if(FPRdouble::IsINF(CPU.FPR[fra]) && FPRdouble::IsINF(CPU.FPR[frb])) + { + CPU.FPSCR.VXIDI = 1; + res = FPR_NAN; + } + else + { + res = CPU.FPR[fra] / CPU.FPR[frb]; + } } - CPU.FPR[frd] = CPU.FPR[fra] / CPU.FPR[frb]; + CPU.FPR[frd] = res; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); if(rc) UNK("fdiv.");//CPU.UpdateCR1(CPU.FPR[frd]); } @@ -3509,15 +3583,31 @@ private: } void FMUL(u32 frd, u32 fra, u32 frc, bool rc) { - CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc]; - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); + if((FPRdouble::IsINF(CPU.FPR[fra]) && CPU.FPR[frc] == 0.0) || (FPRdouble::IsINF(CPU.FPR[frc]) && CPU.FPR[fra] == 0.0)) + { + CPU.SetFPSCRException(FPSCR_VXIMZ); + CPU.FPR[frd] = FPR_NAN; + CPU.FPSCR.FI = 0; + CPU.FPSCR.FR = 0; + CPU.FPSCR.FPRF = FPR_QNAN; + } + else + { + if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frc])) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + } + + CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc]; + CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); + } + if(rc) UNK("fmul.");//CPU.UpdateCR1(CPU.FPR[frd]); } void FRSQRTE(u32 frd, u32 frb, bool rc) { - //if(CPU.FPR[frb]. + UNIMPLEMENTED(); + //CPU.FPR[frd] = 1.0f / (float)sqrt(CPU.FPR[frb]); } void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { @@ -3545,14 +3635,16 @@ private: } void FCMPO(u32 crfd, u32 fra, u32 frb) { - if((CPU.FPSCR.FPRF = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb])) == 1) + int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); + + if(cmp_res == CR_SO) { if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) { CPU.SetFPSCRException(FPSCR_VXSNAN); if(!CPU.FPSCR.VE) CPU.SetFPSCRException(FPSCR_VXVC); } - else if(FPRdouble::IsQNaN(CPU.FPR[fra]) || FPRdouble::IsQNaN(CPU.FPR[frb])) + else { CPU.SetFPSCRException(FPSCR_VXVC); } @@ -3560,11 +3652,12 @@ private: CPU.FPSCR.FX = 1; } - CPU.SetCR(crfd, CPU.FPSCR.FPRF); + CPU.FPSCR.FPRF = cmp_res; + CPU.SetCR(crfd, cmp_res); } void FNEG(u32 frd, u32 frb, bool rc) { - CPU.FPR[frd] = ((u64&)CPU.FPR[frb]) ^ (1ULL << 63); + CPU.FPR[frd] = -CPU.FPR[frb]; if(rc) UNK("fneg.");//CPU.UpdateCR1(CPU.FPR[frd]); } void FMR(u32 frd, u32 frb, bool rc) @@ -3574,7 +3667,7 @@ private: } void FNABS(u32 frd, u32 frb, bool rc) { - (u64&)CPU.FPR[frd] = (u64&)CPU.FPR[frb] | 0x8000000000000000ULL; + CPU.FPR[frd] = -fabs(CPU.FPR[frb]); if(rc) UNK("fnabs.");//CPU.UpdateCR1(CPU.FPR[frd]); } void FABS(u32 frd, u32 frb, bool rc) @@ -3685,7 +3778,24 @@ private: } void FCFID(u32 frd, u32 frb, bool rc) { - CPU.FPR[frd] = (double)(u64&)CPU.FPR[frb]; + s64 bi = (s64&)CPU.FPR[frb]; + double bf = (double)bi; + s64 bfi = (s64)bf; + + if(bi == bfi) + { + CPU.SetFPSCR_FI(0); + CPU.FPSCR.FR = 0; + } + else + { + CPU.SetFPSCR_FI(1); + CPU.FPSCR.FR = abs(bfi) > abs(bi); + } + + CPU.FPR[frd] = bf; + + CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); if(rc) UNK("fcfid.");//CPU.UpdateCR1(CPU.FPR[frd]); } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e3cbffe359..54717b8fd6 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -214,7 +214,7 @@ void PPUThread::DoCode(const s32 code) bool FPRdouble::IsINF(PPCdouble d) { - return d.GetType() == FPR_INF; + return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL; } bool FPRdouble::IsNaN(PPCdouble d) @@ -224,12 +224,18 @@ bool FPRdouble::IsNaN(PPCdouble d) bool FPRdouble::IsQNaN(PPCdouble d) { - return d.GetType() == FPR_QNAN; + return + ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && + ((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL && + ((u64&)d & 0x000800000000000ULL) != 0ULL; } bool FPRdouble::IsSNaN(PPCdouble d) { - return d.GetType() == FPR_SNAN; + return + ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && + ((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL && + ((u64&)d & 0x0008000000000000ULL) == 0ULL; } int FPRdouble::Cmp(PPCdouble a, PPCdouble b) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 571565a2ff..6954c31412 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -298,11 +298,11 @@ union VSCRhdr enum FPRType { - FPR_NORM, - FPR_ZERO, - FPR_SNAN, + //FPR_NORM, + //FPR_ZERO, + //FPR_SNAN, //FPR_QNAN, - FPR_INF, + //FPR_INF, FPR_PZ = 0x2, FPR_PN = 0x4, FPR_PINF = 0x5, @@ -357,7 +357,7 @@ struct PPCdouble switch(fpc) { - case _FPCLASS_SNAN: return FPR_SNAN; + case _FPCLASS_SNAN:// return FPR_SNAN; case _FPCLASS_QNAN: return FPR_QNAN; case _FPCLASS_NINF: return FPR_NINF; case _FPCLASS_NN: return FPR_NN; diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index 86e1e87b7d..0a162f9f2c 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -136,7 +136,7 @@ void VFS::SaveLoadDevices(Array& res, bool is_load) IniEntry entries_count; entries_count.Init("count", "VFSManager"); - int count; + int count = 0; if(is_load) { count = entries_count.LoadValue(count); diff --git a/rpcs3/Emu/GS/GL/FragmentProgram.cpp b/rpcs3/Emu/GS/GL/FragmentProgram.cpp index 5ae2e41e9a..bd30fb2a45 100644 --- a/rpcs3/Emu/GS/GL/FragmentProgram.cpp +++ b/rpcs3/Emu/GS/GL/FragmentProgram.cpp @@ -5,34 +5,37 @@ void FragmentDecompilerThread::AddCode(wxString code) { if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; - wxString cond; + wxString cond = wxEmptyString; - if(src0.exec_if_gr) + if(!src0.exec_if_gr || !src0.exec_if_lt || !src0.exec_if_eq) { - 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) + if(src0.exec_if_gr) { - cond = "!="; + 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) + if(cond.Len()) { 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(); @@ -43,12 +46,12 @@ void FragmentDecompilerThread::AddCode(wxString code) { 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; + 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); @@ -57,6 +60,12 @@ void FragmentDecompilerThread::AddCode(wxString code) } } + if(dst.fp16) + { + //HACK! TODO: fp16 -> fp32 + code = "/*" + code + "*/ vec4(1.0, 1.0, 1.0, 1.0)"; + } + code = AddReg(dst.dest_reg, dst.fp16) + GetMask() + " = " + code + GetMask(); main += "\t" + code + ";\n"; @@ -66,18 +75,24 @@ wxString FragmentDecompilerThread::GetMask() { wxString ret = wxEmptyString; - if(dst.mask_x) ret += 'x'; - if(dst.mask_y) ret += 'y'; - if(dst.mask_z) ret += 'z'; - if(dst.mask_w) ret += 'w'; + static const char dst_mask[2][4] = + { + {'x', 'y', 'z', 'w'}, + {'r', 'g', 'b', 'a'} + }; - return ret.IsEmpty() || ret == "xyzw" ? wxEmptyString : ("." + ret); + 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 ? PARAM_NONE : PARAM_OUT, "vec4", + return m_parr.AddParam((index || fp16) ? PARAM_NONE : PARAM_OUT, "vec4", wxString::Format((fp16 ? "h%d" : "r%d"), index), (index || fp16) ? -1 : 0); } @@ -103,6 +118,8 @@ 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 @@ -148,14 +165,17 @@ template wxString FragmentDecompilerThread::GetSRC(T src) break; } - static const char f[4] = {'x', 'y', 'z', 'w'}; + 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(swizzle != "xyzw") ret += "." + swizzle; + if(strncmp(swizzle, f, 4) != 0) ret += "." + swizzle; if(src.abs) ret = "abs(" + ret + ")"; if(src.neg) ret = "-" + ret; @@ -280,7 +300,7 @@ void FragmentDecompilerThread::Task() } ShaderProgram::ShaderProgram() - : m_decompiler_thread(NULL) + : m_decompiler_thread(nullptr) , id(0) { } diff --git a/rpcs3/Emu/GS/GL/FragmentProgram.h b/rpcs3/Emu/GS/GL/FragmentProgram.h index 09955cbc95..54a0b6b784 100644 --- a/rpcs3/Emu/GS/GL/FragmentProgram.h +++ b/rpcs3/Emu/GS/GL/FragmentProgram.h @@ -41,7 +41,7 @@ struct FragmentDecompilerThread : public ThreadBase u32 swizzle_z : 2; u32 swizzle_w : 2; u32 neg : 1; - u32 exec_if_le : 1; + u32 exec_if_lt : 1; u32 exec_if_eq : 1; u32 exec_if_gr : 1; u32 cond_swizzle_x : 2; diff --git a/rpcs3/Emu/GS/GL/GLBuffers.cpp b/rpcs3/Emu/GS/GL/GLBuffers.cpp index 8d8e96957b..ce788fdd23 100644 --- a/rpcs3/Emu/GS/GL/GLBuffers.cpp +++ b/rpcs3/Emu/GS/GL/GLBuffers.cpp @@ -36,6 +36,7 @@ void GLBufferObject::Delete() void GLBufferObject::Bind(u32 type, u32 num) { + assert(num < m_id.GetCount()); glBindBuffer(type, m_id[num]); } @@ -105,10 +106,16 @@ void GLvao::Bind() const glBindVertexArray(m_id); } +void GLvao::Unbind() +{ + glBindVertexArray(0); +} + void GLvao::Delete() { if(!IsCreated()) return; + Unbind(); glDeleteVertexArrays(1, &m_id); m_id = 0; } diff --git a/rpcs3/Emu/GS/GL/GLBuffers.h b/rpcs3/Emu/GS/GL/GLBuffers.h index e42a7b4078..946184067e 100644 --- a/rpcs3/Emu/GS/GL/GLBuffers.h +++ b/rpcs3/Emu/GS/GL/GLBuffers.h @@ -43,6 +43,7 @@ public: void Create(); void Bind() const; + static void Unbind(); void Delete(); bool IsCreated() const; }; \ No newline at end of file diff --git a/rpcs3/Emu/GS/GL/GLGSRender.cpp b/rpcs3/Emu/GS/GL/GLGSRender.cpp index 686f7f099f..d6adabd82e 100644 --- a/rpcs3/Emu/GS/GL/GLGSRender.cpp +++ b/rpcs3/Emu/GS/GL/GLGSRender.cpp @@ -1,8 +1,9 @@ #include "stdafx.h" #include "GLGSRender.h" #include "Emu/Cell/PPCInstrTable.h" + #define CMD_DEBUG 0 -#define DUMP_VERTEX_DATA 0 +#define DUMP_VERTEX_DATA 1 #if CMD_DEBUG #define CMD_LOG ConLog.Write @@ -12,9 +13,8 @@ gcmBuffer gcmBuffers[2]; -void checkForGlError(const char* situation) +void printGlError(GLenum err, const char* situation) { - GLenum err = glGetError(); if(err != GL_NO_ERROR) { ConLog.Error("%s: opengl error 0x%04x", situation, err); @@ -22,6 +22,11 @@ void checkForGlError(const char* situation) } } +void checkForGlError(const char* situation) +{ + printGlError(glGetError(), situation); +} + #if 0 #define checkForGlError(x) /*x*/ #endif @@ -168,7 +173,15 @@ void GLRSXThread::Task() } } - if(draw) p.m_frame->Flip(); + if(draw) + { + p.m_frame->Flip(); + if(p.m_flip_handler) + { + p.m_flip_handler.Handle(1, 0, 0); + p.m_flip_handler.Branch(false); + } + } p.m_flip_status = 0; if(SemaphorePostAndWait(p.m_sem_flip)) continue; @@ -279,7 +292,7 @@ void GLGSRender::Close() } if(m_frame->IsShown()) m_frame->Hide(); - m_ctrl = NULL; + m_ctrl = nullptr; } void GLGSRender::EnableVertexData(bool indexed_draw) @@ -425,6 +438,7 @@ void GLGSRender::DisableVertexData() m_vertex_data[i].data.Clear(); glDisableVertexAttribArray(i); } + m_vao.Unbind(); } void GLGSRender::LoadVertexData(u32 first, u32 count) @@ -509,7 +523,7 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 c index, offset, location, cubemap, dimension, format, mipmap); u32 tex_addr = GetAddress(offset, location); - ConLog.Warning("texture addr = 0x%x", tex_addr); + //ConLog.Warning("texture addr = 0x%x", tex_addr); tex.SetOffset(tex_addr); tex.SetFormat(cubemap, dimension, format, mipmap); } @@ -1141,6 +1155,28 @@ void GLGSRender::DoCmd(const u32 fcmd, const u32 cmd, mem32_t& args, const u32 c case NV4097_SET_SCULL_CONTROL: break; + case NV4097_GET_REPORT: + { + u32 a0 = args[0]; + u8 type = a0 >> 24; + u32 offset = a0 & 0xffffff; + + u64 data; + switch(type) + { + case 1: + data = std::chrono::steady_clock::now().time_since_epoch().count(); + break; + + default: + ConLog.Error("NV4097_GET_REPORT: bad type %d", type); + break; + } + + Memory.Write64(m_localAddress + offset, data); + } + break; + default: { wxString log = GetMethodName(cmd); @@ -1293,8 +1329,9 @@ void GLGSRender::ExecCMD() GLTexture& tex = m_frame->GetTexture(i); if(!tex.IsEnabled()) continue; - glActiveTexture(GL_TEXTURE0_ARB + i); + glActiveTexture(GL_TEXTURE0 + i); checkForGlError("glActiveTexture"); + tex.Create(); tex.Bind(); checkForGlError("tex.Bind"); m_program.SetTex(i); @@ -1342,6 +1379,7 @@ void GLGSRender::ExecCMD() EnableVertexData(); InitVertexData(); m_vao.Bind(); + glDrawArrays(m_draw_mode, 0, m_draw_array_count); checkForGlError("glDrawArrays"); DisableVertexData(); diff --git a/rpcs3/Emu/GS/GL/GLGSRender.h b/rpcs3/Emu/GS/GL/GLGSRender.h index 22def2cbd4..1736ea74f2 100644 --- a/rpcs3/Emu/GS/GL/GLGSRender.h +++ b/rpcs3/Emu/GS/GL/GLGSRender.h @@ -10,6 +10,7 @@ #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "gl.lib") +void printGlError(GLenum err, const char* situation); void checkForGlError(const char* situation); class GLTexture @@ -40,6 +41,11 @@ public: void Create() { + if(m_id) + { + Delete(); + } + if(!m_id) { glGenTextures(1, &m_id); @@ -83,24 +89,27 @@ public: void Init() { Bind(); - ConLog.Warning("texture addr = 0x%x, width = %d, height = %d", m_offset, m_width, m_height); + //ConLog.Warning("texture addr = 0x%x, width = %d, height = %d", m_offset, m_width, m_height); //TODO: safe init checkForGlError("GLTexture::Init() -> glBindTexture"); switch(m_format & ~(0x20 | 0x40)) { case 0x81: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RED, GL_UNSIGNED_BYTE, Memory.GetMemFromAddr(m_offset)); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_BLUE, GL_UNSIGNED_BYTE, Memory.GetMemFromAddr(m_offset)); checkForGlError("GLTexture::Init() -> glTexImage2D"); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_BLUE); + checkForGlError("GLTexture::Init() -> glTexParameteri"); break; case 0x85: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, Memory.GetMemFromAddr(m_offset)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, Memory.GetMemFromAddr(m_offset)); checkForGlError("GLTexture::Init() -> glTexImage2D"); break; @@ -112,13 +121,31 @@ public: void Save(const wxString& name) { - if(!m_id || !m_offset) return; + if(!m_id || !m_offset || !m_width || !m_height) return; u32* alldata = new u32[m_width * m_height]; Bind(); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, alldata); + switch(m_format & ~(0x20 | 0x40)) + { + case 0x81: + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, alldata); + break; + + case 0x85: + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, alldata); + break; + + default: + delete[] alldata; + return; + } + + { + wxFile f(name + ".raw", wxFile::write); + f.Write(alldata, m_width * m_height * 4); + } u8* data = new u8[m_width * m_height * 3]; u8* alpha = new u8[m_width * m_height]; @@ -164,6 +191,14 @@ public: glBindTexture(GL_TEXTURE_2D, 0); } + void Delete() + { + if(m_id) + { + glDeleteTextures(1, &m_id); + m_id = 0; + } + } void Enable(bool enable) { m_enabled = enable; } bool IsEnabled() const { return m_enabled; } }; diff --git a/rpcs3/Emu/GS/GL/GLProcTable.tbl b/rpcs3/Emu/GS/GL/GLProcTable.tbl index 90a8ac7b65..9d76816541 100644 --- a/rpcs3/Emu/GS/GL/GLProcTable.tbl +++ b/rpcs3/Emu/GS/GL/GLProcTable.tbl @@ -40,6 +40,9 @@ OPENGL_PROC(PFNGLDEPTHRANGEFPROC, DepthRangef); OPENGL_PROC(PFNGLUNIFORM1IPROC, Uniform1i); OPENGL_PROC(PFNGLUNIFORM1FPROC, Uniform1f); OPENGL_PROC(PFNGLUNIFORM4FPROC, Uniform4f); +OPENGL_PROC(PFNGLPROGRAMUNIFORM1IPROC, ProgramUniform1i); +OPENGL_PROC(PFNGLPROGRAMUNIFORM1FPROC, ProgramUniform1f); +OPENGL_PROC(PFNGLPROGRAMUNIFORM4FPROC, ProgramUniform4f); OPENGL_PROC(PFNGLUNIFORMMATRIX4FVPROC, UniformMatrix4fv); OPENGL_PROC(PFNGLUSEPROGRAMPROC, UseProgram); OPENGL_PROC2(PFNWGLSWAPINTERVALEXTPROC, SwapInterval, wglSwapIntervalEXT); diff --git a/rpcs3/Emu/GS/GL/Program.cpp b/rpcs3/Emu/GS/GL/Program.cpp index 9d74358cc0..530031abcd 100644 --- a/rpcs3/Emu/GS/GL/Program.cpp +++ b/rpcs3/Emu/GS/GL/Program.cpp @@ -89,8 +89,12 @@ void Program::SetTex(u32 index) { int loc = GetLocation(wxString::Format("tex%d", index)); checkForGlError(wxString::Format("GetLocation(tex%d)", index)); - glUniform1i(loc, index); - checkForGlError(wxString::Format("SetTex(%d - %d)", index, loc)); + glProgramUniform1i(id, loc, index); + GLenum err = glGetError(); + if(err != 0x502) + { + printGlError(err, wxString::Format("SetTex(%d - %d - %d)", id, index, loc)); + } } void Program::Delete() diff --git a/rpcs3/Emu/GS/GL/VertexProgram.cpp b/rpcs3/Emu/GS/GL/VertexProgram.cpp index 7a9bcfcfb4..a5048f61ea 100644 --- a/rpcs3/Emu/GS/GL/VertexProgram.cpp +++ b/rpcs3/Emu/GS/GL/VertexProgram.cpp @@ -181,7 +181,14 @@ void VertexDecompilerThread::AddCode(bool is_sca, wxString code, bool src_mask) cond = wxString::Format("if(tmp%d.x %s 0) ", d0.dst_tmp, cond); } - code = cond + GetDST(is_sca) + GetMask(is_sca) + " = " + (src_mask ? code + GetMask(is_sca) : code); + wxString value = src_mask ? code + GetMask(is_sca) : code; + + if(d0.staturate) + { + value = "clamp(" + value + ", 0.0, 1.0)"; + } + + code = cond + GetDST(is_sca) + GetMask(is_sca) + " = " + value; main += "\t" + code + ";\n"; } @@ -209,7 +216,7 @@ wxString VertexDecompilerThread::BuildCode() "#version 330\n" "\n" "%s\n" - "void main()\n{\n%s}\n"; + "void main()\n{\n\tgl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n%s}\n"; return wxString::Format(prot, p, main); } @@ -294,6 +301,7 @@ void VertexDecompilerThread::Task() } m_shader = BuildCode(); + main = wxEmptyString; } diff --git a/rpcs3/Emu/GS/GSRender.h b/rpcs3/Emu/GS/GSRender.h index 86c05ece7b..aa08b9cdb7 100644 --- a/rpcs3/Emu/GS/GSRender.h +++ b/rpcs3/Emu/GS/GSRender.h @@ -1,5 +1,6 @@ #pragma once #include "Emu/GS/GCM.h" +#include "Emu/SysCalls/Callback.h" enum Method { @@ -48,6 +49,7 @@ struct GSRender int m_flip_status; int m_flip_mode; volatile bool m_draw; + Callback m_flip_handler; GSRender(); diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index 4d456c19a5..62c2857016 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -13,6 +13,31 @@ Callback::Callback(u32 slot, u64 addr) { } +u32 Callback::GetSlot() const +{ + return m_slot; +} + +u64 Callback::GetAddr() const +{ + return m_addr; +} + +void Callback::SetSlot(u32 slot) +{ + m_slot = slot; +} + +void Callback::SetAddr(u64 addr) +{ + m_addr = addr; +} + +bool Callback::HasData() const +{ + return m_has_data; +} + void Callback::Handle(u64 _a1, u64 _a2, u64 _a3) { a1 = _a1; @@ -21,13 +46,13 @@ void Callback::Handle(u64 _a1, u64 _a2, u64 _a3) m_has_data = true; } -void Callback::Branch() +void Callback::Branch(bool wait) { m_has_data = false; PPCThread& new_thread = Emu.GetCPU().AddThread(PPC_THREAD_PPU); - new_thread.SetPc(m_addr); + new_thread.SetEntry(m_addr); new_thread.SetPrio(1001); new_thread.stack_size = 0x10000; new_thread.SetName("Callback"); @@ -40,7 +65,13 @@ void Callback::Branch() new_thread.Exec(); - GetCurrentPPCThread()->Wait(new_thread); + if(wait) + GetCurrentPPCThread()->Wait(new_thread); +} + +Callback::operator bool() const +{ + return GetAddr() != 0; } Callback2::Callback2(u32 slot, u64 addr, u64 userdata) : Callback(slot, addr) diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h index fe720ab18e..49395f3527 100644 --- a/rpcs3/Emu/SysCalls/Callback.h +++ b/rpcs3/Emu/SysCalls/Callback.h @@ -1,19 +1,29 @@ #pragma once -struct Callback +class Callback { +protected: u64 m_addr; u32 m_slot; + bool m_has_data; + +public: u64 a1; u64 a2; u64 a3; - bool m_has_data; + u32 GetSlot() const; + u64 GetAddr() const; + void SetSlot(u32 slot); + void SetAddr(u64 addr); + bool HasData() const; - Callback(u32 slot, u64 addr); - void Handle(u64 a1, u64 a2, u64 a3); - void Branch(); + Callback(u32 slot = 0, u64 addr = 0); + void Handle(u64 a1 = 0, u64 a2 = 0, u64 a3 = 0); + void Branch(bool wait); + + operator bool() const; }; struct Callback2 : public Callback @@ -46,7 +56,7 @@ struct Callbacks { for(u32 i=0; i