From 2a6af9b8a3b4e00a1e6ee1f5a9912c2c03c04098 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Sun, 17 Feb 2013 01:06:06 +0100 Subject: [PATCH] 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 f66929d071..fb8f92966c 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -100,6 +100,8 @@ reswitch: 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 f20277ac20..65d1782489 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -64,8 +64,9 @@ public: 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 039fc97910..e9f1bb7854 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 7054f60e14..52e1883730 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -59,6 +59,13 @@ public: // 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 7ed3fefd6a..bc513f90e0 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 dd7dcee56a..c5a86426c9 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 @@ public: 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 4b964a274e..6487e9ce36 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 bb1958c365..764ad63735 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 @@ public: return cache.size(); } + bool DecodeTexture(u8 *output, GPUgstate state); private: struct TexCacheEntry { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d41ab94ab2..ff050581ed 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 66b6ccbdd8..8feb9cb569 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -62,4 +62,13 @@ public: { 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 07886c4e30..4edb5de1c5 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 @@ public: 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 065e5c7707..4dd3a64570 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 5a8989ead8..ca55e43879 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); - mainWindow->GetDialogDisasm()->UpdateDisplayList(); - m_hGPUStepEvent.wait(m_hGPUStepMutex); + if(m_GPUFlag == -1) + { + m_GPUFlag = 0; + } EmuThread_LockDraw(true); } -void QtHost::SetGPUStep(bool value) +void QtHost::SendGPUWait(u32 cmd) +{ + EmuThread_LockDraw(false); + + 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, int flag) { m_GPUStep = value; + m_GPUFlag = flag; } void QtHost::NextGPUStep() diff --git a/Qt/QtHost.h b/Qt/QtHost.h index b98ec8954e..8f578c9fd5 100644 --- a/Qt/QtHost.h +++ b/Qt/QtHost.h @@ -51,8 +51,9 @@ public: 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 @@ signals: private: MainWindow* mainWindow; bool m_GPUStep; + int m_GPUFlag; }; #endif // QTAPP_H diff --git a/Qt/ctrldisasmview.cpp b/Qt/ctrldisasmview.cpp index a2b7a00829..92d43f8e51 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 ffc768c48f..c7c6637436 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 09fa91632f..a52c5c88ab 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 5ce363dd95..cfdde62084 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 bd1a007f07..2b670bb150 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 fb47a1935f..5ca646e4be 100644 --- a/Qt/debugger_disasm.h +++ b/Qt/debugger_disasm.h @@ -41,7 +41,6 @@ public: 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 bcf992486f..0cc8967bcf 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 0000000000..0f557354ca --- /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 0000000000..e237a84f31 --- /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 0000000000..77a3ee5415 --- /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 3f73ccefd9..3b5cdedf08 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 0000000000..bc9ea6272d --- /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 0000000000..c04677e8d2 --- /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 0000000000..b163010222 --- /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 8f8efc2269..d2980033f1 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 013bb54e1b..d2de287927 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 @@ public: 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: 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 10f40c73a7..a6ef9df025 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