diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index a221743a1f..08f19e7f84 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1383,7 +1383,7 @@ void FramebufferManager::UpdateFromMemory(u32 addr, int size) { if (useBufferedRendering_ && vfb->fbo) { fbo_bind_as_render_target(vfb->fbo); needUnbind = true; - DrawPixels(Memory::GetPointer(addr), vfb->format, vfb->fb_stride); + DrawPixels(Memory::GetPointer(addr | 0x04000000), vfb->format, vfb->fb_stride); } else { INFO_LOG(SCEGE, "Invalidating FBO for %08x (%i x %i x %i)", vfb->fb_address, vfb->width, vfb->height, vfb->format) DestroyFramebuf(vfb); @@ -1412,13 +1412,16 @@ bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer) { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, gstate.FrameBufFormat()); + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, gstate.FrameBufFormat()); return true; } buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GE_FORMAT_8888, true); if (vfb->fbo) fbo_bind_for_read(vfb->fbo); +#ifndef USING_GLES2 + glReadBuffer(GL_COLOR_ATTACHMENT0); +#endif glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData()); @@ -1440,16 +1443,17 @@ bool FramebufferManager::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? // TODO: Is the value 16-bit? It seems to be. - buffer = GPUDebugBuffer(Memory::GetPointer(z_address), z_stride, 512, GPU_DBG_FORMAT_16BIT); + buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT); return true; } #ifndef USING_GLES2 - buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, true); + buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_16BIT, 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_FLOAT, buffer.GetData()); + glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, buffer.GetData()); return true; #else @@ -1468,7 +1472,8 @@ bool FramebufferManager::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, GPU_DBG_FORMAT_8888); + // TODO: Actually get the stencil. + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, GPU_DBG_FORMAT_8888); return true; } @@ -1476,8 +1481,9 @@ bool FramebufferManager::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_16BIT, true); if (vfb->fbo) fbo_bind_for_read(vfb->fbo); + glReadBuffer(GL_STENCIL_ATTACHMENT); glPixelStorei(GL_PACK_ALIGNMENT, 2); - glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_STENCIL_INDEX, GL_UNSIGNED_SHORT, buffer.GetData()); + glReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer.GetData()); return true; #else diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 55046404d3..d3246213fb 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -283,6 +283,9 @@ void TransformDrawEngine::ApplyDrawState(int prim) { if (alphaMask && enableStencilTest) { glstate.stencilTest.enable(); glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE); + // TODO: In clear mode, the stencil value is set to the alpha value of the vertex. + // A normal clear will be 2 points, the second point has the color. + // We should set "ref" to that value instead of 0. glstate.stencilFunc.set(GL_ALWAYS, 0, 0xFF); } else glstate.stencilTest.disable(); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index d7d1dda31a..0223283187 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -38,6 +38,8 @@ enum PauseAction { PAUSE_CONTINUE, PAUSE_GETFRAMEBUF, + PAUSE_GETDEPTHBUF, + PAUSE_GETSTENCILBUF, PAUSE_GETTEX, }; @@ -60,6 +62,8 @@ static bool breakNextDraw = false; static bool bufferResult; static GPUDebugBuffer bufferFrame; +static GPUDebugBuffer bufferDepth; +static GPUDebugBuffer bufferStencil; static GPUDebugBuffer bufferTex; // TODO: Simplify and move out of windows stuff, just block in a common way for everyone. @@ -122,6 +126,14 @@ static void RunPauseAction() { bufferResult = gpuDebug->GetCurrentFramebuffer(bufferFrame); break; + case PAUSE_GETDEPTHBUF: + bufferResult = gpuDebug->GetCurrentDepthbuffer(bufferDepth); + break; + + case PAUSE_GETSTENCILBUF: + bufferResult = gpuDebug->GetCurrentStencilbuffer(bufferStencil); + break; + case PAUSE_GETTEX: bufferResult = gpuDebug->GetCurrentTexture(bufferTex); break; @@ -139,7 +151,7 @@ static void ForceUnpause() { } CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) - : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), frameWindow(NULL), texWindow(NULL) { + : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), primaryDisplay(PRIMARY_FRAMEBUF), frameWindow(NULL), texWindow(NULL) { breakCmds.resize(256, false); Core_ListenShutdown(ForceUnpause); @@ -218,14 +230,30 @@ void CGEDebugger::SetupPreviews() { void CGEDebugger::UpdatePreviews() { // TODO: Do something different if not paused? + GPUDebugBuffer *primaryBuffer = NULL; bufferResult = false; - SetPauseAction(PAUSE_GETFRAMEBUF); + switch (primaryDisplay) { + case PRIMARY_FRAMEBUF: + SetPauseAction(PAUSE_GETFRAMEBUF); + primaryBuffer = &bufferFrame; + break; - if (bufferResult) { - auto fmt = SimpleGLWindow::Format(bufferFrame.GetFormat()); - frameWindow->Draw(bufferFrame.GetData(), bufferFrame.GetStride(), bufferFrame.GetHeight(), bufferFrame.GetFlipped(), fmt); + case PRIMARY_DEPTHBUF: + SetPauseAction(PAUSE_GETDEPTHBUF); + primaryBuffer = &bufferDepth; + break; + + case PRIMARY_STENCILBUF: + SetPauseAction(PAUSE_GETSTENCILBUF); + primaryBuffer = &bufferStencil; + break; + } + + if (bufferResult && primaryBuffer != NULL) { + auto fmt = SimpleGLWindow::Format(primaryBuffer->GetFormat()); + frameWindow->Draw(primaryBuffer->GetData(), primaryBuffer->GetStride(), primaryBuffer->GetHeight(), primaryBuffer->GetFlipped(), fmt); } else { - ERROR_LOG(COMMON, "Unable to get framebuffer."); + ERROR_LOG(COMMON, "Unable to get buffer for main display."); frameWindow->Clear(); } @@ -235,8 +263,17 @@ void CGEDebugger::UpdatePreviews() { if (bufferResult) { auto fmt = SimpleGLWindow::Format(bufferTex.GetFormat()); texWindow->Draw(bufferTex.GetData(), bufferTex.GetStride(), bufferTex.GetHeight(), bufferTex.GetFlipped(), fmt); + + if (gpuDebug != NULL) { + auto state = gpuDebug->GetGState(); + if (state.isTextureAlphaUsed()) { + texWindow->SetFlags(SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_SHRINK_CENTER); + } else { + texWindow->SetFlags(SimpleGLWindow::RESIZE_SHRINK_CENTER); + } + } } else { - ERROR_LOG(COMMON, "Unable to get texture."); + ERROR_LOG(COMMON, "Unable to get texture (may be no texture set.)"); texWindow->Clear(); } diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index d51da9fa7a..53ae7e636f 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -61,6 +61,13 @@ private: void UpdateSize(WORD width, WORD height); void SavePosition(); + enum PrimaryDisplayType { + PRIMARY_FRAMEBUF, + PRIMARY_DEPTHBUF, + PRIMARY_STENCILBUF, + }; + + PrimaryDisplayType primaryDisplay; CtrlDisplayListView *displayList; TabDisplayLists *lists; TabStateFlags *flags; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 436c3f148e..e404779972 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "math/lin/matrix4x4.h" #include "gfx_es2/glsl_program.h" #include "Common/Common.h" @@ -29,13 +30,13 @@ void SimpleGLWindow::RegisterClass() { wndClass.lpszClassName = windowClass; wndClass.hInstance = GetModuleHandle(0); wndClass.lpfnWndProc = WndProc; - wndClass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hIcon = 0; wndClass.lpszMenuName = 0; wndClass.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); - wndClass.style = 0; + wndClass.style = CS_DBLCLKS; wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(SimpleGLWindow*); + wndClass.cbWndExtra = sizeof(SimpleGLWindow *); wndClass.hIconSm = 0; RegisterClassEx(&wndClass); @@ -66,7 +67,8 @@ static const char basic_vs[] = "}\n"; SimpleGLWindow::SimpleGLWindow(HWND wnd) - : hWnd_(wnd), valid_(false), drawProgram_(NULL), tex_(0), flags_(0) { + : hWnd_(wnd), valid_(false), drawProgram_(NULL), tex_(0), flags_(0), zoom_(false), + dragging_(false), offsetX_(0), offsetY_(0) { SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG) this); } @@ -203,17 +205,7 @@ void SimpleGLWindow::DrawChecker() { } void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { - DrawChecker(); - - if (flags_ & ALPHA_BLEND) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - } else { - glDisable(GL_BLEND); - } - glViewport(0, 0, w_, h_); - glScissor(0, 0, w_, h_); + wglMakeCurrent(hDC_, hGLRC_); GLint components = GL_RGBA; GLenum glfmt; @@ -247,11 +239,37 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // Reset offset when the texture size changes. + if (tw_ != w || th_ != h) { + tw_ = w; + th_ = h; + offsetX_ = 0; + offsetY_ = 0; + } + tflipped_ = flipped; + + Redraw(); +} + +void SimpleGLWindow::Redraw() { + DrawChecker(); + + if (flags_ & ALPHA_BLEND) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + } else { + glDisable(GL_BLEND); + } + glViewport(0, 0, w_, h_); + glScissor(0, 0, w_, h_); + + glBindTexture(GL_TEXTURE_2D, tex_); glsl_bind(drawProgram_); - float fw = (float)w, fh = (float)h; + float fw = (float)tw_, fh = (float)th_; float x = 0.0f, y = 0.0f; - if (flags_ & (RESIZE_SHRINK_FIT | RESIZE_SHRINK_CENTER)) { + if (flags_ & (RESIZE_SHRINK_FIT | RESIZE_CENTER) && !zoom_) { float wscale = fw / w_, hscale = fh / h_; // Too wide, and width is the biggest problem, so scale based on that. @@ -262,12 +280,15 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { fw /= hscale; fh = (float)h_; } - - if (flags_ & RESIZE_SHRINK_CENTER) { - x = ((float)w_ - fw) / 2; - y = ((float)h_ - fh) / 2; - } } + if (flags_ & RESIZE_CENTER) { + x = ((float)w_ - fw) / 2; + y = ((float)h_ - fh) / 2; + } + + x += offsetX_; + y += offsetY_; + const float pos[12] = {x,y,0, x+fw,y,0, x+fw,y+fh,0, x,y+fh,0}; static const float texCoords[8] = {0,0, 1,0, 1,1, 0,1}; static const float texCoordsFlipped[8] = {0,1, 1,1, 1,0, 0,0}; @@ -277,7 +298,7 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1); glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos); - glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, flipped ? texCoordsFlipped : texCoords); + glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, tflipped_ ? texCoordsFlipped : texCoords); glActiveTexture(GL_TEXTURE0); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); @@ -304,6 +325,43 @@ LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPA // Continue with window creation. return win != NULL; + + case WM_LBUTTONDBLCLK: + win->zoom_ = !win->zoom_; + // Reset the offset when zooming out (or in, doesn't matter.) + win->offsetX_ = 0; + win->offsetY_ = 0; + // Redrawn in WM_LBUTTONUP. + return 0; + + case WM_LBUTTONDOWN: + // Only while zoomed in, otherwise it's shrink to fit mode or fixed. + if (win->zoom_) { + win->dragging_ = true; + win->dragStartX_ = GET_X_LPARAM(lParam) - win->offsetX_; + win->dragStartY_ = GET_Y_LPARAM(lParam) - win->offsetY_; + win->dragLastUpdate_ = GetTickCount(); + } + return 0; + + case WM_LBUTTONUP: + win->dragging_ = false; + win->Redraw(); + return 0; + + case WM_MOUSEMOVE: + if (win->dragging_) { + int x = GET_X_LPARAM(lParam); + int y = GET_Y_LPARAM(lParam); + win->offsetX_ = x - win->dragStartX_; + win->offsetY_ = y - win->dragStartY_; + const u32 MS_BETWEEN_DRAG_REDRAWS = 5; + if (GetTickCount() - win->dragLastUpdate_ > MS_BETWEEN_DRAG_REDRAWS) { + win->Redraw(); + } + return 0; + } + break; } return DefWindowProc(hwnd, msg, wParam, lParam); diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index 2e72da1eca..d9739a6b54 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -36,8 +36,9 @@ struct SimpleGLWindow { enum Flags { RESIZE_NONE = 0x00, + RESIZE_CENTER = 0x02, RESIZE_SHRINK_FIT = 0x01, - RESIZE_SHRINK_CENTER = 0x02, + RESIZE_SHRINK_CENTER = 0x03, ALPHA_IGNORE = 0x00, ALPHA_BLEND = 0x04, }; @@ -47,6 +48,7 @@ struct SimpleGLWindow { void Clear(); void Draw(u8 *data, int w, int h, bool flipped = false, Format = FORMAT_8888); + void Redraw(); void Initialize(u32 flags); static SimpleGLWindow *GetFrom(HWND hwnd); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -71,11 +73,25 @@ protected: HDC hDC_; HGLRC hGLRC_; bool valid_; + // Width and height of the window. int w_; int h_; + // Last texture size/flipped for Redraw(). + int tw_; + int th_; + bool tflipped_; GLSLProgram *drawProgram_; GLuint checker_; GLuint tex_; u32 flags_; + // Disable shrink (toggled by double click.) + bool zoom_; + bool dragging_; + int dragStartX_; + int dragStartY_; + u32 dragLastUpdate_; + // Offset to position the texture is drawn at. + int offsetX_; + int offsetY_; }; \ No newline at end of file