From 1ef4ccc5a1b222cc18c7710a00436d0794442c24 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 02:04:04 -0800 Subject: [PATCH 01/18] Log an error when vfpu swizzle is used badly. --- Core/MIPS/MIPSIntVFPU.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 4313f0101ba4..8466b5250cb4 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -113,7 +113,10 @@ void ApplyPrefixST(float *v, u32 data, VectorSize size) // Prefix may say "z, z, z, z" but if this is a pair, we force to x. // TODO: But some ops seem to use const 0 instead? if (regnum >= n) + { + ERROR_LOG(CPU, "Invalid VFPU swizzle: %08x / %d", data, size); regnum = 0; + } v[i] = origV[regnum]; if (abs) @@ -1185,7 +1188,11 @@ namespace MIPSInt ReadVector(s, sz, vs); ApplySwizzleS(s, sz); float scale = V(vt); - ApplySwizzleT(&scale, V_Single); + if (currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX] != 0xE4) + { + WARN_LOG(CPU, "Broken T prefix used with VScl: %08x / %08x", currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX], op); + ApplySwizzleT(&scale, V_Single); + } int n = GetNumVectorElements(sz); for (int i = 0; i < n; i++) { From 35537b3c97c09e5b48bd8da9bfe9e2aa544b38f7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 03:15:22 -0800 Subject: [PATCH 02/18] Add TEMP0 fpu regs to x86 like in armjit. But... will probably need more and the ability to swap into memory if we want to deal with prefixes. --- Core/MIPS/x86/CompVFPU.cpp | 53 +++++++++++++++++++++++++++++++---- Core/MIPS/x86/RegCacheFPU.cpp | 36 ++++++++++++++++++++++-- Core/MIPS/x86/RegCacheFPU.h | 15 ++++++++-- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 2ea60ad84417..dbc473300849 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -144,6 +144,24 @@ void Jit::ApplyPrefixD(const u8 *vregs, u32 prefix, VectorSize sz, bool onlyWrit } } +// Vector regs can overlap in all sorts of swizzled ways. +bool DestRegOverlaps(int dreg, int sn, u8 sregs[], int tn, u8 tregs[]) +{ + for (int i = 0; i < sn; ++i) + { + if (sregs[i] == dreg) + return true; + } + for (int i = 0; i < tn; ++i) + { + if (tregs[i] == dreg) + return true; + } + + // Hurray, no overlap, we can write directly. + return false; +} + static u32 GC_ALIGNED16(ssLoadStoreTemp[1]); void Jit::Comp_SV(u32 op) { @@ -394,16 +412,39 @@ void Jit::Comp_VecDo3(u32 op) { } int n = GetNumVectorElements(sz); - // We need at least n temporaries... - if (n > 2) - fpr.Flush(); + + X64Reg tempxregs[4]; + for (int i = 0; i < n; ++i) + { + if (DestRegOverlaps(dregs[i], n, sregs, n, tregs)) + { + // On 32-bit we only have 6 xregs for mips regs, use XMM0/XMM1 if possible. + if (i < 2) + tempxregs[i] = (X64Reg) (XMM0 + i); + else + { + fpr.BindToRegister(TEMP0 + i, false, true); + fpr.SpillLock(TEMP0 + i); + tempxregs[i] = fpr.RX(TEMP0 + i); + } + } + else + { + fpr.MapRegV(dregs[i], MAP_NOINIT | MAP_DIRTY); + fpr.SpillLockV(dregs[i]); + tempxregs[i] = fpr.VX(dregs[i]); + } + } for (int i = 0; i < n; ++i) - MOVSS((X64Reg) (XMM0 + i), fpr.V(sregs[i])); + MOVSS(tempxregs[i], fpr.V(sregs[i])); for (int i = 0; i < n; ++i) - (this->*xmmop)((X64Reg) (XMM0 + i), fpr.V(tregs[i])); + (this->*xmmop)(tempxregs[i], fpr.V(tregs[i])); for (int i = 0; i < n; ++i) - MOVSS(fpr.V(dregs[i]), (X64Reg) (XMM0 + i)); + { + if (!fpr.R(dregs[i]).IsSimpleReg(tempxregs[i])) + MOVSS(fpr.V(dregs[i]), tempxregs[i]); + } fpr.ReleaseSpillLocks(); diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index 9c2cb9c837a9..f2356a6d5762 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -97,7 +97,9 @@ void FPURegCache::BindToRegister(const int i, bool doLoad, bool makeDirty) { if (!regs[i].location.IsImm() && (regs[i].location.offset & 0x3)) { PanicAlert("WARNING - misaligned fp register location %i", i); } - emit->MOVSS(xr, regs[i].location); + if (i < TEMP0) { + emit->MOVSS(xr, regs[i].location); + } } regs[i].location = newloc; regs[i].away = true; @@ -124,8 +126,24 @@ void FPURegCache::StoreFromRegister(int i) { } } +void FPURegCache::DiscardR(int i) +{ + _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "FPU can't handle imm yet."); + if (regs[i].away) { + X64Reg xr = regs[i].location.GetSimpleReg(); + _assert_msg_(DYNA_REC, xr < NUM_X_FPREGS, "DiscardR: MipsReg had bad X64Reg"); + // Note that we DO NOT write it back here. That's the whole point of Discard. + xregs[xr].dirty = false; + xregs[xr].mipsReg = -1; + regs[i].location = GetDefaultLocation(i); + regs[i].away = false; + } else { + // _assert_msg_(DYNA_REC,0,"already stored"); + } +} + void FPURegCache::Flush() { - for (int i = 0; i < NUM_MIPS_FPRS; i++) { + for (int i = 0; i < TEMP0; i++) { if (regs[i].locked) { PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); } @@ -141,6 +159,9 @@ void FPURegCache::Flush() { } } } + for (int i = TEMP0; i < TEMP0 + NUM_TEMPS; ++i) { + DiscardR(i); + } } OpArg FPURegCache::GetDefaultLocation(int reg) const { @@ -189,6 +210,15 @@ X64Reg FPURegCache::GetFreeXReg() { } //Okay, not found :( Force grab one + // Maybe a temp reg? + for (int i = TEMP0; i < NUM_MIPS_FPRS; ++i) { + if (regs[i].away && !regs[i].locked) { + X64Reg xr = regs[i].location.GetSimpleReg(); + DiscardR(i); + return xr; + } + } + //TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; @@ -203,7 +233,7 @@ X64Reg FPURegCache::GetFreeXReg() { return (X64Reg) -1; } -void FPURegCache::FlushR(X64Reg reg) { +void FPURegCache::FlushX(X64Reg reg) { if (reg >= NUM_X_FPREGS) PanicAlert("Flushing non existent reg"); if (xregs[reg].mipsReg != -1) { diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index cb4db210df2d..804d367ab03c 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -28,7 +28,14 @@ using namespace Gen; // GPRs are numbered 0 to 31 // VFPU regs are numbered 32 to 160. -#define NUM_MIPS_FPRS (32 + 128) +enum { + NUM_TEMPS = 4, + TEMP0 = 32 + 128, + TEMP1 = TEMP0 + 1, + TEMP2 = TEMP0 + 2, + TEMP3 = TEMP0 + 3, + NUM_MIPS_FPRS = 32 + 128 + NUM_TEMPS, +}; #ifdef _M_X64 #define NUM_X_FPREGS 16 @@ -68,6 +75,7 @@ class FPURegCache StoreFromRegister(preg + 32); } OpArg GetDefaultLocation(int reg) const; + void DiscardR(int preg); void SetEmitter(XEmitter *emitter) {emit = emitter;} @@ -100,6 +108,9 @@ class FPURegCache void MapRegV(int vreg, int flags); void MapRegsV(int vec, VectorSize vsz, int flags); void MapRegsV(const u8 *v, VectorSize vsz, int flags); + void SpillLockV(int vreg) { + SpillLock(vreg + 32); + } void SpillLockV(const u8 *v, VectorSize vsz); void SpillLockV(int vec, VectorSize vsz); @@ -107,7 +118,7 @@ class FPURegCache private: X64Reg GetFreeXReg(); - void FlushR(X64Reg reg); + void FlushX(X64Reg reg); const int *GetAllocationOrder(int &count); MIPSCachedFPReg regs[NUM_MIPS_FPRS]; From 0d5da967eb76ff75f78172c3acb45328f87feec3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 03:27:48 -0800 Subject: [PATCH 03/18] Enable VDot and Vec3 in x86 jit. --- Core/MIPS/x86/CompVFPU.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index dbc473300849..c1687ed85a3b 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -310,7 +310,7 @@ void Jit::Comp_SVQ(u32 op) } void Jit::Comp_VDot(u32 op) { - DISABLE; + CONDITIONAL_DISABLE; // WARNING: No prefix support! if (js.MayHavePrefix()) { @@ -357,7 +357,7 @@ void Jit::Comp_VDot(u32 op) { } void Jit::Comp_VecDo3(u32 op) { - DISABLE; + CONDITIONAL_DISABLE; // WARNING: No prefix support! if (js.MayHavePrefix()) From 0bd382c51803a18a98cad5c2e3947255d1647c07 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 10:18:13 -0800 Subject: [PATCH 04/18] Discard temp regs right away, some helper funcs. --- Core/MIPS/x86/RegCacheFPU.cpp | 18 +++++++----------- Core/MIPS/x86/RegCacheFPU.h | 10 ++++++++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index f2356a6d5762..fa637f7fb59f 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -82,6 +82,8 @@ void FPURegCache::MapRegsV(const u8 *v, VectorSize sz, int flags) { void FPURegCache::ReleaseSpillLocks() { for (int i = 0; i < NUM_MIPS_FPRS; i++) regs[i].locked = false; + for (int i = TEMP0; i < TEMP0 + NUM_TEMPS; ++i) + DiscardR(i); } void FPURegCache::BindToRegister(const int i, bool doLoad, bool makeDirty) { @@ -126,8 +128,7 @@ void FPURegCache::StoreFromRegister(int i) { } } -void FPURegCache::DiscardR(int i) -{ +void FPURegCache::DiscardR(int i) { _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "FPU can't handle imm yet."); if (regs[i].away) { X64Reg xr = regs[i].location.GetSimpleReg(); @@ -142,6 +143,10 @@ void FPURegCache::DiscardR(int i) } } +bool FPURegCache::IsTemp(X64Reg xr) { + return xregs[xr].mipsReg >= TEMP0; +} + void FPURegCache::Flush() { for (int i = 0; i < TEMP0; i++) { if (regs[i].locked) { @@ -210,15 +215,6 @@ X64Reg FPURegCache::GetFreeXReg() { } //Okay, not found :( Force grab one - // Maybe a temp reg? - for (int i = TEMP0; i < NUM_MIPS_FPRS; ++i) { - if (regs[i].away && !regs[i].locked) { - X64Reg xr = regs[i].location.GetSimpleReg(); - DiscardR(i); - return xr; - } - } - //TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index 804d367ab03c..429c25b1486d 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -26,7 +26,8 @@ using namespace Gen; // GPRs are numbered 0 to 31 -// VFPU regs are numbered 32 to 160. +// VFPU regs are numbered 32 to 159. +// Then we have some temp regs for VFPU handling from 160 to 167. enum { NUM_TEMPS = 4, @@ -34,6 +35,7 @@ enum { TEMP1 = TEMP0 + 1, TEMP2 = TEMP0 + 2, TEMP3 = TEMP0 + 3, + TEMP4 = TEMP0 + 4, NUM_MIPS_FPRS = 32 + 128 + NUM_TEMPS, }; @@ -75,7 +77,11 @@ class FPURegCache StoreFromRegister(preg + 32); } OpArg GetDefaultLocation(int reg) const; - void DiscardR(int preg); + void DiscardR(int freg); + void DiscardV(int vreg) { + DiscardR(vreg + 32); + } + bool IsTemp(X64Reg xreg); void SetEmitter(XEmitter *emitter) {emit = emitter;} From 1c4c5e718b03534be7e8ad11db43cad218fc7103 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 10:19:05 -0800 Subject: [PATCH 05/18] Optimize VDot and VecDo3 to avoid temporaries. --- Core/MIPS/x86/CompVFPU.cpp | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index c1687ed85a3b..6338099eb662 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -145,11 +145,12 @@ void Jit::ApplyPrefixD(const u8 *vregs, u32 prefix, VectorSize sz, bool onlyWrit } // Vector regs can overlap in all sorts of swizzled ways. -bool DestRegOverlaps(int dreg, int sn, u8 sregs[], int tn, u8 tregs[]) +// This does allow a single overlap in sregs[i]. +bool DestRegOverlaps(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) { for (int i = 0; i < sn; ++i) { - if (sregs[i] == dreg) + if (sregs[i] == dreg && i != di) return true; } for (int i = 0; i < tn; ++i) @@ -332,25 +333,34 @@ void Jit::Comp_VDot(u32 op) { // TODO: applyprefixST here somehow (shuffle, etc...) - MOVSS(XMM0, fpr.V(sregs[0])); - MULSS(XMM0, fpr.V(tregs[0])); - int n = GetNumVectorElements(sz); + X64Reg tempxreg = XMM0; + if (!DestRegOverlaps(dregs[0], 0, n, sregs, n, tregs)) + { + fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + tempxreg = fpr.VX(dregs[0]); + } + + if (!fpr.V(sregs[0]).IsSimpleReg(tempxreg)) + MOVSS(tempxreg, fpr.V(sregs[0])); + MULSS(tempxreg, fpr.V(tregs[0])); + for (int i = 1; i < n; i++) { // sum += s[i]*t[i]; MOVSS(XMM1, fpr.V(sregs[i])); MULSS(XMM1, fpr.V(tregs[i])); - ADDSS(XMM0, R(XMM1)); + ADDSS(tempxreg, R(XMM1)); } - fpr.ReleaseSpillLocks(); - fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + if (!fpr.V(dregs[0]).IsSimpleReg(tempxreg)) + { + fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); + MOVSS(fpr.V(dregs[0]), XMM0); + } // TODO: applyprefixD here somehow (write mask etc..) - MOVSS(fpr.V(vd), XMM0); - fpr.ReleaseSpillLocks(); js.EatPrefix(); @@ -416,7 +426,7 @@ void Jit::Comp_VecDo3(u32 op) { X64Reg tempxregs[4]; for (int i = 0; i < n; ++i) { - if (DestRegOverlaps(dregs[i], n, sregs, n, tregs)) + if (DestRegOverlaps(dregs[i], i, n, sregs, n, tregs)) { // On 32-bit we only have 6 xregs for mips regs, use XMM0/XMM1 if possible. if (i < 2) @@ -430,19 +440,22 @@ void Jit::Comp_VecDo3(u32 op) { } else { - fpr.MapRegV(dregs[i], MAP_NOINIT | MAP_DIRTY); + fpr.MapRegV(dregs[i], (dregs[i] == sregs[i] ? 0 : MAP_NOINIT) | MAP_DIRTY); fpr.SpillLockV(dregs[i]); tempxregs[i] = fpr.VX(dregs[i]); } } for (int i = 0; i < n; ++i) - MOVSS(tempxregs[i], fpr.V(sregs[i])); + { + if (!fpr.V(sregs[i]).IsSimpleReg(tempxregs[i])) + MOVSS(tempxregs[i], fpr.V(sregs[i])); + } for (int i = 0; i < n; ++i) (this->*xmmop)(tempxregs[i], fpr.V(tregs[i])); for (int i = 0; i < n; ++i) { - if (!fpr.R(dregs[i]).IsSimpleReg(tempxregs[i])) + if (!fpr.V(dregs[i]).IsSimpleReg(tempxregs[i])) MOVSS(fpr.V(dregs[i]), tempxregs[i]); } From b27701ac7d19d4672946e793ffe7ab15fb3c6921 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 10:37:42 -0800 Subject: [PATCH 06/18] Fix VDot returning -0.0 in x86 jit. --- Core/MIPS/x86/CompVFPU.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 6338099eb662..958f6baf3763 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -49,7 +49,7 @@ namespace MIPSComp static const float one = 1.0f; static const float minus_one = -1.0f; -static const float zero = -1.0f; +static const float zero = 0.0f; const u32 GC_ALIGNED16( noSignMask[4] ) = {0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}; const u32 GC_ALIGNED16( signBitLower[4] ) = {0x80000000, 0, 0, 0}; @@ -341,9 +341,10 @@ void Jit::Comp_VDot(u32 op) { tempxreg = fpr.VX(dregs[0]); } - if (!fpr.V(sregs[0]).IsSimpleReg(tempxreg)) - MOVSS(tempxreg, fpr.V(sregs[0])); - MULSS(tempxreg, fpr.V(tregs[0])); + MOVSS(tempxreg, M((void *) &zero)); + MOVSS(XMM1, fpr.V(sregs[0])); + MULSS(XMM1, fpr.V(tregs[0])); + ADDSS(tempxreg, R(XMM1)); for (int i = 1; i < n; i++) { From 49e04609a89a3c045e2c5911cceb4b52ddf7c0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Sun, 17 Feb 2013 00:37:42 +0100 Subject: [PATCH 07/18] Remove fast interpreter option --- Qt/EmuThread.cpp | 2 +- Qt/mainwindow.cpp | 23 ++++++----------------- Qt/mainwindow.h | 2 -- Qt/mainwindow.ui | 9 --------- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/Qt/EmuThread.cpp b/Qt/EmuThread.cpp index 3c41af03598b..065e5c770769 100644 --- a/Qt/EmuThread.cpp +++ b/Qt/EmuThread.cpp @@ -185,7 +185,7 @@ void EmuThread::run() coreParameter.fileToStart = fileToStart.toStdString(); coreParameter.enableSound = true; coreParameter.gpuCore = GPU_GLES; - coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore; + coreParameter.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; coreParameter.enableDebugging = true; coreParameter.printfEmuLog = false; coreParameter.headLess = false; diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index af4cf7776a51..8f8efc22690b 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -109,15 +109,11 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co gfxLog = true; break; case 'j': - g_Config.iCpuCore = CPU_JIT; - g_Config.bSaveSettings = false; - break; - case 'f': - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = true; g_Config.bSaveSettings = false; break; case 'i': - g_Config.iCpuCore = CPU_INTERPRETER; + g_Config.bJit = false; g_Config.bSaveSettings = false; break; case 'l': @@ -231,9 +227,8 @@ void MainWindow::UpdateMenus() { ui->action_OptionsDisplayRawFramebuffer->setChecked(g_Config.bDisplayFramebuffer); ui->action_OptionsIgnoreIllegalReadsWrites->setChecked(g_Config.bIgnoreBadMemAccess); - ui->action_CPUInterpreter->setChecked(g_Config.iCpuCore == CPU_INTERPRETER); - ui->action_CPUFastInterpreter->setChecked(g_Config.iCpuCore == CPU_FASTINTERPRETER); - ui->action_CPUDynarec->setChecked(g_Config.iCpuCore == CPU_JIT); + ui->action_CPUInterpreter->setChecked(!g_Config.bJit); + ui->action_CPUDynarec->setChecked(g_Config.bJit); ui->action_OptionsBufferedRendering->setChecked(g_Config.bBufferedRendering); ui->action_OptionsShowDebugStatistics->setChecked(g_Config.bShowDebugStats); ui->action_OptionsWireframe->setChecked(g_Config.bDrawWireframe); @@ -518,19 +513,13 @@ void MainWindow::on_action_FileExit_triggered() void MainWindow::on_action_CPUDynarec_triggered() { - g_Config.iCpuCore = CPU_JIT; + g_Config.bJit = true; UpdateMenus(); } void MainWindow::on_action_CPUInterpreter_triggered() { - g_Config.iCpuCore = CPU_INTERPRETER; - UpdateMenus(); -} - -void MainWindow::on_action_CPUFastInterpreter_triggered() -{ - g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bJit = false; UpdateMenus(); } diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 14a1b8af7575..013bb54e1be5 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -81,8 +81,6 @@ private slots: void on_action_CPUInterpreter_triggered(); - void on_action_CPUFastInterpreter_triggered(); - void on_action_DebugLoadMapFile_triggered(); void on_action_DebugSaveMapFile_triggered(); diff --git a/Qt/mainwindow.ui b/Qt/mainwindow.ui index a167aad88430..10f40c73a77e 100644 --- a/Qt/mainwindow.ui +++ b/Qt/mainwindow.ui @@ -180,7 +180,6 @@ &Core - @@ -289,14 +288,6 @@ &Interpreter - - - true - - - &Slightly Faster Interpreter - - true From 2a6af9b8a3b4e00a1e6ee1f5a9912c2c03c04098 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Sun, 17 Feb 2013 01:06:06 +0100 Subject: [PATCH 08/18] Add displayList debug dialog --- Core/Core.cpp | 2 + Core/Host.h | 5 +- GPU/GLES/DisplayListInterpreter.cpp | 5 + GPU/GLES/DisplayListInterpreter.h | 7 + GPU/GLES/Framebuffer.cpp | 20 + GPU/GLES/Framebuffer.h | 3 + GPU/GLES/TextureCache.cpp | 288 +++++ GPU/GLES/TextureCache.h | 2 + GPU/GPUCommon.cpp | 14 +- GPU/GPUCommon.h | 9 + GPU/GPUInterface.h | 15 + Qt/EmuThread.cpp | 24 +- Qt/QtHost.cpp | 36 +- Qt/QtHost.h | 6 +- Qt/ctrldisasmview.cpp | 17 +- Qt/ctrlmemview.cpp | 7 +- Qt/ctrlregisterlist.cpp | 11 +- Qt/ctrlvfpuview.cpp | 11 +- Qt/debugger_disasm.cpp | 130 +-- Qt/debugger_disasm.h | 5 - Qt/debugger_disasm.ui | 66 +- Qt/debugger_displaylist.cpp | 1520 +++++++++++++++++++++++++++ Qt/debugger_displaylist.h | 114 ++ Qt/debugger_displaylist.ui | 527 ++++++++++ Qt/debugger_memory.cpp | 6 +- Qt/debugger_memorytex.cpp | 93 ++ Qt/debugger_memorytex.h | 30 + Qt/debugger_memorytex.ui | 177 ++++ Qt/mainwindow.cpp | 31 +- Qt/mainwindow.h | 10 + Qt/mainwindow.ui | 9 +- 31 files changed, 2950 insertions(+), 250 deletions(-) create mode 100644 Qt/debugger_displaylist.cpp create mode 100644 Qt/debugger_displaylist.h create mode 100644 Qt/debugger_displaylist.ui create mode 100644 Qt/debugger_memorytex.cpp create mode 100644 Qt/debugger_memorytex.h create mode 100644 Qt/debugger_memorytex.ui diff --git a/Core/Core.cpp b/Core/Core.cpp index f66929d07144..fb8f92966c5a 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -100,6 +100,8 @@ void Core_Run() case CORE_STEPPING: //1: wait for step command.. #if defined(USING_QT_UI) || defined(_DEBUG) + host->UpdateDisassembly(); + host->UpdateMemView(); host->SendCoreWait(true); #endif diff --git a/Core/Host.h b/Core/Host.h index f20277ac20e8..65d17824895c 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -64,8 +64,9 @@ class Host virtual void SendCoreWait(bool) {} virtual bool GpuStep() { return false; } - virtual void SendGPUWait() {} - virtual void SetGPUStep(bool value) {} + virtual void SendGPUStart() {} + virtual void SendGPUWait(u32 cmd) {} + virtual void SetGPUStep(bool value, int flag = 0) {} virtual void NextGPUStep() {} // Used for headless. diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 039fc97910b4..e9f1bb78540a 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -1056,6 +1056,11 @@ void GLES_GPU::Resized() { framebufferManager_.Resized(); } +std::vector GLES_GPU::GetFramebufferList() +{ + return framebufferManager_.GetFramebufferList(); +} + void GLES_GPU::DoState(PointerWrap &p) { GPUCommon::DoState(p); diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 7054f60e14e0..52e1883730f8 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -59,6 +59,13 @@ class GLES_GPU : public GPUCommon // Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*. virtual void Resized(); + virtual bool DecodeTexture(u8* dest, GPUgstate state) + { + return textureCache_.DecodeTexture(dest, state); + } + + + std::vector GetFramebufferList(); private: void DoBlockTransfer(); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 7ed3fefd6ada..bc513f90e07d 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -449,6 +449,26 @@ void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, int for } } +std::vector FramebufferManager::GetFramebufferList() +{ + std::vector list; + + for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { + VirtualFramebuffer *vfb = *iter; + + FramebufferInfo info; + info.fb_address = vfb->fb_address; + info.z_address = vfb->z_address; + info.format = vfb->format; + info.width = vfb->width; + info.height = vfb->height; + info.fbo = vfb->fbo; + list.push_back(info); + } + + return list; +} + void FramebufferManager::DecimateFBOs() { for (auto iter = vfbs_.begin(); iter != vfbs_.end();) { VirtualFramebuffer *vfb = *iter; diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index dd7dcee56a04..c5a86426c9ee 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -26,6 +26,7 @@ #include "../Globals.h" +#include "GPU/GPUCommon.h" struct GLSLProgram; class TextureCache; @@ -80,6 +81,8 @@ class FramebufferManager { void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format); size_t NumVFBs() const { return vfbs_.size(); } + std::vector GetFramebufferList(); + int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; } int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 4b964a274ed9..6487e9ce36aa 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -1131,3 +1131,291 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, int level) GLuint components = dstFmt == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA; glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components, dstFmt, finalBuf); } + +bool TextureCache::DecodeTexture(u8* output, GPUgstate state) +{ + GPUgstate oldState = gstate; + gstate = state; + + u32 texaddr = (gstate.texaddr[0] & 0xFFFFF0) | ((gstate.texbufwidth[0]<<8) & 0x0F000000); + + if (!Memory::IsValidAddress(texaddr)) { + return false; + } + + u8 level = 0; + u32 format = gstate.texformat & 0xF; + if (format >= 11) { + ERROR_LOG(G3D, "Unknown texture format %i", format); + format = 0; + } + + u32 clutformat = gstate.clutformat & 3; + u32 clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2); + + const u8 *texptr = Memory::GetPointer(texaddr); + u32 texhash = texptr ? MiniHash((const u32*)texptr) : 0; + + u64 cachekey = texaddr ^ texhash; + if (formatUsesClut[format]) + cachekey |= (u64) clutaddr << 32; + + int bufw = gstate.texbufwidth[0] & 0x3ff; + + int w = 1 << (gstate.texsize[0] & 0xf); + int h = 1 << ((gstate.texsize[0]>>8) & 0xf); + + + GLenum dstFmt = 0; + u32 texByteAlign = 1; + + void *finalBuf = NULL; + + // TODO: Look into using BGRA for 32-bit textures when the GL_EXT_texture_format_BGRA8888 extension is available, as it's faster than RGBA on some chips. + + // TODO: Actually decode the mipmaps. + + switch (format) + { + case GE_TFMT_CLUT4: + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + + switch (clutformat) { + case GE_CMODE_16BIT_BGR5650: + case GE_CMODE_16BIT_ABGR5551: + case GE_CMODE_16BIT_ABGR4444: + { + ReadClut16(clutBuf16); + const u16 *clut = clutBuf16; + u32 clutSharingOff = 0;//gstate.mipmapShareClut ? 0 : level * 16; + texByteAlign = 2; + if (!(gstate.texmode & 1)) { + const u8 *addr = Memory::GetPointer(texaddr); + for (int i = 0; i < bufw * h; i += 2) + { + u8 index = *addr++; + tmpTexBuf16[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOff]; + tmpTexBuf16[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOff]; + } + } else { + UnswizzleFromMem(texaddr, 0, level); + for (int i = 0, j = 0; i < bufw * h; i += 8, j++) + { + u32 n = tmpTexBuf32[j]; + u32 k, index; + for (k = 0; k < 8; k++) { + index = (n >> (k * 4)) & 0xf; + tmpTexBuf16[i + k] = clut[GetClutIndex(index) + clutSharingOff]; + } + } + } + finalBuf = tmpTexBuf16; + } + break; + + case GE_CMODE_32BIT_ABGR8888: + { + ReadClut32(clutBuf32); + const u32 *clut = clutBuf32; + u32 clutSharingOff = 0;//gstate.mipmapShareClut ? 0 : level * 16; + if (!(gstate.texmode & 1)) { + const u8 *addr = Memory::GetPointer(texaddr); + for (int i = 0; i < bufw * h; i += 2) + { + u8 index = *addr++; + tmpTexBuf32[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOff]; + tmpTexBuf32[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOff]; + } + } else { + u32 pixels = bufw * h; + UnswizzleFromMem(texaddr, 0, level); + for (int i = pixels - 8, j = (pixels / 8) - 1; i >= 0; i -= 8, j--) { + u32 n = tmpTexBuf32[j]; + for (int k = 0; k < 8; k++) { + u32 index = (n >> (k * 4)) & 0xf; + tmpTexBuf32[i + k] = clut[GetClutIndex(index) + clutSharingOff]; + } + } + } + finalBuf = tmpTexBuf32; + } + break; + + default: + ERROR_LOG(G3D, "Unknown CLUT4 texture mode %d", (gstate.clutformat & 3)); + return false; + } + break; + + case GE_TFMT_CLUT8: + finalBuf = readIndexedTex(level, texaddr, 1); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_CLUT16: + finalBuf = readIndexedTex(level, texaddr, 2); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_CLUT32: + finalBuf = readIndexedTex(level, texaddr, 4); + dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3)); + texByteAlign = texByteAlignMap[(gstate.clutformat & 3)]; + break; + + case GE_TFMT_4444: + case GE_TFMT_5551: + case GE_TFMT_5650: + if (format == GE_TFMT_4444) + dstFmt = GL_UNSIGNED_SHORT_4_4_4_4; + else if (format == GE_TFMT_5551) + dstFmt = GL_UNSIGNED_SHORT_5_5_5_1; + else if (format == GE_TFMT_5650) + dstFmt = GL_UNSIGNED_SHORT_5_6_5; + texByteAlign = 2; + + if (!(gstate.texmode & 1)) { + int len = std::max(bufw, w) * h; + for (int i = 0; i < len; i++) + tmpTexBuf16[i] = Memory::ReadUnchecked_U16(texaddr + i * 2); + finalBuf = tmpTexBuf16; + } + else + finalBuf = UnswizzleFromMem(texaddr, 2, level); + break; + + case GE_TFMT_8888: + dstFmt = GL_UNSIGNED_BYTE; + if (!(gstate.texmode & 1)) { + int len = bufw * h; + for (int i = 0; i < len; i++) + tmpTexBuf32[i] = Memory::ReadUnchecked_U32(texaddr + i * 4); + finalBuf = tmpTexBuf32; + } + else + finalBuf = UnswizzleFromMem(texaddr, 4, level); + break; + + case GE_TFMT_DXT1: + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT1Block *src = (DXT1Block*)texptr; + + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT1Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + finalBuf = tmpTexBuf32; + w = (w + 3) & ~3; + } + break; + + case GE_TFMT_DXT3: + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT3Block *src = (DXT3Block*)texptr; + + // Alpha is off + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT3Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + w = (w + 3) & ~3; + finalBuf = tmpTexBuf32; + } + break; + + case GE_TFMT_DXT5: + ERROR_LOG(G3D, "Unhandled compressed texture, format %i! swizzle=%i", format, gstate.texmode & 1); + dstFmt = GL_UNSIGNED_BYTE; + { + u32 *dst = tmpTexBuf32; + DXT5Block *src = (DXT5Block*)texptr; + + // Alpha is almost right + for (int y = 0; y < h; y += 4) { + u32 blockIndex = (y / 4) * (bufw / 4); + for (int x = 0; x < std::min(bufw, w); x += 4) { + decodeDXT5Block(dst + bufw * y + x, src + blockIndex, bufw); + blockIndex++; + } + } + w = (w + 3) & ~3; + finalBuf = tmpTexBuf32; + } + break; + + default: + ERROR_LOG(G3D, "Unknown Texture Format %d!!!", format); + finalBuf = tmpTexBuf32; + return false; + } + + if (!finalBuf) { + ERROR_LOG(G3D, "NO finalbuf! Will crash!"); + } + + convertColors((u8*)finalBuf, dstFmt, bufw * h); + + if(dstFmt == GL_UNSIGNED_SHORT_4_4_4_4) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = (val & 0xF) * 255 / 15; + u32 r = ((val & 0xF) >> 24) * 255 / 15; + u32 g = ((val & 0xF) >> 16) * 255 / 15; + u32 b = ((val & 0xF) >> 8) * 255 / 15; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else if(dstFmt == GL_UNSIGNED_SHORT_5_5_5_1) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = (val & 0x1) * 255; + u32 r = ((val & 0x1F) >> 11) * 255 / 31; + u32 g = ((val & 0x1F) >> 6) * 255 / 31; + u32 b = ((val & 0x1F) >> 1) * 255 / 31; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else if(dstFmt == GL_UNSIGNED_SHORT_5_6_5) + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u16*)finalBuf)[x*bufw + y]; + u32 a = 0xFF; + u32 r = ((val & 0x1F) >> 11) * 255 / 31; + u32 g = ((val & 0x3F) >> 6) * 255 / 63; + u32 b = ((val & 0x1F)) * 255 / 31; + ((u32*)output)[x*w + y] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else + { + for(int x = 0; x < h; x++) + for(int y = 0; y < bufw; y++) + { + u32 val = ((u32*)finalBuf)[x*bufw + y]; + ((u32*)output)[x*w + y] = ((val & 0xFF000000)) | ((val & 0x00FF0000)>>16) | ((val & 0x0000FF00)) | ((val & 0x000000FF)<<16); + } + } + + gstate = oldState; + return true; +} diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index bb1958c365f9..764ad6373524 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -19,6 +19,7 @@ #include "../Globals.h" #include "gfx_es2/fbo.h" +#include "GPU/GPUState.h" class TextureCache { @@ -42,6 +43,7 @@ class TextureCache return cache.size(); } + bool DecodeTexture(u8 *output, GPUgstate state); private: struct TexCacheEntry { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d41ab94ab2cd..ff050581ed82 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -76,6 +76,12 @@ bool GPUCommon::InterpretList(DisplayList &list) ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc); return true; } +#if defined(USING_QT_UI) + if(host->GpuStep()) + { + host->SendGPUStart(); + } +#endif while (!finished) { @@ -85,14 +91,16 @@ bool GPUCommon::InterpretList(DisplayList &list) list.status = PSP_GE_LIST_STALL_REACHED; return false; } + + op = Memory::ReadUnchecked_U32(list.pc); //read from memory + u32 cmd = op >> 24; + #if defined(USING_QT_UI) if(host->GpuStep()) { - host->SendGPUWait(); + host->SendGPUWait(cmd); } #endif - op = Memory::ReadUnchecked_U32(list.pc); //read from memory - u32 cmd = op >> 24; u32 diff = op ^ gstate.cmdmem[cmd]; PreExecuteOp(op, diff); // TODO: Add a compiler flag to remove stuff like this at very-final build time. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 66b6ccbdd8bc..8feb9cb5699e 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -62,4 +62,13 @@ class GPUCommon : public GPUInterface { return currentList; } + virtual bool DecodeTexture(u8* dest, GPUgstate state) + { + return false; + } + std::vector GetFramebufferList() + { + return std::vector(); + } + }; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 07886c4e304f..4edb5de1c5b8 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -18,6 +18,7 @@ #pragma once #include "../Globals.h" +#include "GPUState.h" #include class PointerWrap; @@ -32,6 +33,18 @@ enum DisplayListStatus PSP_GE_LIST_CANCEL_DONE = 5, // canceled? }; + +// Used for debug +struct FramebufferInfo +{ + u32 fb_address; + u32 z_address; + int format; + u32 width; + u32 height; + void* fbo; +}; + struct DisplayList { int id; @@ -94,4 +107,6 @@ class GPUInterface virtual void DumpNextFrame() = 0; virtual const std::deque& GetDisplayLists() = 0; virtual DisplayList* GetCurrentDisplayList() = 0; + virtual bool DecodeTexture(u8* dest, GPUgstate state) = 0; + virtual std::vector GetFramebufferList() = 0; }; diff --git a/Qt/EmuThread.cpp b/Qt/EmuThread.cpp index 065e5c770769..4dd3a6457098 100644 --- a/Qt/EmuThread.cpp +++ b/Qt/EmuThread.cpp @@ -152,7 +152,7 @@ void EmuThread::run() host->UpdateUI(); host->InitGL(); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); #ifndef USING_GLES2 glewInit(); @@ -163,6 +163,8 @@ void EmuThread::run() QElapsedTimer timer; + EmuThread_LockDraw(false); + while(running) { //UpdateGamepad(*input_state); timer.start(); @@ -173,10 +175,7 @@ void EmuThread::run() if(gRun) { - - gameMutex->lock(); - - glWindow->makeCurrent(); + EmuThread_LockDraw(true); if(needInitGame) { g_State.bEmuThreadStarted = true; @@ -239,14 +238,12 @@ void EmuThread::run() qint64 time = timer.elapsed(); const int frameTime = (1.0f/60.0f) * 1000; - gameMutex->unlock(); if(time < frameTime) { - glWindow->doneCurrent(); + EmuThread_LockDraw(false); msleep(frameTime-time); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); } - gameMutex->lock(); timer.start(); } @@ -276,13 +273,11 @@ void EmuThread::run() } #endif glWindow->swapBuffers(); - glWindow->doneCurrent(); - gameMutex->unlock(); + EmuThread_LockDraw(false); } else { - gameMutex->lock(); - glWindow->makeCurrent(); + EmuThread_LockDraw(true); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -323,8 +318,7 @@ void EmuThread::run() ui_draw2d.Flush(UIShader_Get()); glWindow->swapBuffers(); - glWindow->doneCurrent(); - gameMutex->unlock(); + EmuThread_LockDraw(false); qint64 time = timer.elapsed(); const int frameTime = (1.0f/60.0f) * 1000; if(time < frameTime) diff --git a/Qt/QtHost.cpp b/Qt/QtHost.cpp index 5a8989ead8a5..ca55e43879fe 100644 --- a/Qt/QtHost.cpp +++ b/Qt/QtHost.cpp @@ -12,6 +12,7 @@ #include "android/jni/EmuScreen.h" #include "android/jni/UIShader.h" #include "android/jni/ui_atlas.h" +#include "GPU/ge_constants.h" #include "EmuThread.h" std::string boot_filename = ""; @@ -65,6 +66,10 @@ void QtHost::UpdateDisassembly() mainWindow->GetDialogDisasm()->GotoPC(); mainWindow->GetDialogDisasm()->Update(); } + if(mainWindow->GetDialogDisplaylist()) + { + mainWindow->GetDialogDisplaylist()->Update(); + } } void QtHost::SetDebugMode(bool mode) @@ -145,19 +150,42 @@ bool QtHost::GpuStep() return m_GPUStep; } -void QtHost::SendGPUWait() +void QtHost::SendGPUStart() +{ + EmuThread_LockDraw(false); + + if(m_GPUFlag == -1) + { + m_GPUFlag = 0; + } + + EmuThread_LockDraw(true); +} + +void QtHost::SendGPUWait(u32 cmd) { EmuThread_LockDraw(false); - mainWindow->GetDialogDisasm()->UpdateDisplayList(); - m_hGPUStepEvent.wait(m_hGPUStepMutex); + if((m_GPUFlag == 1 && (cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE))) + { + // Break after the draw + m_GPUFlag = 0; + } + else if(m_GPUFlag == 0) + { + + mainWindow->GetDialogDisasm()->UpdateDisplayList(); + mainWindow->GetDialogDisplaylist()->Update(); + m_hGPUStepEvent.wait(m_hGPUStepMutex); + } EmuThread_LockDraw(true); } -void QtHost::SetGPUStep(bool value) +void QtHost::SetGPUStep(bool value, int flag) { m_GPUStep = value; + m_GPUFlag = flag; } void QtHost::NextGPUStep() diff --git a/Qt/QtHost.h b/Qt/QtHost.h index b98ec8954e4a..8f578c9fd5fc 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -51,8 +51,9 @@ class QtHost : public QObject, public Host void SendCoreWait(bool); bool GpuStep(); - void SendGPUWait(); - void SetGPUStep(bool value); + void SendGPUWait(u32 cmd); + void SendGPUStart(); + void SetGPUStep(bool value, int flag = 0); void NextGPUStep(); signals: @@ -60,6 +61,7 @@ class QtHost : public QObject, public Host private: MainWindow* mainWindow; bool m_GPUStep; + int m_GPUFlag; }; #endif // QTAPP_H diff --git a/Qt/ctrldisasmview.cpp b/Qt/ctrldisasmview.cpp index a2b7a00829e7..92d43f8e51f6 100644 --- a/Qt/ctrldisasmview.cpp +++ b/Qt/ctrldisasmview.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -164,9 +163,7 @@ void CtrlDisAsmView::GoToMemoryView() void CtrlDisAsmView::CopyAddress() { - char temp[16]; - sprintf(temp,"%08x",selection); - QApplication::clipboard()->setText(QString(temp)); + QApplication::clipboard()->setText(QString("%1").arg(selection,8,16,QChar('0'))); } void CtrlDisAsmView::CopyInstrDisAsm() @@ -178,11 +175,9 @@ void CtrlDisAsmView::CopyInstrDisAsm() void CtrlDisAsmView::CopyInstrHex() { - char temp[24]; EmuThread_LockDraw(true); - sprintf(temp,"%08x",debugger->readMemory(selection)); + QApplication::clipboard()->setText(QString("%1").arg(debugger->readMemory(selection),8,16,QChar('0'))); EmuThread_LockDraw(false); - QApplication::clipboard()->setText(temp); } void CtrlDisAsmView::SetNextStatement() @@ -234,8 +229,7 @@ void CtrlDisAsmView::RenameFunction() int sym = symbolMap.GetSymbolNum(selection); if (sym != -1) { - char name[256]; - strncpy(name, symbolMap.GetSymbolName(sym),256); + QString name = symbolMap.GetSymbolName(sym); bool ok; QString newname = QInputDialog::getText(this, tr("New function name"), tr("New function name:"), QLineEdit::Normal, @@ -300,8 +294,6 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) int rowY1 = rect().bottom()/2 + rowHeight*i - rowHeight/2; int rowY2 = rect().bottom()/2 + rowHeight*i + rowHeight/2 - 1; - char temp[256]; - sprintf(temp,"%08x",address); lbr.setColor(marker==address?QColor(0xFFFFEEE0):QColor(debugger->getColor(address))); QColor bg = lbr.color(); @@ -319,7 +311,6 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) if (address == debugger->getPC()) { painter.setBrush(pcBrush); - qDebug() << address; } painter.drawRect(16,rowY1,width-16-1,rowY2-rowY1); @@ -327,7 +318,7 @@ void CtrlDisAsmView::paintEvent(QPaintEvent *) QPen textPen = QPen(QColor(halfAndHalf(bg.rgba(),0))); painter.setPen(textPen); painter.setFont(alignedFont); - painter.drawText(17,rowY1-3+rowHeight,QString(temp)); + painter.drawText(17,rowY1-3+rowHeight,QString("%1").arg(address,8,16,QChar('0'))); painter.setFont(normalFont); textPen.setColor(QColor(0xFF000000)); painter.setPen(textPen); diff --git a/Qt/ctrlmemview.cpp b/Qt/ctrlmemview.cpp index ffc768c48f7d..c7c66374369d 100644 --- a/Qt/ctrlmemview.cpp +++ b/Qt/ctrlmemview.cpp @@ -108,7 +108,6 @@ void CtrlMemView::paintEvent(QPaintEvent *) int rowY2 = rect().bottom()/2 + rowHeight*i + rowHeight/2; char temp[256]; - sprintf(temp,"%08x",address); painter.setBrush(currentBrush); @@ -123,7 +122,7 @@ void CtrlMemView::paintEvent(QPaintEvent *) textPen.setColor(0x600000); painter.setPen(textPen); painter.setFont(alignedFont); - painter.drawText(17,rowY1-2+rowHeight, temp); + painter.drawText(17,rowY1-2+rowHeight, QString("%1").arg(address,8,16,QChar('0'))); textPen.setColor(0xFF000000); painter.setPen(textPen); if (debugger->isAlive()) @@ -231,9 +230,7 @@ void CtrlMemView::contextMenu(const QPoint &pos) void CtrlMemView::CopyValue() { - char temp[24]; - sprintf(temp,"%08x",Memory::ReadUnchecked_U32(selection)); - QApplication::clipboard()->setText(temp); + QApplication::clipboard()->setText(QString("%1").arg(Memory::ReadUnchecked_U32(selection),8,16,QChar('0'))); } void CtrlMemView::Dump() diff --git a/Qt/ctrlregisterlist.cpp b/Qt/ctrlregisterlist.cpp index 09fa91632f45..a52c5c88abb2 100644 --- a/Qt/ctrlregisterlist.cpp +++ b/Qt/ctrlregisterlist.cpp @@ -236,14 +236,14 @@ void CtrlRegisterList::paintEvent(QPaintEvent *) painter.setBrush(currentBrush); if (iGetNumRegsInCategory(category)) { - char temp[256]; - sprintf(temp,"%s",cpu->GetRegName(category,i)); + QString regName = cpu->GetRegName(category,i); textPen.setColor(0x600000); painter.setPen(textPen); - painter.drawText(17,rowY1-3+rowHeight,temp); + painter.drawText(17,rowY1-3+rowHeight,regName); textPen.setColor(0xFF000000); painter.setPen(textPen); + char temp[256]; cpu->PrintRegValue(category,i,temp); if (category == 0 && changedCat0Regs[i]) { @@ -331,10 +331,7 @@ void CtrlRegisterList::CopyValue() u32 val = cpu->GetRegValue(cat,reg); EmuThread_LockDraw(false); - char temp[24]; - sprintf(temp,"%08x",val); - - QApplication::clipboard()->setText(temp); + QApplication::clipboard()->setText(QString("%1").arg(val,8,16,QChar('0'))); } void CtrlRegisterList::Change() diff --git a/Qt/ctrlvfpuview.cpp b/Qt/ctrlvfpuview.cpp index 5ce363dd95f3..cfdde62084e7 100644 --- a/Qt/ctrlvfpuview.cpp +++ b/Qt/ctrlvfpuview.cpp @@ -45,9 +45,7 @@ void CtrlVfpuView::paintEvent(QPaintEvent *) { int my = (int)(yStart + matrix * rowHeight * 5.5f); painter.drawRect(0, my, xStart-1, rowHeight-1); - char temp[256]; - sprintf(temp, "M%i00", matrix); - painter.drawText(3, my+rowHeight-3, temp); + painter.drawText(3, my+rowHeight-3, QString("M%1").arg(matrix)+"00"); painter.drawRect(xStart, my+rowHeight, columnWidth*4-1, 4*rowHeight-1); for (int column = 0; column<4; column++) @@ -56,13 +54,10 @@ void CtrlVfpuView::paintEvent(QPaintEvent *) int x = column * columnWidth + xStart; painter.drawRect(x, y, columnWidth-1, rowHeight - 1); - char temp[256]; - sprintf(temp, "R%i0%i", matrix, column); - painter.drawText(x+3, y-3+rowHeight, temp); + painter.drawText(x+3, y-3+rowHeight, QString("R%1").arg(matrix)+QString("0%1").arg(column)); painter.drawRect(0, y+rowHeight*(column+1), xStart - 1, rowHeight - 1); - sprintf(temp, "C%i%i0", matrix, column); - painter.drawText(3, y+rowHeight*(column+2)-3, temp); + painter.drawText(3, y+rowHeight*(column+2)-3, QString("C%1").arg(matrix)+QString("%1").arg(column)+"0"); y+=rowHeight; diff --git a/Qt/debugger_disasm.cpp b/Qt/debugger_disasm.cpp index bd1a007f0742..2b670bb1504c 100644 --- a/Qt/debugger_disasm.cpp +++ b/Qt/debugger_disasm.cpp @@ -344,7 +344,7 @@ void Debugger_Disasm::FillFunctions() if(symbolMap.GetSymbolType(i) & ST_FUNCTION) { QListWidgetItem* item = new QListWidgetItem(); - item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QVariant(symbolMap.GetSymbolSize(i)).toString() +")"); + item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QString::number(symbolMap.GetSymbolSize(i)) +")"); item->setData(Qt::UserRole, symbolMap.GetAddress(i)); ui->FuncList->addItem(item); } @@ -372,9 +372,7 @@ void Debugger_Disasm::UpdateBreakpointsGUI() if(!CBreakPoints::IsTempBreakPoint(addr_)) { QTreeWidgetItem* item = new QTreeWidgetItem(); - char temp[24]; - sprintf(temp,"%08x",addr_); - item->setText(0,temp); + item->setText(0,QString("%1").arg(addr_,8,16,QChar('0'))); item->setData(0,Qt::UserRole,addr_); ui->breakpointsList->addTopLevelItem(item); if(curBpAddr == addr_) @@ -434,7 +432,7 @@ void Debugger_Disasm::UpdateThreadGUI() for(int i = 0; i < threads.size(); i++) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(threads[i].id).toString()); + item->setText(0,QString::number(threads[i].id)); item->setData(0,Qt::UserRole,threads[i].id); item->setText(1,threads[i].name); QString status = ""; @@ -445,12 +443,9 @@ void Debugger_Disasm::UpdateThreadGUI() if(threads[i].status & THREADSTATUS_DORMANT) status += "Dormant "; if(threads[i].status & THREADSTATUS_DEAD) status += "Dead "; item->setText(2,status); - char temp[24]; - sprintf(temp,"%08x",threads[i].curPC); - item->setText(3,temp); + item->setText(3,QString("%1").arg(threads[i].curPC,8,16,QChar('0'))); item->setData(3,Qt::UserRole,threads[i].curPC); - sprintf(temp,"%08x",threads[i].entrypoint); - item->setText(4,temp); + item->setText(4,QString("%1").arg(threads[i].entrypoint,8,16,QChar('0'))); item->setData(4,Qt::UserRole,threads[i].entrypoint); if(threads[i].isCurrent) @@ -461,6 +456,8 @@ void Debugger_Disasm::UpdateThreadGUI() ui->threadList->addTopLevelItem(item); } + for(int i = 0; i < ui->threadList->columnCount(); i++) + ui->threadList->resizeColumnToContents(i); } void Debugger_Disasm::on_threadList_itemClicked(QTreeWidgetItem *item, int column) @@ -542,7 +539,6 @@ void Debugger_Disasm::UpdateDisplayListGUI() curDlId = ui->displayList->currentItem()->data(0,Qt::UserRole).toInt(); ui->displayList->clear(); - ui->displayListData->clear(); EmuThread_LockDraw(true); const std::deque& dlQueue = gpu->GetDisplayLists(); @@ -551,7 +547,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() if(dl) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(dl->id).toString()); + item->setText(0,QString::number(dl->id)); item->setData(0, Qt::UserRole, dl->id); switch(dl->status) { @@ -563,19 +559,15 @@ void Debugger_Disasm::UpdateDisplayListGUI() case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; default: break; } - char temp[24]; - sprintf(temp,"%08x",dl->startpc); - item->setText(2,temp); + item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0'))); item->setData(2, Qt::UserRole, dl->startpc); - sprintf(temp,"%08x",dl->pc); - item->setText(3,temp); + item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, dl->pc); ui->displayList->addTopLevelItem(item); if(curDlId == dl->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; - ShowDLCode(); } } @@ -584,7 +576,7 @@ void Debugger_Disasm::UpdateDisplayListGUI() if(dl && it->id == dl->id) continue; QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(0,QVariant(it->id).toString()); + item->setText(0,QString::number(it->id)); item->setData(0, Qt::UserRole, it->id); switch(it->status) { @@ -596,21 +588,19 @@ void Debugger_Disasm::UpdateDisplayListGUI() case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; default: break; } - char temp[24]; - sprintf(temp,"%08x",it->startpc); - item->setText(2,temp); + item->setText(2,QString("%1").arg(it->startpc,8,16,QChar('0'))); item->setData(2, Qt::UserRole, it->startpc); - sprintf(temp,"%08x",it->pc); - item->setText(3,temp); + item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); item->setData(3, Qt::UserRole, it->pc); ui->displayList->addTopLevelItem(item); if(curDlId == it->id) { ui->displayList->setCurrentItem(item); displayListRowSelected = item; - ShowDLCode(); } } + for(int i = 0; i < ui->displayList->columnCount(); i++) + ui->displayList->resizeColumnToContents(i); EmuThread_LockDraw(false); } @@ -621,96 +611,12 @@ void Debugger_Disasm::on_displayList_customContextMenuRequested(const QPoint &po { displayListRowSelected = item; - QMenu menu(this); + /*QMenu menu(this); QAction *showCode = new QAction(tr("Show code"), this); connect(showCode, SIGNAL(triggered()), this, SLOT(ShowDLCode())); - menu.addAction(showCode); + menu.addAction(showCode);*/ - menu.exec( ui->displayList->mapToGlobal(pos)); + //menu.exec( ui->displayList->mapToGlobal(pos)); } } - -void Debugger_Disasm::ShowDLCode() -{ - ui->displayListData->clear(); - ui->displayListData->setColumnWidth(0,70); - - u32 startPc = displayListRowSelected->data(2,Qt::UserRole).toInt(); - u32 curPc = displayListRowSelected->data(3,Qt::UserRole).toInt(); - - std::map data; - FillDisplayListCmd(data, startPc,0); - - for(std::map::iterator it = data.begin(); it != data.end(); it++) - { - QTreeWidgetItem* item = new QTreeWidgetItem(); - char temp[24]; - sprintf(temp,"%08x",it->first); - item->setText(0,temp); - item->setText(1,it->second.c_str()); - if(curPc == it->first) - { - for(int j = 0; j < 2; j++) - item->setTextColor(j, Qt::green); - } - ui->displayListData->addTopLevelItem(item); - } -} - -void Debugger_Disasm::FillDisplayListCmd(std::map& data, u32 pc, u32 prev) -{ - u32 curPc = pc; - int debugLimit = 10000; // Anti crash if this code is bugged - while(Memory::IsValidAddress(curPc) && debugLimit > 0) - { - if(data.find(curPc) != data.end()) - return; - - u32 op = Memory::ReadUnchecked_U32(curPc); //read from memory - u32 cmd = op >> 24; - u32 diff = op ^ gstate.cmdmem[cmd]; - char temp[256]; - GeDisassembleOp(curPc, op, prev, temp); - data[curPc] = temp; - prev = op; - if(cmd == GE_CMD_JUMP) - { - u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; - FillDisplayListCmd(data, target, prev); - return; - } - else if(cmd == GE_CMD_CALL) - { - u32 target = gstate_c.getRelativeAddress(op & 0xFFFFFF); - FillDisplayListCmd(data, target, prev); - } - else if(cmd == GE_CMD_RET) - { - return; - } - else if(cmd == GE_CMD_FINISH) - { - return; - } - else if(cmd == GE_CMD_END) - { - if(prev >> 24 == GE_CMD_FINISH) - return; - } - curPc += 4; - debugLimit--; - } -} - -void Debugger_Disasm::on_nextGPU_clicked() -{ - host->SetGPUStep(true); - host->NextGPUStep(); -} - -void Debugger_Disasm::on_runBtn_clicked() -{ - host->SetGPUStep(false); - host->NextGPUStep(); -} diff --git a/Qt/debugger_disasm.h b/Qt/debugger_disasm.h index fb47a1935f75..5ca646e4be27 100644 --- a/Qt/debugger_disasm.h +++ b/Qt/debugger_disasm.h @@ -41,7 +41,6 @@ class Debugger_Disasm : public QDialog void UpdateDisplayList(); protected: void showEvent(QShowEvent *); - void FillDisplayListCmd(std::map& data, u32 pc, u32 prev); signals: void updateDisplayList_(); @@ -52,7 +51,6 @@ public slots: void Goto(u32 addr); void RemoveBreakpoint(); void GotoThreadEntryPoint(); - void ShowDLCode(); private slots: void UpdateDisplayListGUI(); @@ -103,9 +101,6 @@ private slots: void SetThreadStatusSuspend(); void on_displayList_customContextMenuRequested(const QPoint &pos); - void on_nextGPU_clicked(); - - void on_runBtn_clicked(); private: void SetThreadStatus(ThreadStatus status); diff --git a/Qt/debugger_disasm.ui b/Qt/debugger_disasm.ui index bcf992486f1d..0cc8967bcfb8 100644 --- a/Qt/debugger_disasm.ui +++ b/Qt/debugger_disasm.ui @@ -313,7 +313,7 @@ - 2 + 0 @@ -424,70 +424,6 @@ - - - - - - false - - - false - - - false - - - 2 - - - false - - - - 1 - - - - - 2 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Run - - - - - - - Step - - - - - - - diff --git a/Qt/debugger_displaylist.cpp b/Qt/debugger_displaylist.cpp new file mode 100644 index 000000000000..0f557354ca93 --- /dev/null +++ b/Qt/debugger_displaylist.cpp @@ -0,0 +1,1520 @@ +#include "debugger_displaylist.h" + +#include +#include + +#include "Core/CPU.h" +#include "ui_debugger_displaylist.h" +#include "GPU/GPUInterface.h" +#include "GPU/GeDisasm.h" +#include "EmuThread.h" +#include "Core/Host.h" +#include "base/display.h" +#include "mainwindow.h" +#include "GPU/GLES/VertexDecoder.h" +#include + + +Debugger_DisplayList::Debugger_DisplayList(DebugInterface *_cpu, MainWindow* mainWindow_, QWidget *parent) : + QDialog(parent), + ui(new Ui::Debugger_DisplayList), + cpu(_cpu), + mainWindow(mainWindow_), + currentRenderFrameDisplay(0), + currentTextureDisplay(0), + fboZoomFactor(1), + maxVtxDisplay(20), + maxIdxDisplay(20) +{ + ui->setupUi(this); + + QObject::connect(this, SIGNAL(updateDisplayList_()), this, SLOT(UpdateDisplayListGUI())); + QObject::connect(this, SIGNAL(updateRenderBufferList_()), this, SLOT(UpdateRenderBufferListGUI())); + +} + +Debugger_DisplayList::~Debugger_DisplayList() +{ + delete ui; +} + + +void Debugger_DisplayList::showEvent(QShowEvent *) +{ + +#ifdef Q_WS_X11 + // Hack to remove the X11 crash with threaded opengl when opening the first dialog + EmuThread_LockDraw(true); + QTimer::singleShot(100, this, SLOT(releaseLock())); +#endif + +} + +void Debugger_DisplayList::releaseLock() +{ + EmuThread_LockDraw(false); +} + + +void Debugger_DisplayList::UpdateDisplayList() +{ + emit updateDisplayList_(); +} + + +void Debugger_DisplayList::UpdateDisplayListGUI() +{ + u32 curDlId = 0; + QTreeWidgetItem* curItem = ui->displayList->currentItem(); + if(curItem) + curDlId = ui->displayList->currentItem()->data(0,Qt::UserRole).toInt(); + + displayListRowSelected = 0; + ui->displayList->clear(); + ui->displayListData->clear(); + + EmuThread_LockDraw(true); + const std::deque& dlQueue = gpu->GetDisplayLists(); + + DisplayList* dl = gpu->GetCurrentDisplayList(); + if(dl) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString::number(dl->id)); + item->setData(0, Qt::UserRole, dl->id); + switch(dl->status) + { + case PSP_GE_LIST_DONE: item->setText(1,"Done"); break; + case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break; + case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break; + case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break; + case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break; + case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; + default: break; + } + item->setText(2,QString("%1").arg(dl->startpc,8,16,QChar('0'))); + item->setData(2, Qt::UserRole, dl->startpc); + item->setText(3,QString("%1").arg(dl->pc,8,16,QChar('0'))); + item->setData(3, Qt::UserRole, dl->pc); + ui->displayList->addTopLevelItem(item); + if(curDlId == dl->id) + { + ui->displayList->setCurrentItem(item); + displayListRowSelected = item; + ShowDLCode(); + } + } + + for(auto it = dlQueue.begin(); it != dlQueue.end(); ++it) + { + if(dl && it->id == dl->id) + continue; + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString::number(it->id)); + item->setData(0, Qt::UserRole, it->id); + switch(it->status) + { + case PSP_GE_LIST_DONE: item->setText(1,"Done"); break; + case PSP_GE_LIST_QUEUED: item->setText(1,"Queued"); break; + case PSP_GE_LIST_DRAWING: item->setText(1,"Drawing"); break; + case PSP_GE_LIST_STALL_REACHED: item->setText(1,"Stall Reached"); break; + case PSP_GE_LIST_END_REACHED: item->setText(1,"End Reached"); break; + case PSP_GE_LIST_CANCEL_DONE: item->setText(1,"Cancel Done"); break; + default: break; + } + item->setText(2,QString("%1").arg(it->startpc,8,16,QChar('0'))); + item->setData(2, Qt::UserRole, it->startpc); + item->setText(3,QString("%1").arg(it->pc,8,16,QChar('0'))); + item->setData(3, Qt::UserRole, it->pc); + ui->displayList->addTopLevelItem(item); + if(curDlId == it->id) + { + ui->displayList->setCurrentItem(item); + displayListRowSelected = item; + ShowDLCode(); + } + } + for(int i = 0; i < ui->displayList->columnCount(); i++) + ui->displayList->resizeColumnToContents(i); + EmuThread_LockDraw(false); +} + + +void Debugger_DisplayList::ShowDLCode() +{ + ui->displayListData->clear(); + ui->displayListData->setColumnCount(4); + + u32 startPc = displayListRowSelected->data(2,Qt::UserRole).toInt(); + u32 curPc = displayListRowSelected->data(3,Qt::UserRole).toInt(); + + std::map data; + GPUgstate listState; + memset(&listState,0,sizeof(GPUgstate)); + drawGPUState.clear(); + vtxBufferSize.clear(); + idxBufferSize.clear(); + + FillDisplayListCmd(data, startPc,0, listState); + + u32 curTexAddr; + u32 curVtxAddr; + u32 curIdxAddr; + + for(std::map::iterator it = data.begin(); it != data.end(); it++) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString("%1").arg(it->first,8,16,QChar('0'))); + item->setData(0, Qt::UserRole, it->first); + item->setText(1,QString("%1").arg(it->second.cmd,2,16,QChar('0'))); + item->setText(2,QString("%1").arg(it->second.data,6,16,QChar('0'))); + item->setText(3,it->second.comment); + if(curPc == it->first) + { + curTexAddr = it->second.texAddr; + curVtxAddr = it->second.vtxAddr; + curIdxAddr = it->second.idxAddr; + setCurrentFBO(it->second.fboAddr); + for(int j = 0; j < ui->displayListData->columnCount(); j++) + item->setTextColor(j, Qt::green); + } + if(it->second.implementationNotFinished) + { + for(int j = 0; j < ui->displayListData->columnCount(); j++) + item->setBackgroundColor(j, Qt::red); + } + ui->displayListData->addTopLevelItem(item); + + if(curPc == it->first) + { + ui->displayListData->setCurrentItem(item); + } + } + for(int j = 0; j < ui->displayListData->columnCount(); j++) + ui->displayListData->resizeColumnToContents(j); + + ui->texturesList->clear(); + ui->vertexData->clear(); + ui->vertexList->clear(); + ui->indexData->clear(); + ui->indexList->clear(); + + std::set usedTexAddr; + std::set usedVtxAddr; + std::set usedIdxAddr; + for(int i = 0; i < drawGPUState.size(); i++) + { + // Textures + QTreeWidgetItem* item = new QTreeWidgetItem(); + u32 texaddr = (drawGPUState[i].texaddr[0] & 0xFFFFF0) | ((drawGPUState[i].texbufwidth[0]<<8) & 0x0F000000); + if(!(usedTexAddr.find(texaddr) != usedTexAddr.end() || !Memory::IsValidAddress(texaddr))) + { + u32 format = drawGPUState[i].texformat & 0xF; + int w = 1 << (drawGPUState[i].texsize[0] & 0xf); + int h = 1 << ((drawGPUState[i].texsize[0]>>8) & 0xf); + + item->setText(0,QString("%1").arg(texaddr,8,16,QChar('0'))); + item->setData(0, Qt::UserRole, i); + item->setText(1,QString::number(w)); + item->setText(2,QString::number(h)); + item->setText(3,QString::number(format,16)); + ui->texturesList->addTopLevelItem(item); + if(curTexAddr == texaddr) + { + ui->texturesList->setCurrentItem(item); + for(int j = 0; j < ui->texturesList->columnCount(); j++) + item->setTextColor(j,Qt::green); + } + usedTexAddr.insert(texaddr); + } + + // Vertex + QTreeWidgetItem* vertexItem = new QTreeWidgetItem(); + u32 baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].vaddr & 0xFFFFFF); + u32 vaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + if(!((drawGPUState[i].vaddr) == 0 || !Memory::IsValidAddress(vaddr) || usedVtxAddr.find(vaddr) != usedVtxAddr.end())) + { + vertexItem->setText(0, QString("%1").arg(vaddr,8,16,QChar('0'))); + vertexItem->setData(0,Qt::UserRole, i); + if((drawGPUState[i].vertType & GE_VTYPE_THROUGH_MASK) == GE_VTYPE_TRANSFORM) + vertexItem->setText(1, "Transform"); + else + vertexItem->setText(1, "Raw"); + vertexItem->setText(2, QString::number((drawGPUState[i].vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT)); + vertexItem->setText(3, QString::number((drawGPUState[i].vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT)); + switch(drawGPUState[i].vertType & GE_VTYPE_WEIGHT_MASK) + { + case GE_VTYPE_WEIGHT_8BIT: vertexItem->setText(4, "8bit"); break; + case GE_VTYPE_WEIGHT_16BIT: vertexItem->setText(4, "16bit"); break; + case GE_VTYPE_WEIGHT_FLOAT: vertexItem->setText(4, "float"); break; + default: vertexItem->setText(4, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_POS_MASK) + { + case GE_VTYPE_POS_8BIT: vertexItem->setText(5, "8bit"); break; + case GE_VTYPE_POS_16BIT: vertexItem->setText(5, "16bit"); break; + case GE_VTYPE_POS_FLOAT: vertexItem->setText(5, "float"); break; + default: vertexItem->setText(5, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_NRM_MASK) + { + case GE_VTYPE_NRM_8BIT: vertexItem->setText(6, "8bit"); break; + case GE_VTYPE_NRM_16BIT: vertexItem->setText(6, "16bit"); break; + case GE_VTYPE_NRM_FLOAT: vertexItem->setText(6, "float"); break; + default: vertexItem->setText(6, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_COL_MASK) + { + case GE_VTYPE_COL_4444: vertexItem->setText(7, "4444"); break; + case GE_VTYPE_COL_5551: vertexItem->setText(7, "5551"); break; + case GE_VTYPE_COL_565: vertexItem->setText(7, "565"); break; + case GE_VTYPE_COL_8888: vertexItem->setText(7, "8888"); break; + default: vertexItem->setText(7, "No"); break; + } + switch(drawGPUState[i].vertType & GE_VTYPE_TC_MASK) + { + case GE_VTYPE_TC_8BIT: vertexItem->setText(8, "8bit"); break; + case GE_VTYPE_TC_16BIT: vertexItem->setText(8, "16bit"); break; + case GE_VTYPE_TC_FLOAT: vertexItem->setText(8, "float"); break; + default: vertexItem->setText(8, "No"); break; + } + + ui->vertexList->addTopLevelItem(vertexItem); + if(curVtxAddr == vaddr) + { + ui->vertexList->setCurrentItem(vertexItem); + for(int j = 0; j < ui->vertexList->columnCount(); j++) + vertexItem->setTextColor(j,Qt::green); + } + usedVtxAddr.insert(vaddr); + } + + + // Index + QTreeWidgetItem* indexItem = new QTreeWidgetItem(); + baseExtended = ((drawGPUState[i].base & 0x0F0000) << 8) | (drawGPUState[i].iaddr & 0xFFFFFF); + u32 iaddr = ((drawGPUState[i].offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + if(!((drawGPUState[i].iaddr & 0xFFFFFF) == 0 || !Memory::IsValidAddress(iaddr) || usedIdxAddr.find(iaddr) != usedIdxAddr.end())) + { + indexItem->setText(0, QString("%1").arg(iaddr,8,16,QChar('0'))); + indexItem->setData(0,Qt::UserRole, i); + + ui->indexList->addTopLevelItem(indexItem); + if(curIdxAddr == iaddr) + { + ui->indexList->setCurrentItem(indexItem); + for(int j = 0; j < ui->indexList->columnCount(); j++) + indexItem->setTextColor(j,Qt::green); + } + usedIdxAddr.insert(iaddr); + } + + for(int i = 0; i < ui->texturesList->columnCount(); i++) + ui->texturesList->resizeColumnToContents(i); + for(int i = 0; i < ui->vertexList->columnCount(); i++) + ui->vertexList->resizeColumnToContents(i); + for(int i = 0; i < ui->indexList->columnCount(); i++) + ui->indexList->resizeColumnToContents(i); + } + + UpdateVertexInfo(); + UpdateIndexInfo(); +} + + +QString Debugger_DisplayList::DisassembleOp(u32 pc, u32 op, u32 prev, const GPUgstate& state) { + u32 cmd = op >> 24; + u32 data = op & 0xFFFFFF; + + // Handle control and drawing commands here directly. The others we delegate. + switch (cmd) + { + case GE_CMD_BASE: + return QString("BASE: %1").arg(data & 0xFFFFFF,6,16,QChar('0')); + break; + + case GE_CMD_VADDR: /// <<8???? + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF); + baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("VADDR: %1").arg(baseExtended,6,16,QChar('0')); + break; + } + + case GE_CMD_IADDR: + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data & 0xFFFFFF); + baseExtended = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("IADDR: %1").arg(baseExtended,6,16,QChar('0')); + break; + } + + case GE_CMD_PRIM: + { + u32 count = data & 0xFFFF; + u32 type = data >> 16; + static const char* types[7] = { + "POINTS", + "LINES", + "LINE_STRIP", + "TRIANGLES", + "TRIANGLE_STRIP", + "TRIANGLE_FAN", + "RECTANGLES", + }; + return QString("DrawPrim type: %1 count: %2").arg(type < 7 ? types[type] : "INVALID").arg(count); + } + break; + + // The arrow and other rotary items in Puzbob are bezier patches, strangely enough. + case GE_CMD_BEZIER: + { + int bz_ucount = data & 0xFF; + int bz_vcount = (data >> 8) & 0xFF; + return QString("DRAW BEZIER: %1 x %2").arg(bz_ucount).arg(bz_vcount); + } + break; + + case GE_CMD_SPLINE: + { + int sp_ucount = data & 0xFF; + int sp_vcount = (data >> 8) & 0xFF; + int sp_utype = (data >> 16) & 0x3; + int sp_vtype = (data >> 18) & 0x3; + return QString("DRAW SPLINE: %1 x %2, %3 x %4").arg(sp_ucount).arg(sp_vcount).arg(sp_utype).arg(sp_vtype); + } + break; + + case GE_CMD_JUMP: + { + u32 target = (((state.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; + return QString("CMD JUMP - %1 to %2").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')); + } + break; + + case GE_CMD_CALL: + { + u32 retval = pc + 4; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (op & 0xFFFFFF); + u32 target = (state.offsetAddr + baseExtended) & 0x0FFFFFFF; + return QString("CMD CALL - %1 to %2, ret=%3").arg(pc,8,16,QChar('0')).arg(target,8,16,QChar('0')).arg(retval,8,16,QChar('0')); + } + break; + + case GE_CMD_RET: + return QString("CMD RET"); + break; + + case GE_CMD_SIGNAL: + return QString("GE_CMD_SIGNAL %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_FINISH: + return QString("CMD FINISH %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_END: + switch (prev >> 24) + { + case GE_CMD_SIGNAL: + { + // TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935# + int behaviour = (prev >> 16) & 0xFF; + int signal = prev & 0xFFFF; + int enddata = data & 0xFFFF; + // We should probably defer to sceGe here, no sense in implementing this stuff in every GPU + switch (behaviour) { + case 1: // Signal with Wait + return QString("Signal with Wait UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 2: + return QString("Signal without wait. signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 3: + return QString("Signal with Pause UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x10: + return QString("Signal with Jump UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x11: + return QString("Signal with Call UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + case 0x12: + return QString("Signal with Return UNIMPLEMENTED! signal/end: %1 %2").arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + default: + return QString("UNKNOWN Signal UNIMPLEMENTED %1 ! signal/end: %1 %2").arg(behaviour).arg(signal,4,16,QChar('0')).arg(enddata,4,16,QChar('0')); + break; + } + } + break; + case GE_CMD_FINISH: + break; + default: + return QString("Ah, not finished: %1").arg(prev & 0xFFFFFF,6,16,QChar('0')); + break; + } + return "CMD END"; + break; + + case GE_CMD_BJUMP: + // bounding box jump. Let's just not jump, for now. + return QString("BBOX JUMP - unimplemented"); + break; + + case GE_CMD_BOUNDINGBOX: + // bounding box test. Let's do nothing. + return QString("BBOX TEST - unimplemented"); + break; + + case GE_CMD_ORIGIN: + return QString("Origin: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_VERTEXTYPE: + return QString("SetVertexType: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_OFFSETADDR: + return QString("OffsetAddr: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_REGION1: + { + int x1 = data & 0x3ff; + int y1 = data >> 10; + //topleft + return QString("Region TL: %1 %2").arg(x1).arg(y1); + } + break; + + case GE_CMD_REGION2: + { + int x2 = data & 0x3ff; + int y2 = data >> 10; + return QString("Region BR: %1 %2").arg(x2).arg(y2); + } + break; + + case GE_CMD_CLIPENABLE: + return QString("Clip Enable: %1").arg(data); + break; + + case GE_CMD_CULLFACEENABLE: + return QString("CullFace Enable: %1").arg(data); + break; + + case GE_CMD_TEXTUREMAPENABLE: + return QString("Texture map enable: %1").arg(data); + break; + + case GE_CMD_LIGHTINGENABLE: + return QString("Lighting enable: %1").arg(data); + break; + + case GE_CMD_FOGENABLE: + return QString("Fog Enable: %1").arg(data); + break; + + case GE_CMD_DITHERENABLE: + return QString("Dither Enable: %1").arg(data); + break; + + case GE_CMD_OFFSETX: + return QString("Offset X: %1").arg(data); + break; + + case GE_CMD_OFFSETY: + return QString("Offset Y: %1").arg(data); + break; + + case GE_CMD_TEXSCALEU: + return QString("Texture U Scale: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXSCALEV: + return QString("Texture V Scale: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXOFFSETU: + return QString("Texture U Offset: %1").arg(getFloat24(data)); + break; + + case GE_CMD_TEXOFFSETV: + return QString("Texture V Offset: %1").arg(getFloat24(data)); + break; + + case GE_CMD_SCISSOR1: + { + int x1 = data & 0x3ff; + int y1 = data >> 10; + return QString("Scissor TL: %1, %2").arg(x1).arg(y1); + } + break; + case GE_CMD_SCISSOR2: + { + int x2 = data & 0x3ff; + int y2 = data >> 10; + return QString("Scissor BR: %1, %2").arg(x2).arg(y2); + } + break; + + case GE_CMD_MINZ: + { + float zMin = getFloat24(data) / 65535.f; + return QString("MinZ: %1").arg(zMin); + } + break; + + case GE_CMD_MAXZ: + { + float zMax = getFloat24(data) / 65535.f; + return QString("MaxZ: %1").arg(zMax); + } + break; + + case GE_CMD_FRAMEBUFPTR: + { + u32 ptr = op & 0xFFE000; + return QString("FramebufPtr: %1").arg(data,8,16,QChar('0')); + } + break; + + case GE_CMD_FRAMEBUFWIDTH: + { + return QString("FramebufWidth: %1").arg(data); + } + break; + + case GE_CMD_FRAMEBUFPIXFORMAT: + return QString("FramebufPixeFormat: %1").arg(data); + break; + + case GE_CMD_TEXADDR0: + case GE_CMD_TEXADDR1: + case GE_CMD_TEXADDR2: + case GE_CMD_TEXADDR3: + case GE_CMD_TEXADDR4: + case GE_CMD_TEXADDR5: + case GE_CMD_TEXADDR6: + case GE_CMD_TEXADDR7: + return QString("Texture address %1: %2").arg(cmd-GE_CMD_TEXADDR0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXBUFWIDTH0: + case GE_CMD_TEXBUFWIDTH1: + case GE_CMD_TEXBUFWIDTH2: + case GE_CMD_TEXBUFWIDTH3: + case GE_CMD_TEXBUFWIDTH4: + case GE_CMD_TEXBUFWIDTH5: + case GE_CMD_TEXBUFWIDTH6: + case GE_CMD_TEXBUFWIDTH7: + return QString("Texture BUFWIDTHess %1: %2").arg(cmd-GE_CMD_TEXBUFWIDTH0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_CLUTADDR: + return QString("CLUT base addr: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_CLUTADDRUPPER: + return QString("CLUT addr upper %1").arg(data,8,16,QChar('0')); + break; + + case GE_CMD_LOADCLUT: + // This could be used to "dirty" textures with clut. + return QString("Clut load"); + break; + + case GE_CMD_TEXMAPMODE: + return QString("Tex map mode: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXSHADELS: + return QString("Tex shade light sources: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_CLUTFORMAT: + { + return QString("Clut format: %1").arg(data,6,16,QChar('0')); + } + break; + + case GE_CMD_TRANSFERSRC: + { + return QString("Block Transfer Src: %1").arg(data,6,16,QChar('0')); + // Nothing to do, the next one prints + } + break; + + case GE_CMD_TRANSFERSRCW: + { + u32 xferSrc = state.transfersrc | ((data&0xFF0000)<<8); + u32 xferSrcW = state.transfersrcw & 1023; + return QString("Block Transfer Src: %1 W: %2").arg(xferSrc,8,16,QChar('0')).arg(xferSrcW); + break; + } + + case GE_CMD_TRANSFERDST: + { + // Nothing to do, the next one prints + return QString("Block Transfer Dst: %1").arg(data,6,16,QChar('0')); + } + break; + + case GE_CMD_TRANSFERDSTW: + { + u32 xferDst= state.transferdst | ((data&0xFF0000)<<8); + u32 xferDstW = state.transferdstw & 1023; + return QString("Block Transfer Dest: %1 W: %2").arg(xferDst,8,16,QChar('0')).arg(xferDstW); + break; + } + + case GE_CMD_TRANSFERSRCPOS: + { + u32 x = (data & 1023)+1; + u32 y = ((data>>10) & 1023)+1; + return QString("Block Transfer Src Rect TL: %1, %2").arg(x).arg(y); + break; + } + + case GE_CMD_TRANSFERDSTPOS: + { + u32 x = (data & 1023)+1; + u32 y = ((data>>10) & 1023)+1; + return QString("Block Transfer Dest Rect TL: %1, %2").arg(x).arg(y); + break; + } + + case GE_CMD_TRANSFERSIZE: + { + u32 w = (data & 1023)+1; + u32 h = ((data>>10) & 1023)+1; + return QString("Block Transfer Rect Size: %1 x %2").arg(w).arg(h); + break; + } + + case GE_CMD_TRANSFERSTART: // Orphis calls this TRXKICK + { + return QString("Block Transfer Start"); + break; + } + + case GE_CMD_TEXSIZE0: + case GE_CMD_TEXSIZE1: + case GE_CMD_TEXSIZE2: + case GE_CMD_TEXSIZE3: + case GE_CMD_TEXSIZE4: + case GE_CMD_TEXSIZE5: + case GE_CMD_TEXSIZE6: + case GE_CMD_TEXSIZE7: + { + int w = 1 << (data & 0xf); + int h = 1 << ((data>>8) & 0xf); + return QString("Texture Size %1: %2, width : %3, height : %4").arg(cmd - GE_CMD_TEXSIZE0).arg(data,6,16,QChar('0')).arg(w).arg(h); + } + break; + + case GE_CMD_ZBUFPTR: + { + u32 ptr = op & 0xFFE000; + return QString("Zbuf Ptr: %1").arg(ptr,6,16,QChar('0')); + } + break; + + case GE_CMD_ZBUFWIDTH: + { + return QString("Zbuf Width: %1").arg(data,6,16,QChar('0')); + } + break; + + case GE_CMD_AMBIENTCOLOR: + return QString("Ambient Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_AMBIENTALPHA: + return QString("Ambient Alpha: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALAMBIENT: + return QString("Material Ambient Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALDIFFUSE: + return QString("Material Diffuse Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALEMISSIVE: + return QString("Material Emissive Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALSPECULAR: + return QString("Material Specular Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALALPHA: + return QString("Material Alpha Color: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MATERIALSPECULARCOEF: + return QString("Material specular coef: %1").arg(getFloat24(data)); + break; + + case GE_CMD_SHADEMODE: + return QString("Shade: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "gouraud" : "flat"); + break; + + case GE_CMD_LIGHTMODE: + return QString("Lightmode: %1 (%2)").arg(data,6,16,QChar('0')).arg(data ? "separate spec" : "single color"); + break; + + case GE_CMD_LIGHTTYPE0: + case GE_CMD_LIGHTTYPE1: + case GE_CMD_LIGHTTYPE2: + case GE_CMD_LIGHTTYPE3: + return QString("Light %1 type: %2").arg(cmd-GE_CMD_LIGHTTYPE0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_LX0:case GE_CMD_LY0:case GE_CMD_LZ0: + case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1: + case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2: + case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3: + { + int n = cmd - GE_CMD_LX0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 pos: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LDX0:case GE_CMD_LDY0:case GE_CMD_LDZ0: + case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1: + case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2: + case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3: + { + int n = cmd - GE_CMD_LDX0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 dir: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LKA0:case GE_CMD_LKB0:case GE_CMD_LKC0: + case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1: + case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2: + case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3: + { + int n = cmd - GE_CMD_LKA0; + int l = n / 3; + int c = n % 3; + float val = getFloat24(data); + return QString("Light %1 %2 att: %3").arg(l).arg(QChar('X')+c).arg(val); + } + break; + + case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3: + case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3: + case GE_CMD_LSC0:case GE_CMD_LSC1:case GE_CMD_LSC2:case GE_CMD_LSC3: + { + float r = (float)(data & 0xff)/255.0f; + float g = (float)((data>>8) & 0xff)/255.0f; + float b = (float)(data>>16)/255.0f; + + int l = (cmd - GE_CMD_LAC0) / 3; + int t = (cmd - GE_CMD_LAC0) % 3; + return QString("Light %1 color %2: %3 %4 %5").arg(l).arg(t).arg(r).arg(g).arg(b); + } + break; + + case GE_CMD_VIEWPORTX1: + case GE_CMD_VIEWPORTY1: + case GE_CMD_VIEWPORTX2: + case GE_CMD_VIEWPORTY2: + return QString("Viewport param %1: %2").arg(cmd-GE_CMD_VIEWPORTX1).arg(getFloat24(data)); + break; + case GE_CMD_VIEWPORTZ1: + { + float zScale = getFloat24(data) / 65535.f; + return QString("Viewport Z scale: %1").arg(zScale); + } + break; + case GE_CMD_VIEWPORTZ2: + { + float zOff = getFloat24(data) / 65535.f; + return QString("Viewport Z pos: %1").arg(zOff); + } + break; + + case GE_CMD_LIGHTENABLE0: + case GE_CMD_LIGHTENABLE1: + case GE_CMD_LIGHTENABLE2: + case GE_CMD_LIGHTENABLE3: + return QString("Light %1 enable: %2").arg(cmd-GE_CMD_LIGHTENABLE0).arg(data); + break; + + case GE_CMD_CULL: + return QString("cull: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_PATCHDIVISION: + { + int patch_div_s = data & 0xFF; + int patch_div_t = (data >> 8) & 0xFF; + return QString("Patch subdivision: %1 x %2").arg(patch_div_s).arg(patch_div_t); + } + break; + + case GE_CMD_PATCHPRIMITIVE: + return QString("Patch Primitive: %1").arg(data); + break; + + case GE_CMD_PATCHFACING: + return QString( "Patch Facing: %1").arg(data); + break; + + case GE_CMD_REVERSENORMAL: + return QString("Reverse normal: %1").arg(data); + break; + + case GE_CMD_MATERIALUPDATE: + return QString("Material Update: %1").arg(data); + break; + + + ////////////////////////////////////////////////////////////////// + // CLEARING + ////////////////////////////////////////////////////////////////// + case GE_CMD_CLEARMODE: + // If it becomes a performance problem, check diff&1 + return QString("Clear mode: %1").arg(data,6,16,QChar('0')); + break; + + + ////////////////////////////////////////////////////////////////// + // ALPHA BLENDING + ////////////////////////////////////////////////////////////////// + case GE_CMD_ALPHABLENDENABLE: + return QString("Alpha blend enable: %1").arg(data); + break; + + case GE_CMD_BLENDMODE: + return QString("Blend mode: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_BLENDFIXEDA: + return QString("Blend fix A: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_BLENDFIXEDB: + return QString("Blend fix B: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_ALPHATESTENABLE: + return QString("Alpha test enable: %1").arg(data); + break; + + case GE_CMD_ALPHATEST: + return QString("Alpha test settings"); + break; + + case GE_CMD_ANTIALIASENABLE: + return QString("Antialias enable: %1").arg(data); + break; + + case GE_CMD_PATCHCULLENABLE: + return QString("Antialias enable: %1").arg(data); + break; + + case GE_CMD_COLORTESTENABLE: + return QString("Color Test enable: %1").arg(data); + break; + + case GE_CMD_LOGICOPENABLE: + return QString("Logic op enable: %1").arg(data); + break; + + case GE_CMD_TEXFUNC: + return QString("TexFunc %1").arg(data&7); + break; + + case GE_CMD_TEXFILTER: + { + int min = data & 7; + int mag = (data >> 8) & 1; + return QString("TexFilter min: %1 mag: %2").arg( min).arg(mag); + } + break; + + case GE_CMD_TEXENVCOLOR: + return QString("TexEnvColor %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXMODE: + return QString("TexMode %1").arg(data,8,16,QChar('0')); + break; + + case GE_CMD_TEXFORMAT: + return QString("TexFormat %1").arg(data,8,16,QChar('0')); + break; + + case GE_CMD_TEXFLUSH: + return QString("TexFlush"); + break; + + case GE_CMD_TEXSYNC: + return QString("TexSync"); + break; + + case GE_CMD_TEXWRAP: + return QString("TexWrap %1").arg(data,8,16,QChar('0')); + break; + + case GE_CMD_TEXLEVEL: + return QString("TexWrap Mode: %1 Offset: %2").arg(data&3).arg(data >> 16); + break; + + case GE_CMD_FOG1: + return QString("Fog1 %1").arg(getFloat24(data)); + break; + + case GE_CMD_FOG2: + return QString( "Fog2 %1").arg(getFloat24(data)); + break; + + case GE_CMD_FOGCOLOR: + return QString("FogColor %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_TEXLODSLOPE: + return QString( "TexLodSlope %1").arg(data,6,16,QChar('0')); + break; + + ////////////////////////////////////////////////////////////////// + // Z/STENCIL TESTING + ////////////////////////////////////////////////////////////////// + + case GE_CMD_ZTESTENABLE: + return QString( "Z test enable: %1").arg(data&1); + break; + + case GE_CMD_STENCILOP: + return QString("Stencil op: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_STENCILTEST: + return QString("Stencil test: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_STENCILTESTENABLE: + return QString("Stencil test enable: %1").arg(data); + break; + + case GE_CMD_ZTEST: + return QString("Z test mode: %1").arg(data); + break; + + case GE_CMD_MORPHWEIGHT0: + case GE_CMD_MORPHWEIGHT1: + case GE_CMD_MORPHWEIGHT2: + case GE_CMD_MORPHWEIGHT3: + case GE_CMD_MORPHWEIGHT4: + case GE_CMD_MORPHWEIGHT5: + case GE_CMD_MORPHWEIGHT6: + case GE_CMD_MORPHWEIGHT7: + { + int index = cmd - GE_CMD_MORPHWEIGHT0; + float weight = getFloat24(data); + return QString("MorphWeight %1 = %2").arg(index).arg(weight); + } + break; + + case GE_CMD_DITH0: + case GE_CMD_DITH1: + case GE_CMD_DITH2: + case GE_CMD_DITH3: + return QString("DitherMatrix %1 = %2").arg(cmd-GE_CMD_DITH0).arg(data,6,16,QChar('0')); + break; + + case GE_CMD_LOGICOP: + return QString("LogicOp: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_ZWRITEDISABLE: + return QString("ZMask: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORTEST: + return QString("ColorTest: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORREF: + return QString("ColorRef: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_COLORTESTMASK: + return QString( "ColorTestMask: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MASKRGB: + return QString("MaskRGB: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_MASKALPHA: + return QString("MaskAlpha: %1").arg(data,6,16,QChar('0')); + break; + + case GE_CMD_WORLDMATRIXNUMBER: + return QString("World # %1").arg(data & 0xF); + break; + + case GE_CMD_WORLDMATRIXDATA: + return QString("World data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_VIEWMATRIXNUMBER: + return QString("VIEW # %1").arg(data & 0xF); + break; + + case GE_CMD_VIEWMATRIXDATA: + return QString("VIEW data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_PROJMATRIXNUMBER: + return QString("PROJECTION # %1").arg(data & 0xF); + break; + + case GE_CMD_PROJMATRIXDATA: + return QString("PROJECTION matrix data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_TGENMATRIXNUMBER: + return QString("TGEN # %1").arg(data & 0xF); + break; + + case GE_CMD_TGENMATRIXDATA: + return QString("TGEN data # %1").arg(getFloat24(data)); + break; + + case GE_CMD_BONEMATRIXNUMBER: + return QString("BONE #%1").arg(data); + break; + + case GE_CMD_BONEMATRIXDATA: + return QString("BONE data #%1 %2").arg(state.boneMatrixNumber & 0x7f).arg(getFloat24(data)); + break; + + default: + return QString("Unknown: %1").arg(op,8,16,QChar('0')); + break; + } +} + + +void Debugger_DisplayList::FillDisplayListCmd(std::map& data, u32 pc, u32 prevAddr, GPUgstate& state) +{ + u32 curPc = pc; + int debugLimit = 10000; // Anti crash if this code is bugged + while(Memory::IsValidAddress(curPc) && debugLimit > 0) + { + if(data.find(curPc) != data.end()) + return; + + u32 op = Memory::ReadUnchecked_U32(curPc); //read from memory + u32 cmd = op >> 24; + u32 data_ = op & 0xFFFFFF; + u32 diff = op ^ gstate.cmdmem[cmd]; + state.cmdmem[cmd] = op; + u32 prevOp = 0; + if(Memory::IsValidAddress(prevAddr)) + Memory::ReadUnchecked_U32(prevAddr); + data[curPc].comment = DisassembleOp(curPc, op, prevOp, state); + data[curPc].addr = curPc; + data[curPc].cmd = cmd; + data[curPc].data = data_; + data[curPc].implementationNotFinished = false; + data[curPc].texAddr = (gstate.texaddr[0] & 0xFFFFF0) | ((gstate.texbufwidth[0]<<8) & 0x0F000000); + data[curPc].fboAddr = state.fbptr & 0xFFFFFF; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF); + data[curPc].vtxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF); + data[curPc].idxAddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + // Add or remove bugged functions for highlight + if(cmd == GE_CMD_BEZIER || + cmd == GE_CMD_SPLINE || + cmd == GE_CMD_BJUMP || + cmd == GE_CMD_BOUNDINGBOX) + { + data[curPc].implementationNotFinished = true; + } + + // We are drawing, save the GPU state for texture, vertex and index list + if(cmd == GE_CMD_PRIM || cmd == GE_CMD_BEZIER || cmd == GE_CMD_SPLINE) + { + drawGPUState.push_back(state); + } + + if(cmd == GE_CMD_JUMP) + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF); + u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF; + FillDisplayListCmd(data, target, prevAddr, state); + return; + } + else if(cmd == GE_CMD_CALL) + { + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (data_ & 0xFFFFFF); + u32 target = (((state.offsetAddr & 0xFFFFFF) << 8) + baseExtended) & 0x0FFFFFFF; + FillDisplayListCmd(data, target, prevAddr, state); + } + else if(cmd == GE_CMD_RET) + { + return; + } + else if(cmd == GE_CMD_FINISH) + { + return; + } + else if(cmd == GE_CMD_END) + { + if(prevOp >> 24 == GE_CMD_FINISH) + return; + } + prevAddr = curPc; + curPc += 4; + debugLimit--; + } +} + +void Debugger_DisplayList::Update() +{ + UpdateRenderBuffer(); + UpdateRenderBufferList(); + UpdateDisplayList(); +} + + +void Debugger_DisplayList::on_displayList_itemClicked(QTreeWidgetItem *item, int column) +{ + displayListRowSelected = item; + ShowDLCode(); +} + +void Debugger_DisplayList::on_stepBtn_clicked() +{ + host->SetGPUStep(true); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_runBtn_clicked() +{ + ui->displayList->clear(); + ui->displayListData->clear(); + host->SetGPUStep(false); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_stopBtn_clicked() +{ + host->SetGPUStep(true); +} + +void Debugger_DisplayList::UpdateRenderBuffer() +{ + EmuThread_LockDraw(true); + + gpu->Flush(); + + int FRAME_WIDTH; + int FRAME_HEIGHT; + u8 *data = 0; + int curTex; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &curTex); + if(currentTextureDisplay == 0) + { + FRAME_WIDTH = pixel_xres; + FRAME_HEIGHT = pixel_yres; + data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4]; + memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4); + if(currentRenderFrameDisplay == 0) + { + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, data); + } + else + { + glReadBuffer(GL_DEPTH_ATTACHMENT); + glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_DEPTH_COMPONENT, GL_FLOAT, data); + } + } + else + { + fbo_get_dimensions(currentTextureDisplay, &FRAME_WIDTH, &FRAME_HEIGHT); + data = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4]; + memset(data,0,FRAME_WIDTH * FRAME_HEIGHT * 4); + if(currentRenderFrameDisplay == 0) + { + fbo_bind_color_as_texture(currentTextureDisplay,0); + glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); + } + } + glBindTexture(GL_TEXTURE_2D, curTex); + + QImage img = QImage(data, FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH*4, QImage::Format_ARGB32).mirrored(false,true); + QPixmap pixmap = QPixmap::fromImage(img); + ui->fboImg->setPixmap(pixmap); + ui->fboImg->setMinimumWidth(pixmap.width() * fboZoomFactor); + ui->fboImg->setMinimumHeight(pixmap.height() * fboZoomFactor); + ui->fboImg->setMaximumWidth(pixmap.width() * fboZoomFactor); + ui->fboImg->setMaximumHeight(pixmap.height() * fboZoomFactor); + + delete[] data; + + EmuThread_LockDraw(false); +} + +void Debugger_DisplayList::on_nextDrawBtn_clicked() +{ + host->SetGPUStep(true, 1); + host->NextGPUStep(); +} + +void Debugger_DisplayList::on_gotoPCBtn_clicked() +{ + if(!displayListRowSelected) + return; + u32 currentPC = displayListRowSelected->data(3, Qt::UserRole).toInt(); + + for(int i = 0; i < ui->displayListData->topLevelItemCount(); i++) + { + if(ui->displayListData->topLevelItem(i)->data(0, Qt::UserRole).toInt() == currentPC) + { + ui->displayListData->setCurrentItem(ui->displayListData->topLevelItem(i)); + } + } +} + +void Debugger_DisplayList::on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column) +{ + mainWindow->GetDialogMemoryTex()->ShowTex(drawGPUState[item->data(0,Qt::UserRole).toInt()]); +} + +void Debugger_DisplayList::on_comboBox_currentIndexChanged(int index) +{ + currentRenderFrameDisplay = index; + UpdateRenderBuffer(); +} + +void Debugger_DisplayList::UpdateRenderBufferList() +{ + emit updateRenderBufferList_(); +} + +void Debugger_DisplayList::UpdateRenderBufferListGUI() +{ + ui->fboList->clear(); + + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,"Framebuffer"); + item->setData(0,Qt::UserRole, 0); + item->setText(1,QString::number(pixel_xres)); + item->setText(2,QString::number(pixel_yres)); + item->setText(3,QString::number(4)); + ui->fboList->addTopLevelItem(item); + + std::vector fboList = gpu->GetFramebufferList(); + + for(int i = 0; i < fboList.size(); i++) + { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,QString("%1").arg(fboList[i].fb_address,8,16,QChar('0'))); + u64 addr = (u64)fboList[i].fbo; + item->setData(0,Qt::UserRole, addr); + item->setData(0,Qt::UserRole+1, fboList[i].fb_address); + item->setText(1,QString::number(fboList[i].width)); + item->setText(2,QString::number(fboList[i].height)); + item->setText(3,QString::number(fboList[i].format)); + + ui->fboList->addTopLevelItem(item); + } +} + +void Debugger_DisplayList::on_fboList_itemClicked(QTreeWidgetItem *item, int column) +{ + u64 addr = item->data(0,Qt::UserRole).toULongLong(); + FBO* fbo = (FBO*)addr; + currentTextureDisplay = fbo; + UpdateRenderBuffer(); +} + +void Debugger_DisplayList::on_nextDLBtn_clicked() +{ + host->SetGPUStep(true,-1); + host->NextGPUStep(); +} + +void Debugger_DisplayList::setCurrentFBO(u32 addr) +{ + for(int i = 0; i < ui->fboList->topLevelItemCount(); i++) + { + if(ui->fboList->topLevelItem(i)->data(0,Qt::UserRole+1).toInt() == addr) + { + for(int j = 0; j < ui->fboList->colorCount(); j++) + ui->fboList->topLevelItem(i)->setTextColor(j,Qt::green); + } + else + { + for(int j = 0; j < ui->fboList->colorCount(); j++) + ui->fboList->topLevelItem(i)->setTextColor(j,Qt::black); + } + } +} + +void Debugger_DisplayList::on_zoommBtn_clicked() +{ + fboZoomFactor *= 0.5; + ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*0.5); + ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*0.5); + ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*0.5); + ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*0.5); +} + +void Debugger_DisplayList::on_zoompBtn_clicked() +{ + fboZoomFactor *= 2; + ui->fboImg->setMinimumWidth(ui->fboImg->minimumWidth()*2); + ui->fboImg->setMinimumHeight(ui->fboImg->minimumHeight()*2); + ui->fboImg->setMaximumWidth(ui->fboImg->minimumWidth()*2); + ui->fboImg->setMaximumHeight(ui->fboImg->minimumHeight()*2); +} + +void Debugger_DisplayList::UpdateVertexInfo() +{ + ui->vertexData->clear(); + + QTreeWidgetItem* item = ui->vertexList->currentItem(); + if(item == 0) + return; + + GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()]; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.vaddr & 0xFFFFFF); + u32 vaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + + VertexDecoder vtcDec; + vtcDec.SetVertexType(state.vertType); + u8 tmp[20*vtcDec.GetDecVtxFmt().stride]; + vtcDec.DecodeVerts(tmp,Memory::GetPointer(vaddr),0,0,0,0,19); + VertexReader vtxRead(tmp,vtcDec.GetDecVtxFmt(),state.vertType); + + for(int i = 0; i < maxVtxDisplay; i++) + { + vtxRead.Goto(i); + QTreeWidgetItem* itemTop = new QTreeWidgetItem(); + itemTop->setText(0,QString::number(i)); + itemTop->setText(1,QString("%1").arg(vaddr+i*vtcDec.GetDecVtxFmt().stride,8,16,QChar('0'))); + ui->vertexData->addTopLevelItem(itemTop); + + if (vtxRead.hasNormal()) + { + float nrm[3]; + vtxRead.ReadNrm(nrm); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Normal"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(nrm[0]).arg(nrm[1]).arg(nrm[2])); + itemTop->addChild(item); + } + if (vtxRead.hasUV()) { + float uv[2]; + vtxRead.ReadUV(uv); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Uv"); + item->setText(2,QString("X: %1, Y: %2").arg(uv[0]).arg(uv[1])); + itemTop->addChild(item); + } + if (vtxRead.hasColor0()) { + float col0[4]; + vtxRead.ReadColor0(col0); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Color0"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col0[0]).arg(col0[1]).arg(col0[2])); + itemTop->addChild(item); + } + if (vtxRead.hasColor0()) { + float col1[3]; + vtxRead.ReadColor1(col1); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Color1"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(col1[0]).arg(col1[1]).arg(col1[2])); + itemTop->addChild(item); + } + float pos[3]; + vtxRead.ReadPos(pos); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(1,"Position"); + item->setText(2,QString("X: %1, Y: %2, Z: %3").arg(pos[0]).arg(pos[1]).arg(pos[2])); + itemTop->addChild(item); + } + for(int i = 0; i < ui->vertexData->columnCount(); i++) + { + ui->vertexData->resizeColumnToContents(i); + } +} + +void Debugger_DisplayList::on_vertexList_itemClicked(QTreeWidgetItem *item, int column) +{ + UpdateVertexInfo(); +} + +void Debugger_DisplayList::on_pushButton_clicked() +{ + maxVtxDisplay += 20; + UpdateVertexInfo(); +} + + +void Debugger_DisplayList::UpdateIndexInfo() +{ + ui->indexData->clear(); + + QTreeWidgetItem* item = ui->indexList->currentItem(); + if(item == 0) + return; + + GPUgstate state = drawGPUState[item->data(0,Qt::UserRole).toInt()]; + u32 baseExtended = ((state.base & 0x0F0000) << 8) | (state.iaddr & 0xFFFFFF); + u32 iaddr = ((state.offsetAddr & 0xFFFFFF) + baseExtended) & 0x0FFFFFFF; + + int sizeIdx = 1; + if((state.vertType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT) + sizeIdx = 2; + + for(int i = 0; i < maxIdxDisplay; i++) + { + QTreeWidgetItem* itemTop = new QTreeWidgetItem(); + itemTop->setText(0,QString::number(i)); + itemTop->setText(1,QString("%1").arg(iaddr+i*sizeIdx,8,16,QChar('0'))); + int idx = 0; + if(sizeIdx == 1) + idx = Memory::Read_U8(iaddr+i*sizeIdx); + else + idx = Memory::Read_U16(iaddr+i*sizeIdx); + itemTop->setText(2,QString::number(idx)); + ui->indexData->addTopLevelItem(itemTop); + } + for(int i = 0; i < ui->indexData->columnCount(); i++) + { + ui->indexData->resizeColumnToContents(i); + } +} + + +void Debugger_DisplayList::on_nextIdx_clicked() +{ + maxIdxDisplay += 20; + UpdateIndexInfo(); +} + +void Debugger_DisplayList::on_indexList_itemClicked(QTreeWidgetItem *item, int column) +{ + UpdateIndexInfo(); +} diff --git a/Qt/debugger_displaylist.h b/Qt/debugger_displaylist.h new file mode 100644 index 000000000000..e237a84f311e --- /dev/null +++ b/Qt/debugger_displaylist.h @@ -0,0 +1,114 @@ +#ifndef DEBUGGER_DISPLAYLIST_H +#define DEBUGGER_DISPLAYLIST_H + +#include "Core/Debugger/DebugInterface.h" +#include +#include +#include "GPU/GPUState.h" +#include "native/gfx_es2/fbo.h" + +class MainWindow; +namespace Ui { +class Debugger_DisplayList; +} + + +class DListLine +{ +public: + u32 addr; + u32 cmd; + u32 data; + QString comment; + bool implementationNotFinished; + u32 texAddr; + u32 fboAddr; + u32 vtxAddr; + int vtxStart; + int vtxCount; + u32 idxAddr; + int idxStart; + int idxCount; +}; + +class Debugger_DisplayList : public QDialog +{ + Q_OBJECT + +public: + explicit Debugger_DisplayList(DebugInterface *_cpu, MainWindow *mainWindow_, QWidget *parent = 0); + ~Debugger_DisplayList(); + + void UpdateDisplayList(); + + void ShowDLCode(); + void FillDisplayListCmd(std::map &data, u32 pc, u32 prev, GPUgstate &state); + void Update(); + void UpdateRenderBuffer(); + void UpdateRenderBufferList(); + void UpdateVertexInfo(); + void UpdateIndexInfo(); +protected: + void showEvent(QShowEvent *); + +signals: + void updateDisplayList_(); + void updateRenderBufferList_(); + +private slots: + void UpdateDisplayListGUI(); + void UpdateRenderBufferListGUI(); + void releaseLock(); + + void on_displayList_itemClicked(QTreeWidgetItem *item, int column); + + void on_stepBtn_clicked(); + + void on_runBtn_clicked(); + + void on_stopBtn_clicked(); + + void on_nextDrawBtn_clicked(); + + void on_gotoPCBtn_clicked(); + + void on_texturesList_itemDoubleClicked(QTreeWidgetItem *item, int column); + + void on_comboBox_currentIndexChanged(int index); + + void on_fboList_itemClicked(QTreeWidgetItem *item, int column); + + void on_nextDLBtn_clicked(); + void setCurrentFBO(u32 addr); + + void on_zoommBtn_clicked(); + + void on_zoompBtn_clicked(); + + void on_vertexList_itemClicked(QTreeWidgetItem *item, int column); + + void on_pushButton_clicked(); + + void on_nextIdx_clicked(); + + void on_indexList_itemClicked(QTreeWidgetItem *item, int column); + +private: + QString DisassembleOp(u32 pc, u32 op, u32 prev, const GPUgstate &state); + + Ui::Debugger_DisplayList *ui; + DebugInterface* cpu; + MainWindow* mainWindow; + QTreeWidgetItem* displayListRowSelected; + int currentRenderFrameDisplay; + FBO* currentTextureDisplay; + float fboZoomFactor; + int maxVtxDisplay; + int maxIdxDisplay; + + std::vector drawGPUState; + std::map vtxBufferSize; + std::map idxBufferSize; +}; + +#endif // DEBUGGER_DISPLAYLIST_H diff --git a/Qt/debugger_displaylist.ui b/Qt/debugger_displaylist.ui new file mode 100644 index 000000000000..77a3ee5415b2 --- /dev/null +++ b/Qt/debugger_displaylist.ui @@ -0,0 +1,527 @@ + + + Debugger_DisplayList + + + + 0 + 0 + 795 + 506 + + + + Dialog + + + + + + Qt::Horizontal + + + + Qt::Vertical + + + + DisplayList + + + + + + Qt::CustomContextMenu + + + false + + + false + + + false + + + 30 + + + + Id + + + + + Status + + + + + Start Address + + + + + Current Address + + + + + + + + + + Run + + + + + + + Stop + + + + + + + Next DL + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + + Commands + + + + + + false + + + false + + + false + + + 2 + + + false + + + + 1 + + + + + 2 + + + + + + + + + + Step + + + + + + + Next Draw + + + + + + + Goto PC + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Textures + + + + + + + Address + + + + + Width + + + + + Height + + + + + Format + + + + + + + + + Vertex Buffer + + + + + + 30 + + + + Address + + + + + Coord Type + + + + + Number Morph + + + + + Number Weights + + + + + Has Weight + + + + + Has Position + + + + + Has Normal + + + + + Has Color + + + + + Has UV + + + + + + + + 30 + + + + Idx + + + + + Address + + + + + Values + + + + + + + + + + Next 20 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Index Buffer + + + + + + Qt::Vertical + + + + + Address + + + + + + 30 + + + + Idx + + + + + Adress + + + + + Value + + + + + + + + + + + Next 20 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Framebuffer + + + + + + Qt::Vertical + + + + + 0 + 0 + + + + + VAddress + + + + + Width + + + + + Height + + + + + Format + + + + + + + 0 + 0 + + + + true + + + + + 0 + 0 + 375 + 76 + + + + + + + QFrame::Box + + + + + + true + + + + + + + + + + + + + + Display : + + + + + + + + Color + + + + + Depth + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Zoom- + + + + + + + Zoom+ + + + + + + + + + + + + + + diff --git a/Qt/debugger_memory.cpp b/Qt/debugger_memory.cpp index 3f73ccefd98e..3b5cdedf08d8 100644 --- a/Qt/debugger_memory.cpp +++ b/Qt/debugger_memory.cpp @@ -51,9 +51,7 @@ void Debugger_Memory::Goto(u32 addr) void Debugger_Memory::on_editAddress_textChanged(const QString &arg1) { - u32 addr; - sscanf(arg1.toStdString().c_str(),"%08x",&addr); - ui->memView->gotoAddr(addr & ~3); + ui->memView->gotoAddr(arg1.toInt(0,16) & ~3); } void Debugger_Memory::on_normalBtn_clicked() @@ -83,7 +81,7 @@ void Debugger_Memory::NotifyMapLoaded() if(symbolMap.GetSymbolType(i) & ST_DATA) { QListWidgetItem* item = new QListWidgetItem(); - item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QVariant(symbolMap.GetSymbolSize(i)).toString() +")"); + item->setText(QString(symbolMap.GetSymbolName(i)) + " ("+ QString::number(symbolMap.GetSymbolSize(i)) +")"); item->setData(Qt::UserRole, symbolMap.GetAddress(i)); ui->symbols->addItem(item); } diff --git a/Qt/debugger_memorytex.cpp b/Qt/debugger_memorytex.cpp new file mode 100644 index 000000000000..bc9ea6272d0a --- /dev/null +++ b/Qt/debugger_memorytex.cpp @@ -0,0 +1,93 @@ +#include "debugger_memorytex.h" +#include "gfx_es2/gl_state.h" +#include "gfx/gl_common.h" +#include "gfx/gl_lost_manager.h" +#include "ui_debugger_memorytex.h" +#include "Core/MemMap.h" +#include +#include +#include "Core/HLE/sceDisplay.h" +#include "GPU/GPUInterface.h" +#include "EmuThread.h" +#include "base/display.h" + +Debugger_MemoryTex::Debugger_MemoryTex(QWidget *parent) : + QDialog(parent), + ui(new Ui::Debugger_MemoryTex) +{ + ui->setupUi(this); +} + +Debugger_MemoryTex::~Debugger_MemoryTex() +{ + delete ui; +} + + +void Debugger_MemoryTex::showEvent(QShowEvent *) +{ + +#ifdef Q_WS_X11 + // Hack to remove the X11 crash with threaded opengl when opening the first dialog + EmuThread_LockDraw(true); + QTimer::singleShot(100, this, SLOT(releaseLock())); +#endif +} + +void Debugger_MemoryTex::releaseLock() +{ + EmuThread_LockDraw(false); +} + + +void Debugger_MemoryTex::ShowTex(const GPUgstate &state) +{ + ui->texaddr->setText(QString("%1").arg(state.texaddr[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texbufwidth0->setText(QString("%1").arg(state.texbufwidth[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texformat->setText(QString("%1").arg(state.texformat & 0xFFFFFF,8,16,QChar('0'))); + ui->texsize->setText(QString("%1").arg(state.texsize[0] & 0xFFFFFF,8,16,QChar('0'))); + ui->texmode->setText(QString("%1").arg(state.texmode & 0xFFFFFF,8,16,QChar('0'))); + ui->clutformat->setText(QString("%1").arg(state.clutformat & 0xFFFFFF,8,16,QChar('0'))); + ui->clutaddr->setText(QString("%1").arg(state.clutaddr & 0xFFFFFF,8,16,QChar('0'))); + ui->clutaddrupper->setText(QString("%1").arg(state.clutaddrupper & 0xFFFFFF,8,16,QChar('0'))); + ui->loadclut->setText(QString("%1").arg(state.loadclut & 0xFFFFFF,8,16,QChar('0'))); + on_readBtn_clicked(); + + show(); +} + +void Debugger_MemoryTex::on_readBtn_clicked() +{ + EmuThread_LockDraw(true); + + GPUgstate state; + state.texaddr[0] = ui->texaddr->text().toInt(0,16); + state.texbufwidth[0] = ui->texbufwidth0->text().toInt(0,16); + state.texformat = ui->texformat->text().toInt(0,16); + state.texsize[0] = ui->texsize->text().toInt(0,16); + state.texmode = ui->texmode->text().toInt(0,16); + state.clutformat = ui->clutformat->text().toInt(0,16); + state.clutaddr = ui->clutaddr->text().toInt(0,16); + state.clutaddrupper = ui->clutaddrupper->text().toInt(0,16); + state.loadclut = ui->loadclut->text().toInt(0,16); + int w = 1 << (state.texsize[0] & 0xf); + int h = 1 << ((state.texsize[0]>>8) & 0xf); + uchar* newData = new uchar[w*h*4]; + + if(gpu->DecodeTexture(newData, state)) + { + QImage img = QImage(newData, w, h, w*4, QImage::Format_ARGB32); // EmuThread_GrabBackBuffer(); + + QPixmap pixmap = QPixmap::fromImage(img); + ui->textureImg->setPixmap(pixmap); + ui->textureImg->setMinimumWidth(pixmap.width()); + ui->textureImg->setMinimumHeight(pixmap.height()); + ui->textureImg->setMaximumWidth(pixmap.width()); + ui->textureImg->setMaximumHeight(pixmap.height()); + } + + delete[] newData; + EmuThread_LockDraw(false); + + +} diff --git a/Qt/debugger_memorytex.h b/Qt/debugger_memorytex.h new file mode 100644 index 000000000000..c04677e8d2e2 --- /dev/null +++ b/Qt/debugger_memorytex.h @@ -0,0 +1,30 @@ +#ifndef DEBUGGER_MEMORYTEX_H +#define DEBUGGER_MEMORYTEX_H + +#include +#include "GPU/GPUState.h" + +namespace Ui { +class Debugger_MemoryTex; +} + +class Debugger_MemoryTex : public QDialog +{ + Q_OBJECT + +public: + explicit Debugger_MemoryTex(QWidget *parent = 0); + ~Debugger_MemoryTex(); + + void ShowTex(const GPUgstate& state); +protected: + void showEvent(QShowEvent *); +private slots: + void releaseLock(); + void on_readBtn_clicked(); + +private: + Ui::Debugger_MemoryTex *ui; +}; + +#endif // DEBUGGER_MEMORYTEX_H diff --git a/Qt/debugger_memorytex.ui b/Qt/debugger_memorytex.ui new file mode 100644 index 000000000000..b16301022215 --- /dev/null +++ b/Qt/debugger_memorytex.ui @@ -0,0 +1,177 @@ + + + Debugger_MemoryTex + + + + 0 + 0 + 768 + 546 + + + + Dialog + + + + + + Qt::Horizontal + + + + + + + + + TexAddr + + + + + + + TexBufWidth0 + + + + + + + TexFormat + + + + + + + TexSize + + + + + + + ClutFormat + + + + + + + ClutAddr + + + + + + + ClutAddrUpper + + + + + + + LoadClut + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TexMode + + + + + + + + + + + + + + Read + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + true + + + + + 0 + 0 + 76 + 526 + + + + + + + QFrame::Box + + + + + + + + + + + + + + + + diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 8f8efc22690b..d2980033f1d1 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -28,7 +28,9 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow), nextState(CORE_POWERDOWN), dialogDisasm(0), - memoryWindow(0) + memoryWindow(0), + memoryTexWindow(0), + displaylistWindow(0) { ui->setupUi(this); qApp->installEventFilter(this); @@ -206,6 +208,8 @@ void MainWindow::Boot() on_action_OptionsFullScreen_triggered(); memoryWindow = new Debugger_Memory(currentDebugMIPS, this, this); + memoryTexWindow = new Debugger_MemoryTex(this); + displaylistWindow = new Debugger_DisplayList(currentDebugMIPS, this, this); if (dialogDisasm) dialogDisasm->NotifyMapLoaded(); @@ -259,13 +263,12 @@ void MainWindow::UpdateMenus() ui->action_FileLoadStateFile->setEnabled(!enable); ui->action_FileQuickloadState->setEnabled(!enable); ui->action_FileQuickSaveState->setEnabled(!enable); - ui->action_CPUDynarec->setEnabled(enable); - ui->action_CPUInterpreter->setEnabled(enable); - ui->action_CPUFastInterpreter->setEnabled(enable); ui->action_EmulationStop->setEnabled(!enable); ui->action_DebugDumpFrame->setEnabled(!enable); ui->action_DebugDisassembly->setEnabled(!enable); ui->action_DebugMemoryView->setEnabled(!enable); + ui->action_DebugMemoryViewTexture->setEnabled(!enable); + ui->action_DebugDisplayList->setEnabled(!enable); ui->action_OptionsScreen1x->setChecked(0 == (g_Config.iWindowZoom - 1)); ui->action_OptionsScreen2x->setChecked(1 == (g_Config.iWindowZoom - 1)); @@ -354,6 +357,10 @@ void MainWindow::on_action_EmulationStop_triggered() dialogDisasm->close(); if(memoryWindow && memoryWindow->isVisible()) memoryWindow->close(); + if(memoryTexWindow && memoryTexWindow->isVisible()) + memoryTexWindow->close(); + if(displaylistWindow && displaylistWindow->isVisible()) + displaylistWindow->close(); EmuThread_StopGame(); SetGameTitle(""); @@ -932,6 +939,10 @@ void MainWindow::on_action_EmulationReset_triggered() dialogDisasm->close(); if(memoryWindow) memoryWindow->close(); + if(memoryTexWindow) + memoryTexWindow->close(); + if(displaylistWindow) + displaylistWindow->close(); EmuThread_StopGame(); @@ -1016,3 +1027,15 @@ void MainWindow::on_action_Sound_triggered() g_Config.bEnableSound = !g_Config.bEnableSound; UpdateMenus(); } + +void MainWindow::on_action_DebugMemoryViewTexture_triggered() +{ + if(memoryTexWindow) + memoryTexWindow->show(); +} + +void MainWindow::on_action_DebugDisplayList_triggered() +{ + if(displaylistWindow) + displaylistWindow->show(); +} diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 013bb54e1be5..d2de2879276a 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -8,6 +8,8 @@ #include "input/input_state.h" #include "debugger_disasm.h" #include "debugger_memory.h" +#include "debugger_memorytex.h" +#include "debugger_displaylist.h" #include "controls.h" #include "gamepaddialog.h" @@ -33,6 +35,8 @@ class MainWindow : public QMainWindow Debugger_Disasm* GetDialogDisasm() { return dialogDisasm; } Debugger_Memory* GetDialogMemory() { return memoryWindow; } + Debugger_MemoryTex* GetDialogMemoryTex() { return memoryTexWindow; } + Debugger_DisplayList* GetDialogDisplaylist() { return displaylistWindow; } CoreState GetNextState() { return nextState; } void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *); @@ -169,6 +173,10 @@ private slots: void on_action_Sound_triggered(); + void on_action_DebugMemoryViewTexture_triggered(); + + void on_action_DebugDisplayList_triggered(); + private: void loadLanguage(const QString &language); void createLanguageMenu(); @@ -188,6 +196,8 @@ private slots: Debugger_Disasm *dialogDisasm; Debugger_Memory *memoryWindow; + Debugger_MemoryTex *memoryTexWindow; + Debugger_DisplayList *displaylistWindow; Controls* controls; GamePadDialog* gamePadDlg; diff --git a/Qt/mainwindow.ui b/Qt/mainwindow.ui index 10f40c73a77e..a6ef9df025a5 100644 --- a/Qt/mainwindow.ui +++ b/Qt/mainwindow.ui @@ -44,7 +44,7 @@ 0 0 800 - 21 + 23 @@ -83,8 +83,10 @@ + + @@ -616,6 +618,11 @@ Memory View Texture... + + + DisplayList... + + true From 3a00e0b9cced423766dc7e52be0f70a1e9546da7 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Sun, 17 Feb 2013 01:53:55 +0100 Subject: [PATCH 09/18] Oops, too much line deleted --- Qt/mainwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index d2980033f1d1..c6b45a5dcc4a 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -263,6 +263,8 @@ void MainWindow::UpdateMenus() ui->action_FileLoadStateFile->setEnabled(!enable); ui->action_FileQuickloadState->setEnabled(!enable); ui->action_FileQuickSaveState->setEnabled(!enable); + ui->action_CPUDynarec->setEnabled(enable); + ui->action_CPUInterpreter->setEnabled(enable); ui->action_EmulationStop->setEnabled(!enable); ui->action_DebugDumpFrame->setEnabled(!enable); ui->action_DebugDisassembly->setEnabled(!enable); From f41b3f7cf1bd0db390a3ab18100c66f71917692a Mon Sep 17 00:00:00 2001 From: raven02 Date: Sun, 17 Feb 2013 09:45:20 +0800 Subject: [PATCH 10/18] sceSAS style & simplification --- Core/HLE/sceSas.cpp | 140 ++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 78 deletions(-) diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 91e4b047f95b..26ad93e6abcd 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -61,9 +61,9 @@ void __SasShutdown() { } -u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) -{ +u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) { INFO_LOG(HLE,"sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate); + sas->SetGrainSize(grainSize); sas->maxVoices = maxVoices; sas->outputMode = outputMode; @@ -75,42 +75,43 @@ u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampl return 0; } -u32 sceSasGetEndFlag(u32 core) -{ +u32 sceSasGetEndFlag(u32 core) { u32 endFlag = 0; for (int i = 0; i < sas->maxVoices; i++) { if (!sas->voices[i].playing) endFlag |= (1 << i); } + DEBUG_LOG(HLE,"sceSasGetEndFlag(%08x)", endFlag); return endFlag; } // Runs the mixer -u32 _sceSasCore(u32 core, u32 outAddr) -{ +u32 _sceSasCore(u32 core, u32 outAddr) { DEBUG_LOG(HLE,"sceSasCore(%08x, %08x)", core, outAddr); + if (!Memory::IsValidAddress(outAddr)) { return ERROR_SAS_INVALID_PARAMETER; } + Memory::Memset(outAddr, 0, sas->GetGrainSize() * 2 * 2); sas->Mix(outAddr); return 0; } // Another way of running the mixer, what was the difference again? -u32 _sceSasCoreWithMix(u32 core, u32 outAddr, int leftVolume, int rightVolume) -{ +u32 _sceSasCoreWithMix(u32 core, u32 outAddr, int leftVolume, int rightVolume) { DEBUG_LOG(HLE,"sceSasCoreWithMix(%08x, %08x, %i, %i)", core , outAddr, leftVolume, rightVolume); + if (!Memory::IsValidAddress(outAddr)) { return ERROR_SAS_INVALID_PARAMETER; } + sas->Mix(outAddr); return 0; } -u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) -{ +u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) { DEBUG_LOG(HLE,"sceSasSetVoice(%08x, %i, %08x, %i, %i)", core, voiceNum, vagAddr, size, loop); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -168,8 +169,7 @@ u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loop) return 0; } -u32 sceSasGetPauseFlag(u32 core) -{ +u32 sceSasGetPauseFlag(u32 core) { u32 pauseFlag = 0; for (int i = 0; i < sas->maxVoices; i++) { if (sas->voices[i].paused) @@ -180,24 +180,21 @@ u32 sceSasGetPauseFlag(u32 core) return pauseFlag; } -u32 sceSasSetPause(u32 core, int voicebit, int pause) -{ +u32 sceSasSetPause(u32 core, int voicebit, int pause) { DEBUG_LOG(HLE,"sceSasSetPause(%08x, %08x, %i)", core, voicebit, pause); + for (int i = 0; voicebit != 0; i++, voicebit >>= 1) { if (i < PSP_SAS_VOICES_MAX && i >= 0) { if ((voicebit & 1) != 0) sas->voices[i].paused = pause ? true : false; - } - // TODO: Correct error code? Mimana crashes otherwise. - else + } else // TODO: Correct error code? Mimana crashes otherwise. return ERROR_SAS_INVALID_VOICE; } return 0; } -u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) -{ +u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) { DEBUG_LOG(HLE,"sceSasSetVolume(%08x, %i, %i, %i, %i, %i)", core, voiceNum, leftVol, rightVol, effectLeftVol, effectRightVol); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -213,8 +210,7 @@ u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effec return 0; } -u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) -{ +u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { DEBUG_LOG(HLE,"sceSasSetPitch(%08x, %i, %i)", core, voiceNum, pitch); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -228,8 +224,7 @@ u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) return 0; } -u32 sceSasSetKeyOn(u32 core, int voiceNum) -{ +u32 sceSasSetKeyOn(u32 core, int voiceNum) { DEBUG_LOG(HLE,"sceSasSetKeyOn(%08x, %i)", core, voiceNum); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -237,39 +232,38 @@ u32 sceSasSetKeyOn(u32 core, int voiceNum) return ERROR_SAS_INVALID_VOICE; } - SasVoice &v = sas->voices[voiceNum]; if (sas->voices[voiceNum].paused) { return ERROR_SAS_VOICE_PAUSED; } + SasVoice &v = sas->voices[voiceNum]; v.KeyOn(); return 0; } // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! -u32 sceSasSetKeyOff(u32 core, int voiceNum) -{ +u32 sceSasSetKeyOff(u32 core, int voiceNum) { if (voiceNum == -1) { // TODO: Some games (like Every Extend Extra) deliberately pass voiceNum = -1. Does that mean all voices? for now let's ignore. DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i) - voiceNum = -1???", core, voiceNum); return 0; - } else if (voiceNum < 0 || voiceNum >= PSP_SAS_VOICES_MAX) { + } else if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } else { DEBUG_LOG(HLE,"sceSasSetKeyOff(%08x, %i)", core, voiceNum); - SasVoice &v = sas->voices[voiceNum]; + if (sas->voices[voiceNum].paused) { return ERROR_SAS_VOICE_PAUSED; } + SasVoice &v = sas->voices[voiceNum]; v.KeyOff(); return 0; } } -u32 sceSasSetNoise(u32 core, int voiceNum, int freq) -{ +u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { DEBUG_LOG(HLE,"sceSasSetNoise(%08x, %i, %i)", core, voiceNum, freq); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -284,8 +278,7 @@ u32 sceSasSetNoise(u32 core, int voiceNum, int freq) return 0; } -u32 sceSasSetSL(u32 core, int voiceNum, int level) -{ +u32 sceSasSetSL(u32 core, int voiceNum, int level) { DEBUG_LOG(HLE,"sceSasSetSL(%08x, %i, %i)", core, voiceNum, level); if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -298,8 +291,7 @@ u32 sceSasSetSL(u32 core, int voiceNum, int level) return 0; } -u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) -{ +u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) { DEBUG_LOG(HLE,"0=sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a, d, s, r) if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -315,8 +307,7 @@ u32 sceSasSetADSR(u32 core, int voiceNum, int flag , int a, int d, int s, int r) return 0; } -u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) -{ +u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) { DEBUG_LOG(HLE,"sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x)",core, voiceNum, flag, a,d,s,r) if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { @@ -333,21 +324,23 @@ u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int } -u32 sceSasSetSimpleADSR(u32 core, u32 voiceNum, u32 ADSREnv1, u32 ADSREnv2) -{ +u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv2) { DEBUG_LOG(HLE,"sasSetSimpleADSR(%08x, %i, %08x, %08x)", core, voiceNum, ADSREnv1, ADSREnv2); + + if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { + WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); + return ERROR_SAS_INVALID_VOICE; + } + SasVoice &v = sas->voices[voiceNum]; v.envelope.SetSimpleEnvelope(ADSREnv1 & 0xFFFF, ADSREnv2 & 0xFFFF); return 0; } -u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum) -{ - // Spam reduction - if (voiceNum == 17) { - DEBUG_LOG(HLE,"sceSasGetEnvelopeHeight(%08x, %i)", core, voiceNum); - } - if (voiceNum >= PSP_SAS_VOICES_MAX) { +u32 sceSasGetEnvelopeHeight(u32 core, int voiceNum) { + DEBUG_LOG(HLE,"sceSasGetEnvelopeHeight(%08x, %i)", core, voiceNum); + + if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; } @@ -356,105 +349,96 @@ u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum) return v.envelope.GetHeight(); } -u32 sceSasRevType(u32 core, int type) -{ +u32 sceSasRevType(u32 core, int type) { DEBUG_LOG(HLE,"sceSasRevType(%08x, %i)", core, type); sas->waveformEffect.type = type; return 0; } -u32 sceSasRevParam(u32 core, int delay, int feedback) -{ +u32 sceSasRevParam(u32 core, int delay, int feedback) { DEBUG_LOG(HLE,"sceSasRevParam(%08x, %i, %i)", core, delay, feedback); sas->waveformEffect.delay = delay; sas->waveformEffect.feedback = feedback; return 0; } -u32 sceSasRevEVOL(u32 core, int lv, int rv) -{ +u32 sceSasRevEVOL(u32 core, int lv, int rv) { DEBUG_LOG(HLE,"sceSasRevEVOL(%08x, %i, %i)", core, lv, rv); sas->waveformEffect.leftVol = lv; sas->waveformEffect.rightVol = rv; return 0; } -u32 sceSasRevVON(u32 core, int dry, int wet) -{ +u32 sceSasRevVON(u32 core, int dry, int wet) { DEBUG_LOG(HLE,"sceSasRevVON(%08x, %i, %i)", core, dry, wet); sas->waveformEffect.isDryOn = (dry > 0); sas->waveformEffect.isWetOn = (wet > 0); return 0; } -u32 sceSasGetGrain(u32 core) -{ +u32 sceSasGetGrain(u32 core) { DEBUG_LOG(HLE,"sceSasGetGrain(%08x)", core); return sas->GetGrainSize(); } -u32 sceSasSetGrain(u32 core, int grain) -{ +u32 sceSasSetGrain(u32 core, int grain) { INFO_LOG(HLE,"sceSasSetGrain(%08x, %i)", core, grain); sas->SetGrainSize(grain); return 0; } -u32 sceSasGetOutputMode(u32 core) -{ +u32 sceSasGetOutputMode(u32 core) { DEBUG_LOG(HLE,"sceSasGetOutputMode(%08x)", core); return sas->outputMode; } -u32 sceSasSetOutputMode(u32 core, u32 outputMode) -{ +u32 sceSasSetOutputMode(u32 core, u32 outputMode) { DEBUG_LOG(HLE,"sceSasSetOutputMode(%08x, %i)", core, outputMode); sas->outputMode = outputMode; return 0; } -u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) -{ +u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { DEBUG_LOG(HLE,"sceSasGetAllEnvelopeHeights(%08x, %i)", core, heightsAddr); - if (Memory::IsValidAddress(heightsAddr)) { - for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { + + if (!Memory::IsValidAddress(heightsAddr)) { + return ERROR_SAS_INVALID_PARAMETER; + } + + for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { int voiceHeight = sas->voices[i].envelope.GetHeight(); Memory::Write_U32(voiceHeight, heightsAddr + i * 4); - } } + return 0; } -u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown) -{ +u32 sceSasSetTriangularWave(u32 sasCore, int voice, int unknown) { ERROR_LOG(HLE,"UNIMPL sceSasSetTriangularWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } -u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) -{ +u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) { ERROR_LOG(HLE,"UNIMPL sceSasSetSteepWave(%08x, %i, %i)", sasCore, voice, unknown); return 0; } -u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context) -{ +u32 __sceSasSetVoiceATRAC3(u32 core, int voice, int atrac3Context) { ERROR_LOG(HLE,"UNIMPL __sceSasSetVoiceATRAC3(%08x, %i, %i)", core, voice, atrac3Context); return 0; } -u32 __sceSasConcatenateATRAC3(u32 core, int voice, u32 atrac3DataAddr, int atrac3DataLength) -{ +u32 __sceSasConcatenateATRAC3(u32 core, int voice, u32 atrac3DataAddr, int atrac3DataLength) { ERROR_LOG(HLE,"UNIMPL __sceSasConcatenateATRAC3(%08x, %i, %i)", core, voice, atrac3DataAddr, atrac3DataLength); return 0; } -u32 __sceSasUnsetATRAC3(u32 core, int voice) -{ +u32 __sceSasUnsetATRAC3(u32 core, int voice) { ERROR_LOG(HLE, "UNIMPL __sceSasUnsetATRAC3(%08x, %i)", core, voice); return 0; } + const HLEFunction sceSasCore[] = { {0x42778a9f, WrapU_UUUUU, "__sceSasInit"}, @@ -468,8 +452,8 @@ const HLEFunction sceSasCore[] = {0x019b25eb, WrapU_UIIIIII, "__sceSasSetADSR"}, {0x9ec3676a, WrapU_UIIIIII, "__sceSasSetADSRmode"}, {0x5f9529f6, WrapU_UII, "__sceSasSetSL"}, - {0x74ae582a, WrapU_UU, "__sceSasGetEnvelopeHeight"}, - {0xcbcd4f79, WrapU_UUUU, "__sceSasSetSimpleADSR"}, + {0x74ae582a, WrapU_UI, "__sceSasGetEnvelopeHeight"}, + {0xcbcd4f79, WrapU_UIUU, "__sceSasSetSimpleADSR"}, {0xa0cf2fa4, WrapU_UI, "__sceSasSetKeyOff"}, {0x76f01aca, WrapU_UI, "__sceSasSetKeyOn"}, {0xf983b186, WrapU_UII, "__sceSasRevVON"}, From 6eae8ed36a737a92248852b1d42353915502049d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 19:57:35 -0800 Subject: [PATCH 11/18] Disable VDot and Vec3 in x86 jit, broke things. --- Core/MIPS/x86/CompVFPU.cpp | 4 ++-- Core/MIPS/x86/RegCacheFPU.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 958f6baf3763..8784d2cafcf8 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -311,7 +311,7 @@ void Jit::Comp_SVQ(u32 op) } void Jit::Comp_VDot(u32 op) { - CONDITIONAL_DISABLE; + DISABLE; // WARNING: No prefix support! if (js.MayHavePrefix()) { @@ -368,7 +368,7 @@ void Jit::Comp_VDot(u32 op) { } void Jit::Comp_VecDo3(u32 op) { - CONDITIONAL_DISABLE; + DISABLE; // WARNING: No prefix support! if (js.MayHavePrefix()) diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index 429c25b1486d..af5d2f495323 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -35,7 +35,6 @@ enum { TEMP1 = TEMP0 + 1, TEMP2 = TEMP0 + 2, TEMP3 = TEMP0 + 3, - TEMP4 = TEMP0 + 4, NUM_MIPS_FPRS = 32 + 128 + NUM_TEMPS, }; From 0fdc975fded82130f31825daafe6eaec30668abf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 20:22:08 -0800 Subject: [PATCH 12/18] Fix wrong type in x86 jit fpu/vfpu load store. --- Core/MIPS/x86/CompFPU.cpp | 2 +- Core/MIPS/x86/CompVFPU.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index f5ac3226ea8e..bee31435cc9f 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -87,7 +87,7 @@ void Jit::Comp_FPU3op(u32 op) } } -static u32 GC_ALIGNED16(ssLoadStoreTemp[1]); +static u32 GC_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_FPULS(u32 op) { diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 8784d2cafcf8..8da64f698797 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -163,7 +163,7 @@ bool DestRegOverlaps(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) return false; } -static u32 GC_ALIGNED16(ssLoadStoreTemp[1]); +static u32 GC_ALIGNED16(ssLoadStoreTemp); void Jit::Comp_SV(u32 op) { CONDITIONAL_DISABLE; From d99c9fb2ff2bf22eee63d884ca031a5434d35f28 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 17 Feb 2013 15:23:56 +1000 Subject: [PATCH 13/18] Fix Symbian JIT + FastMem by using a mapped virtual address RChunk. --- Common/MemArena.cpp | 54 +++++++++++++++++++++------------------- Common/MemArena.h | 8 ++++++ Common/MemoryUtil.h | 5 ---- Core/MIPS/ARM/ArmAsm.cpp | 4 --- Core/MemMap.h | 4 +-- 5 files changed, 39 insertions(+), 36 deletions(-) diff --git a/Common/MemArena.cpp b/Common/MemArena.cpp index dcb0c82e51a5..4fabb11237ed 100644 --- a/Common/MemArena.cpp +++ b/Common/MemArena.cpp @@ -131,8 +131,6 @@ void MemArena::GrabLowMemSpace(size_t size) ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); return; } -#elif defined(UNUSABLE_MMAP) - // Do nothing as we are using malloc() #else mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); @@ -157,8 +155,9 @@ void MemArena::ReleaseSpace() #ifdef _WIN32 CloseHandle(hMemoryMapping); hMemoryMapping = 0; -#elif defined(UNUSABLE_MMAP) - // Do nothing as we are using malloc() +#elif defined(__SYMBIAN32__) + memmap->Close(); + delete memmap; #else close(fd); #endif @@ -170,20 +169,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base) #ifdef _WIN32 size = roundup(size); void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); - if (!ptr) { - //ERROR_LOG(MEMMAP, "Failed to map memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg()); - } else { - //ERROR_LOG(MEMMAP, "Mapped memory: %08x %08x %08x : %s", (u32)offset, (u32)size, (u32)base, GetLastErrorMsg()); - } return ptr; -#elif defined(UNUSABLE_MMAP) - void *retval = malloc(size); - if (!retval) - { - NOTICE_LOG(MEMMAP, "malloc failed: %s", strerror(errno)); - return 0; - } - return retval; #else void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | ((base == 0) ? 0 : MAP_FIXED), fd, offset); @@ -202,14 +188,14 @@ void MemArena::ReleaseView(void* view, size_t size) { #ifdef _WIN32 UnmapViewOfFile(view); -#elif defined(UNUSABLE_MMAP) - free(view); +#elif defined(__SYMBIAN32__) + memmap->Decommit((int)view - (int)memmap->Base(), size); #else munmap(view, size); #endif } - +#ifndef __SYMBIAN32__ u8* MemArena::Find4GBBase() { #ifdef _M_X64 @@ -224,8 +210,8 @@ u8* MemArena::Find4GBBase() return reinterpret_cast(0x2300000000ULL); #endif -#else - // 32 bit +#else // 32 bit + #ifdef _WIN32 // The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it. u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE); @@ -233,9 +219,6 @@ u8* MemArena::Find4GBBase() VirtualFree(base, 0, MEM_RELEASE); } return base; -#elif defined(UNUSABLE_MMAP) - // We are unable to use relative addresses due to lack of mmap() - return NULL; #else void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); @@ -248,6 +231,7 @@ u8* MemArena::Find4GBBase() #endif #endif } +#endif // yeah, this could also be done in like two bitwise ops... @@ -282,6 +266,12 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 if (view.flags & MV_MIRROR_PREVIOUS) { position = last_position; } else { +#ifdef __SYMBIAN32__ + *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); + arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + } + *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); +#else *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size); if (!*view.out_ptr_low) goto bail; @@ -299,6 +289,8 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 if (!*view.out_ptr) goto bail; } +#endif + #endif last_position = position; position += roundup(view.size); @@ -344,7 +336,9 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena total_mem += roundup(views[i].size); } // Grab some pagefile backed memory out of the void ... +#ifndef __SYMBIAN32__ arena->GrabLowMemSpace(total_mem); +#endif // Now, create views in high memory where there's plenty of space. #ifdef _M_X64 @@ -374,6 +368,16 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena break; } } +#elif defined(__SYMBIAN32__) + arena->memmap = new RChunk(); + arena->memmap->CreateDisconnectedLocal(0 , 0, 0x10000000); + if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return 0; + } + u8* base = arena->memmap->Base(); #else // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. u8 *base = MemArena::Find4GBBase(); diff --git a/Common/MemArena.h b/Common/MemArena.h index 75dd738b0e18..a12f8f493b85 100644 --- a/Common/MemArena.h +++ b/Common/MemArena.h @@ -22,6 +22,10 @@ #include #endif +#ifdef __SYMBIAN32__ +#include +#endif + #include "Common.h" // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. @@ -36,8 +40,12 @@ class MemArena void *CreateView(s64 offset, size_t size, void *base = 0); void ReleaseView(void *view, size_t size); +#ifdef __SYMBIAN32__ + RChunk* memmap; +#else // This only finds 1 GB in 32-bit static u8 *Find4GBBase(); +#endif private: #ifdef _WIN32 diff --git a/Common/MemoryUtil.h b/Common/MemoryUtil.h index f8c6ee6b1af6..bafa7e4e881f 100644 --- a/Common/MemoryUtil.h +++ b/Common/MemoryUtil.h @@ -23,11 +23,6 @@ #endif #include -#if defined(__SYMBIAN32__) - // Also Xbox 360 - #define UNUSABLE_MMAP 1 -#endif - void* AllocateExecutableMemory(size_t size, bool low = true); void* AllocateMemoryPages(size_t size); void FreeMemoryPages(void* ptr, size_t size); diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 9a1ad4bc82ee..d7d1e4b9072e 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -113,11 +113,7 @@ void Jit::GenerateFixedCode() // * downcount // * R2-R4 // Really starting to run low on registers already though... -#ifdef UNUSABLE_MMAP - MOVI2R(R11, (u32)Memory::m_pRAM - 0x08000000); -#else MOVI2R(R11, (u32)Memory::base); -#endif MOVI2R(R10, (u32)mips_); MOVI2R(R9, (u32)GetBlockCache()->GetCodePointers()); diff --git a/Core/MemMap.h b/Core/MemMap.h index bf7769201851..a7731d839f72 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -36,9 +36,9 @@ #if defined(_DEBUG) //#define SAFE_MEMORY #endif -// Required for UNUSABLE_MMAP. Can define this in cmake instead later + #ifdef __SYMBIAN32__ -#define SAFE_MEMORY +//#define SAFE_MEMORY #endif From 106cbcfc5d3758929995475fdf3ea35440bc048e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Feb 2013 21:26:32 -0800 Subject: [PATCH 14/18] Fix possible overlap issue in VDot. --- Core/MIPS/MIPSIntVFPU.cpp | 1 + Core/MIPS/x86/CompVFPU.cpp | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 8466b5250cb4..7aa182f6b5e0 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -936,6 +936,7 @@ namespace MIPSInt } d = sum; ApplyPrefixD(&d,V_Single); + // TODO: Shouldn't this respect the mask? V(vd) = d; PC += 4; EatPrefixes(); diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 8da64f698797..b011c6ae52c3 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -146,21 +146,26 @@ void Jit::ApplyPrefixD(const u8 *vregs, u32 prefix, VectorSize sz, bool onlyWrit // Vector regs can overlap in all sorts of swizzled ways. // This does allow a single overlap in sregs[i]. -bool DestRegOverlaps(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) +bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) { for (int i = 0; i < sn; ++i) { if (sregs[i] == dreg && i != di) - return true; + return false; } for (int i = 0; i < tn; ++i) { if (tregs[i] == dreg) - return true; + return false; } // Hurray, no overlap, we can write directly. - return false; + return true; +} + +bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn, u8 tregs[]) +{ + return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; } static u32 GC_ALIGNED16(ssLoadStoreTemp); @@ -335,18 +340,15 @@ void Jit::Comp_VDot(u32 op) { int n = GetNumVectorElements(sz); X64Reg tempxreg = XMM0; - if (!DestRegOverlaps(dregs[0], 0, n, sregs, n, tregs)) + if (IsOverlapSafe(dregs[0], 0, n, sregs, n, tregs)) { fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); tempxreg = fpr.VX(dregs[0]); } + // Need to start with +0.0f so it doesn't result in -0.0f. MOVSS(tempxreg, M((void *) &zero)); - MOVSS(XMM1, fpr.V(sregs[0])); - MULSS(XMM1, fpr.V(tregs[0])); - ADDSS(tempxreg, R(XMM1)); - - for (int i = 1; i < n; i++) + for (int i = 0; i < n; i++) { // sum += s[i]*t[i]; MOVSS(XMM1, fpr.V(sregs[i])); @@ -357,7 +359,7 @@ void Jit::Comp_VDot(u32 op) { if (!fpr.V(dregs[0]).IsSimpleReg(tempxreg)) { fpr.MapRegsV(dregs, V_Single, MAP_NOINIT); - MOVSS(fpr.V(dregs[0]), XMM0); + MOVSS(fpr.V(dregs[0]), tempxreg); } // TODO: applyprefixD here somehow (write mask etc..) @@ -427,7 +429,7 @@ void Jit::Comp_VecDo3(u32 op) { X64Reg tempxregs[4]; for (int i = 0; i < n; ++i) { - if (DestRegOverlaps(dregs[i], i, n, sregs, n, tregs)) + if (!IsOverlapSafeAllowS(dregs[i], i, n, sregs, n, tregs)) { // On 32-bit we only have 6 xregs for mips regs, use XMM0/XMM1 if possible. if (i < 2) From ff8390123a8ee551013a9909175325ec293dabdb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 17 Feb 2013 00:38:50 -0800 Subject: [PATCH 15/18] Focus the main window when showing the log. --- Windows/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Windows/main.cpp b/Windows/main.cpp index 48fce377a6d3..f729c9abb881 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -161,6 +161,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } // else // MainWindow::BrowseAndBoot(); + if (!hideLog) + SetForegroundWindow(hwndMain); if (fileToStart != NULL && stateToLoad != NULL) SaveState::Load(stateToLoad); From a9eb6cf4a49a12953f63439e0dc4a737054b27fb Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 17 Feb 2013 20:21:42 +1000 Subject: [PATCH 16/18] Fix crash on Symbian when doing "Return to Menu" --- Common/MemArena.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/MemArena.cpp b/Common/MemArena.cpp index 4fabb11237ed..d2d03bd7207a 100644 --- a/Common/MemArena.cpp +++ b/Common/MemArena.cpp @@ -189,7 +189,7 @@ void MemArena::ReleaseView(void* view, size_t size) #ifdef _WIN32 UnmapViewOfFile(view); #elif defined(__SYMBIAN32__) - memmap->Decommit((int)view - (int)memmap->Base(), size); + memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); #else munmap(view, size); #endif From 8ba2769d5ebe8265bbce4c386da59fc12678192a Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 18 Feb 2013 00:04:44 +1000 Subject: [PATCH 17/18] iOS Objective-C code dump. ViewController courtesy of rock88. Made modifications for simplification and code-style. Still missing some files (eg. images). Also, CMake is not set up correctly yet. --- CMakeLists.txt | 19 +++- ios/AppDelegate.h | 13 +++ ios/AppDelegate.m | 25 +++++ ios/PPSSPP-Info.plist | 46 ++++++++ ios/PPSSPP-Prefix.pch | 9 ++ ios/ViewController.h | 8 ++ ios/ViewController.mm | 241 ++++++++++++++++++++++++++++++++++++++++ ios/ios.toolchain.cmake | 2 +- ios/main.m | 12 ++ 9 files changed, 371 insertions(+), 4 deletions(-) create mode 100644 ios/AppDelegate.h create mode 100644 ios/AppDelegate.m create mode 100644 ios/PPSSPP-Info.plist create mode 100644 ios/PPSSPP-Prefix.pch create mode 100644 ios/ViewController.h create mode 100644 ios/ViewController.mm create mode 100644 ios/main.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 37509ed44212..c0c7004b83e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -410,6 +410,16 @@ if(ANDROID) native/android/native-audio-so.h) target_link_libraries(native_audio OpenSLES) # No target +elseif(IOS) + set(nativeExtra ${nativeExtra} + ios/main.m + ios/AppDelegate.m + ios/AppDelegate.h + ios/ViewController.mm + ios/ViewController.h) + set(CMAKE_EXE_LINKER_FLAGS "-framework Foundation -framework CoreGraphics -framework QuartzCore -framework OpenGLES -framework UIKit") + # No target + # set(TargetBin PPSSPP) elseif(USING_QT_UI) # Currently unused find_package(Qt4 COMPONENTS QtMultimedia QtOpenGL QtGui QtCore) @@ -433,9 +443,7 @@ elseif(SDL_FOUND) elseif(PANDORA) set(nativeExtraLibs ${nativeExtraLibs} pthread EGL X11) endif() - if(NOT IOS) # No target - set(TargetBin PPSSPPSDL) - endif() + set(TargetBin PPSSPPSDL) else() message(FATAL_ERROR "Could not find SDL. Failing.") endif() @@ -950,4 +958,9 @@ endif() file(INSTALL ${NativeAssets} DESTINATION assets) +# code signing +if (IOS) + set_target_properties(${NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST PPSSPP-Info.plist XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name") +endif() + #include(CPack) diff --git a/ios/AppDelegate.h b/ios/AppDelegate.h new file mode 100644 index 000000000000..263e85d369ea --- /dev/null +++ b/ios/AppDelegate.h @@ -0,0 +1,13 @@ +// AppDelegate.h boilerplate + +#import + +@class ViewController; + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@property (strong, nonatomic) ViewController *viewController; + +@end diff --git a/ios/AppDelegate.m b/ios/AppDelegate.m new file mode 100644 index 000000000000..8601d4fee799 --- /dev/null +++ b/ios/AppDelegate.m @@ -0,0 +1,25 @@ +// AppDelegate.m boilerplate + +#import "AppDelegate.h" + +#import "ViewController.h" + +@implementation AppDelegate + +- (void)dealloc +{ + [_window release]; + [_viewController release]; + [super dealloc]; +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.viewController = [[[ViewController alloc] init] autorelease]; + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist new file mode 100644 index 000000000000..5fe1a739c6dd --- /dev/null +++ b/ios/PPSSPP-Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.rock88dev.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/PPSSPP-Prefix.pch b/ios/PPSSPP-Prefix.pch new file mode 100644 index 000000000000..6cc2cfc1a8d5 --- /dev/null +++ b/ios/PPSSPP-Prefix.pch @@ -0,0 +1,9 @@ +#import + +#ifndef __IPHONE_4_0 +#warning "This project uses features only available in iOS SDK 4.0 and later." +#endif + +#ifdef __OBJC__ + #import +#endif diff --git a/ios/ViewController.h b/ios/ViewController.h new file mode 100644 index 000000000000..b505050d4481 --- /dev/null +++ b/ios/ViewController.h @@ -0,0 +1,8 @@ +// ViewController.h boilerplate + +#import +#import + +@interface ViewController : GLKViewController + +@end diff --git a/ios/ViewController.mm b/ios/ViewController.mm new file mode 100644 index 000000000000..576d3b68cac2 --- /dev/null +++ b/ios/ViewController.mm @@ -0,0 +1,241 @@ +// +// ViewController.m +// +// Created by rock88 +// Modified by xSacha +// + +#import "ViewController.h" +#import + +#include "base/display.h" +#include "base/timeutil.h" +#include "file/zip_read.h" +#include "input/input_state.h" +#include "net/resolve.h" +#include "ui_atlas.h" +#include "ui/screen.h" + +#include "Config.h" +#include "gfx_es2/fbo.h" + +#define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + +extern void UIUpdateMouse(int i, float x, float y, bool down); + +float dp_xscale = 1.0f; +float dp_yscale = 1.0f; + +static uint32_t pad_buttons_async_set = 0; +static uint32_t pad_buttons_async_clear = 0; + +extern ScreenManager *screenManager; +InputState input_state; + +extern std::string ram_temp_file; + +@interface ViewController () + +@property (strong, nonatomic) EAGLContext *context; +@property (nonatomic,retain) NSString* documentsPath; +@property (nonatomic,retain) NSString* bundlePath; +@property (nonatomic,retain) NSMutableArray* touches; + +@end + +@implementation ViewController +@synthesize documentsPath,bundlePath,touches; + +- (id)init +{ + self = [super init]; + if (self) { + self.touches = [[[NSMutableArray alloc] init] autorelease]; + + self.documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + self.bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/"]; + + memset(&input_state, 0, sizeof(input_state)); + + net::Init(); + + ram_temp_file = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"ram_tmp.file"] fileSystemRepresentation]; + NativeInit(0, NULL, [self.bundlePath UTF8String], [self.documentsPath UTF8String], NULL); + + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.frame = [[UIScreen mainScreen] bounds]; + self.view.multipleTouchEnabled = YES; + self.context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease]; + + GLKView *view = (GLKView *)self.view; + view.context = self.context; + view.drawableDepthFormat = GLKViewDrawableDepthFormat24; + [EAGLContext setCurrentContext:self.context]; + + float scale = [UIScreen mainScreen].scale; + CGSize size = [[UIApplication sharedApplication].delegate window].frame.size; + + if (size.height > size.width) { + float h = size.height; + size.height = size.width; + size.width = h; + } + + g_dpi = (IS_IPAD() ? 200 : 150) * scale; + g_dpi_scale = 240.0f / (float)g_dpi; + pixel_xres = size.width * scale; + pixel_yres = size.height * scale; + pixel_in_dps = (float)pixel_xres / (float)dp_xres; + + dp_xres = pixel_xres * g_dpi_scale; + dp_yres = pixel_yres * g_dpi_scale; + + NativeInitGraphics(); + + dp_xscale = (float)dp_xres / (float)pixel_xres; + dp_yscale = (float)dp_yres / (float)pixel_yres; + +/* + UISwipeGestureRecognizer* gesture = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)] autorelease]; + [self.view addGestureRecognizer:gesture]; +*/ +} + +- (void)viewDidUnload +{ + [super viewDidUnload]; + + if ([EAGLContext currentContext] == self.context) { + [EAGLContext setCurrentContext:nil]; + } + self.context = nil; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; +} + +- (void)dealloc +{ + [self viewDidUnload]; + + self.touches = nil; + self.documentsPath = nil; + self.bundlePath = nil; + + NativeShutdown(); + [super dealloc]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation +{ + return YES; +} + +//static BOOL menuDown = NO; + +- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect +{ + lock_guard guard(input_state.lock); + input_state.pad_buttons |= pad_buttons_async_set; + input_state.pad_buttons &= ~pad_buttons_async_clear; + UpdateInputState(&input_state); + + { + lock_guard guard(input_state.lock); + UIUpdateMouse(0, input_state.pointer_x[0], input_state.pointer_y[0], input_state.pointer_down[0]); + screenManager->update(input_state); + } + + { + lock_guard guard(input_state.lock); + EndInputState(&input_state); + } + + NativeRender(); + time_update(); +} + +- (void)swipeGesture:(id)sender +{ + // TODO: Use a swipe gesture to handle BACK +/* + pad_buttons_async_set |= PAD_BUTTON_MENU; + pad_buttons_async_clear &= PAD_BUTTON_MENU; + + int64_t delayInSeconds = 1.5; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + pad_buttons_async_set &= PAD_BUTTON_MENU; + pad_buttons_async_clear |= PAD_BUTTON_MENU; + }); + + if (g_Config.bBufferedRendering) + fbo_unbind(); + + screenManager->push(new InGameMenuScreen()); +*/ +} + +- (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId +{ + lock_guard guard(input_state.lock); + + float scale = [UIScreen mainScreen].scale; + + float scaledX = (int)(x * dp_xscale) * scale; + float scaledY = (int)(y * dp_yscale) * scale; + + input_state.pointer_x[pointerId] = scaledX; + input_state.pointer_y[pointerId] = scaledY; + if (code == 1) { + input_state.pointer_down[pointerId] = true; + } else if (code == 2) { + input_state.pointer_down[pointerId] = false; + } + input_state.mouse_valid = true; +} + +- (void)touchesBegan:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + [self.touches addObject:touch]; + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:1 pointerId:[self.touches indexOfObject:touch]]; + } +} + +- (void)touchesMoved:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:0 pointerId:[self.touches indexOfObject:touch]]; + } +} + +- (void)touchesEnded:(NSSet *)_touches withEvent:(UIEvent *)event +{ + for(UITouch* touch in _touches) { + CGPoint point = [touch locationInView:self.view]; + [self touchX:point.x y:point.y code:2 pointerId:[self.touches indexOfObject:touch]]; + [self.touches removeObject:touch]; + } +} + +void LaunchBrowser(char const* url) +{ + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]]; +} + +void EnableFZ(){}; +void DisableFZ(){}; + +@end diff --git a/ios/ios.toolchain.cmake b/ios/ios.toolchain.cmake index 469e83acf114..eeb0fd3deb64 100644 --- a/ios/ios.toolchain.cmake +++ b/ios/ios.toolchain.cmake @@ -141,7 +141,7 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su # set the architecture for iOS # NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv6 armv7) + set (IOS_ARCH armv7) else (${IOS_PLATFORM} STREQUAL "OS") set (IOS_ARCH i386) endif (${IOS_PLATFORM} STREQUAL "OS") diff --git a/ios/main.m b/ios/main.m new file mode 100644 index 000000000000..2c76d754c1df --- /dev/null +++ b/ios/main.m @@ -0,0 +1,12 @@ +// main.m boilerplate + +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} From 8c80641b288852f6a89bcc156dc86e2ebefdafdd Mon Sep 17 00:00:00 2001 From: Sacha Date: Mon, 18 Feb 2013 00:41:51 +1000 Subject: [PATCH 18/18] iOS redundancies iOS simulator does not support requires GLES2.0 environment. Remove all references to simulator. Add support for armv7s (swift) arch. --- CMakeLists.txt | 4 +--- ios/ios.toolchain.cmake | 18 +++++------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0c7004b83e9..0a1402a5d020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,7 @@ if(ANDROID) endif() if (IOS) - if (${IOS_PLATFORM} STREQUAL "OS") - set(ARM ON) - endif() + set(ARM ON) endif() if(BLACKBERRY) diff --git a/ios/ios.toolchain.cmake b/ios/ios.toolchain.cmake index eeb0fd3deb64..9af6cb06e6de 100644 --- a/ios/ios.toolchain.cmake +++ b/ios/ios.toolchain.cmake @@ -4,10 +4,9 @@ # Options: # -# IOS_PLATFORM = OS (default) or SIMULATOR -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders +# IOS_PLATFORM = OS (default) +# This needs to be OS as the simulator cannot use the required GLES2.0 environment. # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. # # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder # By default this location is automatcially chosen based on the IOS_PLATFORM value above. @@ -96,16 +95,11 @@ set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") # Check the platform selection and setup for developer root if (${IOS_PLATFORM} STREQUAL "OS") set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. PPSSPP is unable to run on simulator") else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or leave default") endif (${IOS_PLATFORM} STREQUAL "OS") # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT @@ -141,9 +135,7 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su # set the architecture for iOS # NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7) -else (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH i386) + set (IOS_ARCH armv7 armv7s) endif (${IOS_PLATFORM} STREQUAL "OS") set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")