diff --git a/CMakeLists.txt b/CMakeLists.txt index 07ee2c1d5d..515761f6d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1455,6 +1455,7 @@ add_library(GPU OBJECT GPU/Common/DepalettizeShaderCommon.h GPU/Common/FramebufferCommon.cpp GPU/Common/FramebufferCommon.h + GPU/Common/GPUDebugInterface.cpp GPU/Common/GPUDebugInterface.h GPU/Common/DrawEngineCommon.cpp GPU/Common/DrawEngineCommon.h diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp new file mode 100644 index 0000000000..d76ab6111b --- /dev/null +++ b/GPU/Common/GPUDebugInterface.cpp @@ -0,0 +1,98 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPUDebugInterface.h" + +void GPUDebugBuffer::Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped, bool reversed) { + GPUDebugBufferFormat actualFmt = GPUDebugBufferFormat(fmt); + if (reversed && actualFmt < GPU_DBG_FORMAT_8888) { + actualFmt |= GPU_DBG_FORMAT_REVERSE_FLAG; + } + Allocate(stride, height, actualFmt, flipped); +} + +void GPUDebugBuffer::Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, bool flipped) { + if (alloc_ && stride_ == stride && height_ == height && fmt_ == fmt) { + // Already allocated the right size. + flipped_ = flipped; + return; + } + + Free(); + alloc_ = true; + height_ = height; + stride_ = stride; + fmt_ = fmt; + flipped_ = flipped; + + u32 pixelSize = PixelSize(fmt); + data_ = new u8[pixelSize * stride * height]; +} + +void GPUDebugBuffer::Free() { + if (alloc_ && data_ != NULL) { + delete [] data_; + } + data_ = NULL; +} + +u32 GPUDebugBuffer::PixelSize(GPUDebugBufferFormat fmt) const { + switch (fmt) { + case GPU_DBG_FORMAT_8888: + case GPU_DBG_FORMAT_8888_BGRA: + case GPU_DBG_FORMAT_FLOAT: + case GPU_DBG_FORMAT_24BIT_8X: + case GPU_DBG_FORMAT_24X_8BIT: + return 4; + + case GPU_DBG_FORMAT_888_RGB: + return 3; + + case GPU_DBG_FORMAT_8BIT: + return 1; + + default: + return 2; + } +} + +u32 GPUDebugBuffer::GetRawPixel(int x, int y) const { + if (data_ == nullptr) { + return 0; + } + + if (flipped_) { + y = height_ - y - 1; + } + + u32 pixelSize = PixelSize(fmt_); + u32 byteOffset = pixelSize * (stride_ * y + x); + const u8 *ptr = &data_[byteOffset]; + + switch (pixelSize) { + case 4: + return *(const u32 *)ptr; + case 3: + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); + case 2: + return *(const u16 *)ptr; + case 1: + return *(const u8 *)ptr; + default: + return 0; + } +} diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index c062777260..db960fc88b 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -121,65 +121,16 @@ struct GPUDebugBuffer { return *this; } - void Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped = false, bool reversed = false) { - GPUDebugBufferFormat actualFmt = GPUDebugBufferFormat(fmt); - if (reversed && actualFmt < GPU_DBG_FORMAT_8888) { - actualFmt |= GPU_DBG_FORMAT_REVERSE_FLAG; - } - Allocate(stride, height, actualFmt, flipped); - } - - void Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, bool flipped = false) { - if (alloc_ && stride_ == stride && height_ == height && fmt_ == fmt) { - // Already allocated the right size. - flipped_ = flipped; - return; - } - - Free(); - alloc_ = true; - height_ = height; - stride_ = stride; - fmt_ = fmt; - flipped_ = flipped; - - u32 pixelSize; - switch (fmt) { - case GPU_DBG_FORMAT_8888: - case GPU_DBG_FORMAT_8888_BGRA: - case GPU_DBG_FORMAT_FLOAT: - case GPU_DBG_FORMAT_24BIT_8X: - case GPU_DBG_FORMAT_24X_8BIT: - pixelSize = 4; - break; - - case GPU_DBG_FORMAT_888_RGB: - pixelSize = 3; - break; - - case GPU_DBG_FORMAT_8BIT: - pixelSize = 1; - break; - - default: - pixelSize = 2; - break; - } - - data_ = new u8[pixelSize * stride * height]; - } - - void Free() { - if (alloc_ && data_ != NULL) { - delete [] data_; - } - data_ = NULL; - } + void Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped = false, bool reversed = false); + void Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, bool flipped = false); + void Free(); u8 *GetData() { return data_; } + u32 GetRawPixel(int x, int y) const; + const u8 *GetData() const { return data_; } @@ -201,6 +152,8 @@ struct GPUDebugBuffer { } private: + u32 PixelSize(GPUDebugBufferFormat fmt) const; + bool alloc_; u8 *data_; u32 stride_; diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 21d123854f..1908a25682 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1907,12 +1907,12 @@ bool FramebufferManager::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_add } #ifndef USING_GLES2 - buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_16BIT, true); + buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, true); if (vfb->fbo) fbo_bind_for_read(vfb->fbo); glReadBuffer(GL_DEPTH_ATTACHMENT); glPixelStorei(GL_PACK_ALIGNMENT, 4); - glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, buffer.GetData()); + glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_FLOAT, buffer.GetData()); return true; #else diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 0e92a7c33d..0117fc4505 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -245,6 +245,7 @@ + @@ -318,9 +319,6 @@ {3fcdbae2-5103-4350-9a8e-848ce9c73195} - - - diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 1ef4f62305..bc8fa1fb20 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -183,7 +183,9 @@ Common - + + Common + @@ -351,9 +353,11 @@ Common - - - - + + Common + + + Common + \ No newline at end of file diff --git a/Qt/GPU.pro b/Qt/GPU.pro index 34729febf6..f8a1a307dd 100644 --- a/Qt/GPU.pro +++ b/Qt/GPU.pro @@ -42,6 +42,7 @@ SOURCES += $$P/GPU/GeDisasm.cpp \ # GPU $$P/GPU/Software/*.cpp \ $$P/GPU/Debugger/*.cpp \ $$P/GPU/Common/DepalettizeShaderCommon.cpp \ + $$P/GPU/Common/GPUDebugInterface.cpp \ $$P/GPU/Common/IndexGenerator.cpp \ $$P/GPU/Common/TextureDecoder.cpp \ $$P/GPU/Common/TextureScalerCommon.cpp \ diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 0dda4e5da1..3bd8f1cba1 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -20,6 +20,7 @@ #include #include "base/functional.h" +#include "Common/ColorConv.h" #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/GEDebugger/SimpleGLWindow.h" #include "Windows/GEDebugger/CtrlDisplayListView.h" @@ -58,7 +59,8 @@ void CGEDebugger::Init() { } CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) - : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), frameWindow(NULL), texWindow(NULL), textureLevel_(0) { + : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), frameWindow(nullptr), texWindow(nullptr), + textureLevel_(0), primaryBuffer_(nullptr), texBuffer_(nullptr) { GPUBreakpoints::Init(); Core_ListenShutdown(ForceUnpause); @@ -137,18 +139,46 @@ CGEDebugger::~CGEDebugger() { } void CGEDebugger::SetupPreviews() { - if (frameWindow == NULL) { + if (frameWindow == nullptr) { frameWindow = SimpleGLWindow::GetFrom(GetDlgItem(m_hDlg, IDC_GEDBG_FRAME)); frameWindow->Initialize(SimpleGLWindow::ALPHA_IGNORE | SimpleGLWindow::RESIZE_SHRINK_CENTER); + frameWindow->SetHoverCallback([&] (int x, int y) { + PreviewFramebufHover(x, y); + }); frameWindow->Clear(); } - if (texWindow == NULL) { + if (texWindow == nullptr) { texWindow = SimpleGLWindow::GetFrom(GetDlgItem(m_hDlg, IDC_GEDBG_TEX)); texWindow->Initialize(SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_SHRINK_CENTER); + texWindow->SetHoverCallback([&] (int x, int y) { + PreviewTextureHover(x, y); + }); texWindow->Clear(); } } +void CGEDebugger::DescribeFramebufTab(const GPUgstate &state, wchar_t desc[256]) { + _assert_msg_(MASTER_LOG, primaryBuffer_ != nullptr, "Must have a valid primaryBuffer_"); + + switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) { + case PRIMARY_FRAMEBUF: + _snwprintf(desc, 256, L"Color: 0x%08x (%dx%d) fmt %i", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight(), state.FrameBufFormat()); + break; + + case PRIMARY_DEPTHBUF: + _snwprintf(desc, 256, L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); + break; + + case PRIMARY_STENCILBUF: + _snwprintf(desc, 256, L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight()); + break; + } +} + +void CGEDebugger::DescribeTexture(const GPUgstate &state, wchar_t desc[256]) { + _snwprintf(desc, 256, L"Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); +} + void CGEDebugger::UpdatePreviews() { auto memLock = Memory::Lock(); if (!PSP_IsInited()) { @@ -156,7 +186,6 @@ void CGEDebugger::UpdatePreviews() { } wchar_t desc[256]; - const GPUDebugBuffer *primaryBuffer = NULL; bool bufferResult = false; GPUgstate state = {0}; @@ -164,45 +193,41 @@ void CGEDebugger::UpdatePreviews() { state = gpuDebug->GetGState(); } + primaryBuffer_ = nullptr; switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) { case PRIMARY_FRAMEBUF: - bufferResult = GPU_GetCurrentFramebuffer(primaryBuffer); - if (bufferResult) { - _snwprintf(desc, ARRAY_SIZE(desc), L"Color: 0x%08x (%dx%d) fmt %i", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight(), state.FrameBufFormat()); - } + bufferResult = GPU_GetCurrentFramebuffer(primaryBuffer_); break; case PRIMARY_DEPTHBUF: - bufferResult = GPU_GetCurrentDepthbuffer(primaryBuffer); - if (bufferResult) { - _snwprintf(desc, ARRAY_SIZE(desc), L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight()); - } + bufferResult = GPU_GetCurrentDepthbuffer(primaryBuffer_); break; case PRIMARY_STENCILBUF: - bufferResult = GPU_GetCurrentStencilbuffer(primaryBuffer); - if (bufferResult) { - _snwprintf(desc, ARRAY_SIZE(desc), L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight()); - } + bufferResult = GPU_GetCurrentStencilbuffer(primaryBuffer_); break; } - if (bufferResult && primaryBuffer != NULL) { - auto fmt = SimpleGLWindow::Format(primaryBuffer->GetFormat()); - frameWindow->Draw(primaryBuffer->GetData(), primaryBuffer->GetStride(), primaryBuffer->GetHeight(), primaryBuffer->GetFlipped(), fmt); + if (bufferResult && primaryBuffer_ != nullptr) { + auto fmt = SimpleGLWindow::Format(primaryBuffer_->GetFormat()); + frameWindow->Draw(primaryBuffer_->GetData(), primaryBuffer_->GetStride(), primaryBuffer_->GetHeight(), primaryBuffer_->GetFlipped(), fmt); + + DescribeFramebufTab(state, desc); SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, desc); } else if (frameWindow != NULL) { frameWindow->Clear(); + primaryBuffer_ = nullptr; + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L"Failed"); } - const GPUDebugBuffer *bufferTex = NULL; + texBuffer_ = nullptr; UpdateTextureLevel(textureLevel_); - bufferResult = GPU_GetCurrentTexture(bufferTex, textureLevel_); + bufferResult = GPU_GetCurrentTexture(texBuffer_, textureLevel_); if (bufferResult) { - auto fmt = SimpleGLWindow::Format(bufferTex->GetFormat()); - texWindow->Draw(bufferTex->GetData(), bufferTex->GetStride(), bufferTex->GetHeight(), bufferTex->GetFlipped(), fmt); + auto fmt = SimpleGLWindow::Format(texBuffer_->GetFormat()); + texWindow->Draw(texBuffer_->GetData(), texBuffer_->GetStride(), texBuffer_->GetHeight(), texBuffer_->GetFlipped(), fmt); if (gpuDebug != NULL) { if (state.isTextureAlphaUsed()) { @@ -210,7 +235,7 @@ void CGEDebugger::UpdatePreviews() { } else { texWindow->SetFlags(SimpleGLWindow::RESIZE_SHRINK_CENTER); } - _snwprintf(desc, ARRAY_SIZE(desc), L"Texture L%d: 0x%08x (%dx%d)", textureLevel_, state.getTextureAddress(textureLevel_), state.getTextureWidth(textureLevel_), state.getTextureHeight(textureLevel_)); + DescribeTexture(state, desc); SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc); UpdateLastTexture(state.getTextureAddress(textureLevel_)); @@ -219,6 +244,8 @@ void CGEDebugger::UpdatePreviews() { } } else if (texWindow != NULL) { texWindow->Clear(); + texBuffer_ = nullptr; + if (gpuDebug == NULL || state.isTextureMapEnabled()) { SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"Texture: failed"); } else { @@ -248,6 +275,163 @@ void CGEDebugger::UpdatePreviews() { lists->Update(); } +void CGEDebugger::PreviewFramebufHover(int x, int y) { + if (primaryBuffer_ == nullptr) { + return; + } + + wchar_t desc[256] = {0}; + + if (!frameWindow->HasTex()) { + desc[0] = 0; + } else if (x < 0 || y < 0) { + // This means they left the area. + GPUgstate state = {0}; + if (gpuDebug != nullptr) { + state = gpuDebug->GetGState(); + } + DescribeFramebufTab(state, desc); + } else { + // Coordinates are relative to actual framebuffer size. + u32 pix = primaryBuffer_->GetRawPixel(x, y); + DescribePixel(pix, primaryBuffer_->GetFormat(), x, y, desc); + } + + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, desc); +} + +void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]) { + switch (fmt) { + case GPU_DBG_FORMAT_565: + case GPU_DBG_FORMAT_565_REV: + case GPU_DBG_FORMAT_5551: + case GPU_DBG_FORMAT_5551_REV: + case GPU_DBG_FORMAT_5551_BGRA: + case GPU_DBG_FORMAT_4444: + case GPU_DBG_FORMAT_4444_REV: + case GPU_DBG_FORMAT_4444_BGRA: + case GPU_DBG_FORMAT_8888: + case GPU_DBG_FORMAT_8888_BGRA: + DescribePixelRGBA(pix, fmt, x, y, desc); + break; + + case GPU_DBG_FORMAT_16BIT: + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, pix, pix * (1.0f / 65535.0f)); + break; + + case GPU_DBG_FORMAT_8BIT: + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, pix, pix * (1.0f / 255.0f)); + break; + + case GPU_DBG_FORMAT_24BIT_8X: + // These are only ever going to be depth values, so let's also show scaled to 16 bit. + _snwprintf(desc, 256, L"%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), (pix & 0x00FFFFFF) * (65535.0f / 16777215.0f)); + break; + + case GPU_DBG_FORMAT_24X_8BIT: + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, (pix >> 24) & 0xFF, ((pix >> 24) & 0xFF) * (1.0f / 255.0f)); + break; + + case GPU_DBG_FORMAT_FLOAT: + _snwprintf(desc, 256, L"%d,%d: %f / %f", x, y, *(float *)&pix, *(float *)&pix * 65535.0f); + break; + + default: + _snwprintf(desc, 256, L"Unexpected format"); + } +} + +void CGEDebugger::DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]) { + u32 r = -1, g = -1, b = -1, a = -1; + + switch (fmt) { + case GPU_DBG_FORMAT_565: + r = Convert5To8((pix >> 0) & 0x1F); + g = Convert6To8((pix >> 5) & 0x3F); + b = Convert5To8((pix >> 11) & 0x1F); + case GPU_DBG_FORMAT_565_REV: + b = Convert5To8((pix >> 0) & 0x1F); + g = Convert6To8((pix >> 5) & 0x3F); + r = Convert5To8((pix >> 11) & 0x1F); + case GPU_DBG_FORMAT_5551: + r = Convert5To8((pix >> 0) & 0x1F); + g = Convert5To8((pix >> 5) & 0x1F); + b = Convert5To8((pix >> 10) & 0x1F); + a = (pix >> 15) & 1 ? 255 : 0; + case GPU_DBG_FORMAT_5551_REV: + a = pix & 1 ? 255 : 0; + b = Convert5To8((pix >> 1) & 0x1F); + g = Convert5To8((pix >> 6) & 0x1F); + r = Convert5To8((pix >> 11) & 0x1F); + case GPU_DBG_FORMAT_5551_BGRA: + b = Convert5To8((pix >> 0) & 0x1F); + g = Convert5To8((pix >> 5) & 0x1F); + r = Convert5To8((pix >> 10) & 0x1F); + a = (pix >> 15) & 1 ? 255 : 0; + break; + case GPU_DBG_FORMAT_4444: + r = Convert4To8((pix >> 0) & 0x0F); + g = Convert4To8((pix >> 4) & 0x0F); + b = Convert4To8((pix >> 8) & 0x0F); + a = Convert4To8((pix >> 12) & 0x0F); + break; + case GPU_DBG_FORMAT_4444_REV: + a = Convert4To8((pix >> 0) & 0x0F); + b = Convert4To8((pix >> 4) & 0x0F); + g = Convert4To8((pix >> 8) & 0x0F); + r = Convert4To8((pix >> 12) & 0x0F); + break; + case GPU_DBG_FORMAT_4444_BGRA: + b = Convert4To8((pix >> 0) & 0x0F); + g = Convert4To8((pix >> 4) & 0x0F); + r = Convert4To8((pix >> 8) & 0x0F); + a = Convert4To8((pix >> 12) & 0x0F); + break; + case GPU_DBG_FORMAT_8888: + r = (pix >> 0) & 0xFF; + g = (pix >> 8) & 0xFF; + b = (pix >> 16) & 0xFF; + a = (pix >> 24) & 0xFF; + break; + case GPU_DBG_FORMAT_8888_BGRA: + b = (pix >> 0) & 0xFF; + g = (pix >> 8) & 0xFF; + r = (pix >> 16) & 0xFF; + a = (pix >> 24) & 0xFF; + break; + + default: + _snwprintf(desc, 256, L"Unexpected format"); + return; + } + + _snwprintf(desc, 256, L"%d,%d: r=%d, g=%d, b=%d, a=%d", x, y, r, g, b, a); +} + +void CGEDebugger::PreviewTextureHover(int x, int y) { + if (texBuffer_ == nullptr) { + return; + } + + wchar_t desc[256] = {0}; + + if (!texWindow->HasTex()) { + desc[0] = 0; + } else if (x < 0 || y < 0) { + // This means they left the area. + GPUgstate state = {0}; + if (gpuDebug != nullptr) { + state = gpuDebug->GetGState(); + } + DescribeTexture(state, desc); + } else { + u32 pix = texBuffer_->GetRawPixel(x, y); + DescribePixel(pix, texBuffer_->GetFormat(), x, y, desc); + } + + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc); +} + void CGEDebugger::UpdateTextureLevel(int level) { GPUgstate state = {0}; if (gpuDebug != NULL) { diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index edebfdf85a..e5313403c3 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -18,6 +18,7 @@ #pragma once #include "Common/CommonWindows.h" +#include "GPU/Common/GPUDebugInterface.h" #include "Globals.h" #include "Windows/resource.h" #include "Windows/W32Util/DialogManager.h" @@ -51,6 +52,7 @@ class TabStateTexture; class TabStateSettings; class TabVertices; class TabMatrices; +struct GPUgstate; class CGEDebugger : public Dialog { public: @@ -71,6 +73,14 @@ private: void SavePosition(); void SetBreakNext(BreakNextType type); void UpdateTextureLevel(int level); + void DescribeFramebufTab(const GPUgstate &state, wchar_t desc[256]); + void DescribeDepthbufPixel(int x, int y, wchar_t desc[256]); + void DescribeStencilbufPixel(int x, int y, wchar_t desc[256]); + void DescribeTexture(const GPUgstate &state, wchar_t desc[256]); + void PreviewFramebufHover(int x, int y); + void PreviewTextureHover(int x, int y); + void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]); + void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, wchar_t desc[256]); CtrlDisplayListView *displayList; TabDisplayLists *lists; @@ -85,6 +95,9 @@ private: TabControl *tabs; TabControl *fbTabs; int textureLevel_; + // The most recent primary/framebuffer and texture buffers. + const GPUDebugBuffer *primaryBuffer_; + const GPUDebugBuffer *texBuffer_; int minWidth,minHeight; }; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 8f24b65179..15d24cadc1 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -68,7 +68,7 @@ static const char basic_vs[] = SimpleGLWindow::SimpleGLWindow(HWND wnd) : hWnd_(wnd), valid_(false), drawProgram_(nullptr), tex_(0), flags_(0), zoom_(false), - dragging_(false), offsetX_(0), offsetY_(0), reformatBuf_(nullptr) { + dragging_(false), offsetX_(0), offsetY_(0), reformatBuf_(nullptr), hoverCallback_(nullptr) { SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this); } @@ -434,6 +434,45 @@ bool SimpleGLWindow::ToggleZoom() { return true; } +bool SimpleGLWindow::Hover(int mouseX, int mouseY) { + if (hoverCallback_ == nullptr) { + return false; + } + + float fw, fh; + float x, y; + GetContentSize(x, y, fw, fh); + + if (mouseX < x || mouseX >= x + fw || mouseY < y || mouseY >= y + fh) { + // Outside of bounds. + hoverCallback_(-1, -1); + return true; + } + + float tx = (mouseX - x) * (tw_ / fw); + float ty = (mouseY - y) * (th_ / fh); + + hoverCallback_((int)tx, (int)ty); + + // Find out when they are done. + TRACKMOUSEEVENT tracking = {0}; + tracking.cbSize = sizeof(tracking); + tracking.dwFlags = TME_LEAVE; + tracking.hwndTrack = hWnd_; + TrackMouseEvent(&tracking); + + return true; +} + +bool SimpleGLWindow::Leave() { + if (hoverCallback_ == nullptr) { + return false; + } + + hoverCallback_(-1, -1); + return true; +} + const u8 *SimpleGLWindow::Reformat(const u8 *data, Format fmt, u32 numPixels) { if (!reformatBuf_ || reformatBufSize_ < numPixels) { delete [] reformatBuf_; @@ -463,8 +502,19 @@ SimpleGLWindow *SimpleGLWindow::GetFrom(HWND hwnd) { LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SimpleGLWindow *win = SimpleGLWindow::GetFrom(hwnd); - switch(msg) - { + int mouseX = 0, mouseY = 0; + switch (msg) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + mouseX = GET_X_LPARAM(lParam); + mouseY = GET_Y_LPARAM(lParam); + break; + default: + break; + } + + switch (msg) { case WM_NCCREATE: win = new SimpleGLWindow(hwnd); @@ -482,19 +532,28 @@ LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPA break; case WM_LBUTTONDOWN: - if (win->DragStart(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + if (win->DragStart(mouseX, mouseY)) { return 0; } break; case WM_LBUTTONUP: - if (win->DragEnd(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + if (win->DragEnd(mouseX, mouseY)) { return 0; } break; case WM_MOUSEMOVE: - if (win->DragContinue(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + if (win->DragContinue(mouseX, mouseY)) { + return 0; + } + if (win->Hover(mouseX, mouseY)) { + return 0; + } + break; + + case WM_MOUSELEAVE: + if (win->Leave()) { return 0; } break; diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index fe47b2317d..f1802c511f 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -17,6 +17,7 @@ #pragma once +#include "base/functional.h" #include "gfx_es2/glsl_program.h" #include "Common/CommonWindows.h" #include "Globals.h" @@ -82,6 +83,10 @@ struct SimpleGLWindow { return h_; } + bool HasTex() { + return tw_ > 0 && th_ > 0; + } + int TexWidth() { return tw_; } @@ -92,6 +97,10 @@ struct SimpleGLWindow { void GetContentSize(float &x, float &y, float &fw, float &fh); + void SetHoverCallback(std::function hoverCallback) { + hoverCallback_ = hoverCallback; + } + static void RegisterClass(); protected: void SetupGL(); @@ -102,6 +111,8 @@ protected: bool DragStart(int mouseX, int mouseY); bool DragContinue(int mouseX, int mouseY); bool DragEnd(int mouseX, int mouseY); + bool Hover(int mouseX, int mouseY); + bool Leave(); bool ToggleZoom(); const u8 *Reformat(const u8 *data, Format fmt, u32 numPixels); @@ -132,4 +143,6 @@ protected: int offsetY_; u32 *reformatBuf_; u32 reformatBufSize_; + + std::function hoverCallback_; }; \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index b4361662d9..1f81df8120 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -154,6 +154,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/GeDisasm.cpp \ $(SRC)/GPU/Common/DepalettizeShaderCommon.cpp \ $(SRC)/GPU/Common/FramebufferCommon.cpp \ + $(SRC)/GPU/Common/GPUDebugInterface.cpp \ $(SRC)/GPU/Common/IndexGenerator.cpp.arm \ $(SRC)/GPU/Common/SoftwareTransformCommon.cpp.arm \ $(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \