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 \