From d4984ab991f186bd1d13293a83226078c40cd864 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 21 Dec 2017 21:09:26 +0000 Subject: [PATCH 1/9] SDL: unbreak on more non-Vulkan platforms SDL/SDLMain.cpp:160:2: error: unknown type name 'SDL_SysWMinfo'; did you mean 'SDL_SysWMmsg'? SDL_SysWMinfo sysInfo; //Will hold our Window information ^~~~~~~~~~~~~ SDL_SysWMmsg SDL/SDLMain.cpp:433:2: error: unknown type name 'SDL_SysWMinfo'; did you mean 'SDL_SysWMmsg'? SDL_SysWMinfo sys_info{}; ^~~~~~~~~~~~~ SDL_SysWMmsg SDL/SDLMain.cpp:440:2: warning: expression result unused [-Wunused-value] Window x11_window = sys_info.info.x11.window; ^~~~~~ --- SDL/SDLMain.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index f3202d24bf..04e011e314 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -36,15 +36,17 @@ SDLJoystick *joystick = NULL; #include "Common/Vulkan/VulkanDebug.h" #include "math.h" +#if !defined(__APPLE__) +#include "SDL_syswm.h" +#endif + #if defined(VK_USE_PLATFORM_XLIB_KHR) #include #include -#include "SDL_syswm.h" #elif defined(VK_USE_PLATFORM_XCB_KHR) #include #include #include -#include "SDL_syswm.h" #endif #if defined(USING_EGL) From 9f02e9c4f027cb1ef692b79982f8abe7e8a4e9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 22 Dec 2017 00:00:54 +0100 Subject: [PATCH 2/9] Android cmake fix --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8915f868a..df8dbd2078 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ if(NOT ANDROID) endif() endif() -if(NOT WIN32 AND VULKAN) +if(VULKAN AND NOT WIN32 AND NOT ANDROID) IF (NOT Vulkan_FOUND) find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/ext/vulkan" REQUIRED) IF (Vulkan_LIBRARY) @@ -1676,7 +1676,7 @@ set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-gl target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs} ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) -if(VULKAN) +if(VULKAN AND NOT ANDROID AND NOT WIN32) target_link_libraries(${CoreLibName} ${Vulkan_LIBRARY}) endif() From 510f9652a0a7c5286823635a3313bc965240857a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 21 Dec 2017 18:44:47 -0800 Subject: [PATCH 3/9] GLES: Improve HW tess requirements validation. We also need texelFetch of some kind, seen in reporting. --- GPU/GLES/GPU_GLES.cpp | 3 ++- UI/GameSettingsScreen.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 6fc70b7ef7..a1854df7a5 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -175,7 +175,8 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) if (g_Config.bHardwareTessellation) { // Disable hardware tessellation if device is unsupported. - if (!gstate_c.SupportsAll(GPU_SUPPORTS_INSTANCE_RENDERING | GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT)) { + bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; + if (!gstate_c.SupportsAll(GPU_SUPPORTS_INSTANCE_RENDERING | GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT) || !hasTexelFetch) { // TODO: Check unsupported device name list.(Above gpu features are supported but it has issues with weak gpu, memory, shader compiler etc...) g_Config.bHardwareTessellation = false; ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation"); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 0c0b2dcdcf..e2409223f6 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -99,8 +99,9 @@ bool CheckSupportInstancedTessellationGLES() { bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID); bool textureFloat = gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float; + bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4; - return instanceRendering && vertexTexture && textureFloat; + return instanceRendering && vertexTexture && textureFloat && hasTexelFetch; #endif } From c5897a1c5c46c3d9f7ad3e9793b987cb8ab046f4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 21 Dec 2017 18:50:41 -0800 Subject: [PATCH 4/9] GPU: Cleanup some feature flags usage. --- GPU/Common/DrawEngineCommon.cpp | 2 +- GPU/Common/GPUStateUtils.cpp | 6 +++--- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 8 ++++---- GPU/GLES/ShaderManagerGLES.cpp | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 9fce9a6fb5..4ea75b7d16 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -489,7 +489,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, } bool DrawEngineCommon::ApplyShaderBlending() { - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) { + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { return true; } diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index dfd7d3ba2c..ea4b9359b5 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -302,7 +302,7 @@ ReplaceBlendType ReplaceBlendWithShader(bool allowShaderBlend, GEBufferFormat bu case GE_DSTBLEND_DOUBLESRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. // Using a copy isn't accurate either, though, when there's overlap. - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return !allowShaderBlend ? REPLACE_BLEND_PRE_SRC_2X_ALPHA : REPLACE_BLEND_COPY_FBO; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; @@ -444,14 +444,14 @@ ReplaceBlendType ReplaceBlendWithShader(bool allowShaderBlend, GEBufferFormat bu case GE_DSTBLEND_DOUBLESRCALPHA: if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return !allowShaderBlend ? REPLACE_BLEND_PRE_SRC_2X_ALPHA : REPLACE_BLEND_COPY_FBO; return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } else { // This means dst alpha/color is used in the src factor. // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) // We will just hope that doubling alpha for the dst factor will not clamp too badly. - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) return !allowShaderBlend ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; return REPLACE_BLEND_2X_ALPHA; } diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index c1994b8e53..913e6b5829 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -57,7 +57,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (gl_extensions.IsGLES) { // ES doesn't support dual source alpha :( - if (gstate_c.featureFlags & GPU_SUPPORTS_GLSL_ES_300) { + if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300)) { WRITE(p, "#version 300 es\n"); // GLSL ES 3.0 fragColor0 = "fragColor0"; texture = "texture"; @@ -90,8 +90,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform highpFog = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? true : false; highpTexcoord = highpFog; - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) { - if ((gstate_c.featureFlags & GPU_SUPPORTS_GLSL_ES_300) != 0 && gl_extensions.EXT_shader_framebuffer_fetch) { + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { + if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300) && gl_extensions.EXT_shader_framebuffer_fetch) { WRITE(p, "#extension GL_EXT_shader_framebuffer_fetch : require\n"); lastFragData = "fragColor0"; } else if (gl_extensions.EXT_shader_framebuffer_fetch) { @@ -534,7 +534,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (replaceBlend == REPLACE_BLEND_COPY_FBO) { // If we have NV_shader_framebuffer_fetch / EXT_shader_framebuffer_fetch, we skip the blit. // We can just read the prev value more directly. - if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) { + if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { WRITE(p, " lowp vec4 destColor = %s;\n", lastFragData); } else if (!texelFetch) { WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", texture); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index b83f49fb68..11ee8d736d 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -113,7 +113,7 @@ LinkedShader::LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *f glBindAttribLocation(program, ATTR_COLOR1, "color1"); #if !defined(USING_GLES2) - if (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) { + if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) { // Dual source alpha glBindFragDataLocationIndexed(program, 0, 0, "fragColor0"); glBindFragDataLocationIndexed(program, 0, 1, "fragColor1"); @@ -122,7 +122,7 @@ LinkedShader::LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *f } #elif !defined(IOS) if (gl_extensions.GLES3) { - if (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) { + if (gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) { glBindFragDataLocationIndexedEXT(program, 0, 0, "fragColor0"); glBindFragDataLocationIndexedEXT(program, 0, 1, "fragColor1"); } From 554a85e6d8830fea159400caf64047bfeba3f386 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 21 Dec 2017 23:47:49 -0800 Subject: [PATCH 5/9] GE Debugger: Save with alpha for PNGs. --- Core/AVIDump.cpp | 2 +- Core/Screenshot.cpp | 84 +++++++++++++++++++++++-------- Core/Screenshot.h | 3 +- Windows/GEDebugger/GEDebugger.cpp | 9 +++- 4 files changed, 72 insertions(+), 26 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 6188a2bda8..37c6cd620a 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -174,7 +174,7 @@ void AVIDump::AddFrame() u32 h = buf.GetHeight(); CheckResolution(w, h); u8 *flipbuffer = nullptr; - const u8 *buffer = ConvertBufferTo888RGB(buf, flipbuffer, w, h); + const u8 *buffer = ConvertBufferToScreenshot(buf, false, flipbuffer, w, h); #ifdef USE_FFMPEG diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index bc5b046056..46694c35a1 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -125,12 +125,14 @@ static bool WriteScreenshotToPNG(png_imagep image, const char *filename, int con } #endif -static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, const void *buffer, int offset, bool rev) { +static bool ConvertPixelTo8888RGBA(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, u8 &a, const void *buffer, int offset, bool rev) { const u8 *buf8 = (const u8 *)buffer; const u16 *buf16 = (const u16 *)buffer; const u32 *buf32 = (const u32 *)buffer; const float *fbuf = (const float *)buffer; + // NOTE: a and r might be the same channel. This is used for RGB. + u32 src; double fsrc; switch (fmt) { @@ -139,6 +141,7 @@ static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, if (rev) { src = bswap16(src); } + a = 255; r = Convert5To8((src >> 0) & 0x1F); g = Convert6To8((src >> 5) & 0x3F); b = Convert5To8((src >> 11) & 0x1F); @@ -148,6 +151,7 @@ static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, if (rev) { src = bswap16(src); } + a = (src >> 15) ? 255 : 0; r = Convert5To8((src >> 0) & 0x1F); g = Convert5To8((src >> 5) & 0x1F); b = Convert5To8((src >> 10) & 0x1F); @@ -157,6 +161,7 @@ static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, if (rev) { src = bswap16(src); } + a = Convert4To8((src >> 12) & 0xF); r = Convert4To8((src >> 0) & 0xF); g = Convert4To8((src >> 4) & 0xF); b = Convert4To8((src >> 8) & 0xF); @@ -166,54 +171,62 @@ static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, if (rev) { src = bswap32(src); } + a = (src >> 24) & 0xFF; r = (src >> 0) & 0xFF; g = (src >> 8) & 0xFF; b = (src >> 16) & 0xFF; break; case GPU_DBG_FORMAT_FLOAT: fsrc = fbuf[offset]; - r = fsrc >= 1.0 ? 255 : (fsrc < 0.0 ? 0 : (int)(fsrc * 255.0)); + r = 255; g = 0; b = 0; + a = fsrc >= 1.0 ? 255 : (fsrc < 0.0 ? 0 : (int)(fsrc * 255.0)); break; case GPU_DBG_FORMAT_16BIT: src = buf16[offset]; - r = src >> 8; + r = 255; g = 0; b = 0; + a = src >> 8; break; case GPU_DBG_FORMAT_8BIT: src = buf8[offset]; - r = src; + r = 255; g = 0; b = 0; + a = src; break; case GPU_DBG_FORMAT_24BIT_8X: src = buf32[offset]; - r = (src >> 16) & 0xFF; + r = 255; g = 0; b = 0; + a = (src >> 16) & 0xFF; break; case GPU_DBG_FORMAT_24X_8BIT: src = buf32[offset]; - r = (src >> 24) & 0xFF; + r = 255; g = 0; b = 0; + a = (src >> 24) & 0xFF; break; case GPU_DBG_FORMAT_24BIT_8X_DIV_256: src = buf32[offset]& 0x00FFFFFF; src = src - 0x800000 + 0x8000; - r = (src >> 8) & 0xFF; + r = 255; g = 0; b = 0; + a = (src >> 8) & 0xFF; break; case GPU_DBG_FORMAT_FLOAT_DIV_256: fsrc = fbuf[offset]; src = (int)(fsrc * 16777215.0); src = src - 0x800000 + 0x8000; - r = (src >> 8) & 0xFF; + r = 255; g = 0; b = 0; + a = (src >> 8) & 0xFF; break; default: _assert_msg_(SYSTEM, false, "Unsupported framebuffer format for screenshot: %d", fmt); @@ -223,24 +236,27 @@ static bool ConvertPixelTo888RGB(GPUDebugBufferFormat fmt, u8 &r, u8 &g, u8 &b, return true; } -const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h) { +const u8 *ConvertBufferToScreenshot(const GPUDebugBuffer &buf, bool alpha, u8 *&temp, u32 &w, u32 &h) { + int pixelSize = alpha ? 4 : 3; + GPUDebugBufferFormat nativeFmt = alpha ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_888_RGB; + w = std::min(w, buf.GetStride()); h = std::min(h, buf.GetHeight()); // The temp buffer will be freed by the caller if set, and can be the return value. - if (buf.GetFlipped() || buf.GetFormat() != GPU_DBG_FORMAT_888_RGB) { - temp = new u8[3 * w * h]; + if (buf.GetFlipped() || buf.GetFormat() != nativeFmt) { + temp = new u8[pixelSize * w * h]; } else { temp = nullptr; } const u8 *buffer = buf.GetData(); - if (buf.GetFlipped() && buf.GetFormat() == GPU_DBG_FORMAT_888_RGB) { + if (buf.GetFlipped() && buf.GetFormat() == nativeFmt) { // Silly OpenGL reads upside down, we flip to another buffer for simplicity. for (u32 y = 0; y < h; y++) { - memcpy(temp + y * w * 3, buffer + (buf.GetHeight() - y - 1) * buf.GetStride() * 3, w * 3); + memcpy(temp + y * w * pixelSize, buffer + (buf.GetHeight() - y - 1) * buf.GetStride() * pixelSize, w * pixelSize); } - } else if (buf.GetFormat() < GPU_DBG_FORMAT_FLOAT) { + } else if (buf.GetFormat() < GPU_DBG_FORMAT_FLOAT && buf.GetFormat() != nativeFmt) { // Let's boil it down to how we need to interpret the bits. int baseFmt = buf.GetFormat() & ~(GPU_DBG_FORMAT_REVERSE_FLAG | GPU_DBG_FORMAT_BRSWAP_FLAG); bool rev = (buf.GetFormat() & GPU_DBG_FORMAT_REVERSE_FLAG) != 0; @@ -252,21 +268,22 @@ const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u3 for (u32 x = 0; x < w; x++) { u8 *dst; if (flip) { - dst = &temp[(h - y - 1) * w * 3 + x * 3]; + dst = &temp[(h - y - 1) * w * pixelSize + x * pixelSize]; } else { - dst = &temp[y * w * 3 + x * 3]; + dst = &temp[y * w * pixelSize + x * pixelSize]; } u8 &r = brswap ? dst[2] : dst[0]; u8 &g = dst[1]; u8 &b = brswap ? dst[0] : dst[2]; + u8 &a = alpha ? dst[3] : r; - if (!ConvertPixelTo888RGB(GPUDebugBufferFormat(baseFmt), r, g, b, buffer, y * buf.GetStride() + x, rev)) { + if (!ConvertPixelTo8888RGBA(GPUDebugBufferFormat(baseFmt), r, g, b, a, buffer, y * buf.GetStride() + x, rev)) { return nullptr; } } } - } else if (buf.GetFormat() != GPU_DBG_FORMAT_888_RGB) { + } else if (buf.GetFormat() != nativeFmt) { bool flip = buf.GetFlipped(); // This is pretty inefficient. @@ -274,12 +291,13 @@ const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u3 for (u32 x = 0; x < w; x++) { u8 *dst; if (flip) { - dst = &temp[(h - y - 1) * w * 3 + x * 3]; + dst = &temp[(h - y - 1) * w * pixelSize + x * pixelSize]; } else { - dst = &temp[y * w * 3 + x * 3]; + dst = &temp[y * w * pixelSize + x * pixelSize]; } - if (!ConvertPixelTo888RGB(buf.GetFormat(), dst[0], dst[1], dst[2], buffer, y * buf.GetStride() + x, false)) { + u8 &a = alpha ? dst[3] : dst[0]; + if (!ConvertPixelTo8888RGBA(buf.GetFormat(), dst[0], dst[1], dst[2], a, buffer, y * buf.GetStride() + x, false)) { return nullptr; } } @@ -316,7 +334,7 @@ bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotTy u8 *flipbuffer = nullptr; if (success) { - const u8 *buffer = ConvertBufferTo888RGB(buf, flipbuffer, w, h); + const u8 *buffer = ConvertBufferToScreenshot(buf, false, flipbuffer, w, h); success = buffer != nullptr; if (success) { if (width) @@ -364,3 +382,25 @@ bool Save888RGBScreenshot(const char *filename, ScreenshotFormat fmt, const u8 * } #endif } + +bool Save8888RGBAScreenshot(const char *filename, const u8 *buffer, int w, int h) { +#ifdef USING_QT_UI + QImage image(buffer, w, h, QImage::Format_RGBA8888); + return image.save(filename, "PNG"); +#else + png_image png; + memset(&png, 0, sizeof(png)); + png.version = PNG_IMAGE_VERSION; + png.format = PNG_FORMAT_RGBA; + png.width = w; + png.height = h; + bool success = WriteScreenshotToPNG(&png, filename, 0, buffer, w * 4, nullptr); + png_image_free(&png); + + if (png.warning_or_error >= 2) { + ERROR_LOG(SYSTEM, "Saving screenshot to PNG produced errors."); + success = false; + } + return success; +#endif +} diff --git a/Core/Screenshot.h b/Core/Screenshot.h index 75214b54a2..1632a1434c 100644 --- a/Core/Screenshot.h +++ b/Core/Screenshot.h @@ -33,8 +33,9 @@ enum ScreenshotType { SCREENSHOT_RENDER, }; -const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h); +const u8 *ConvertBufferToScreenshot(const GPUDebugBuffer &buf, bool alpha, u8 *&temp, u32 &w, u32 &h); // Can only be used while in game. bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1); bool Save888RGBScreenshot(const char *filename, ScreenshotFormat fmt, const u8 *bufferRGB888, int w, int h); +bool Save8888RGBAScreenshot(const char *filename, const u8 *bufferRGBA8888, int w, int h); diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 325b346a38..86cf69d1b2 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -229,13 +229,18 @@ void CGEDebugger::PreviewExport(const GPUDebugBuffer *dbgBuffer) { std::string fn; if (W32Util::BrowseForFileName(false, GetDlgHandle(), L"Save Preview Image...", nullptr, filter, L"png", fn)) { ScreenshotFormat fmt = fn.find(".jpg") != fn.npos ? ScreenshotFormat::JPG : ScreenshotFormat::PNG; + bool saveAlpha = fmt == ScreenshotFormat::PNG; u8 *flipbuffer = nullptr; u32 w = (u32)-1; u32 h = (u32)-1; - const u8 *buffer = ConvertBufferTo888RGB(*dbgBuffer, flipbuffer, w, h); + const u8 *buffer = ConvertBufferToScreenshot(*dbgBuffer, saveAlpha, flipbuffer, w, h); if (buffer != nullptr) { - Save888RGBScreenshot(fn.c_str(), fmt, buffer, w, h); + if (saveAlpha) { + Save8888RGBAScreenshot(fn.c_str(), buffer, w, h); + } else { + Save888RGBScreenshot(fn.c_str(), fmt, buffer, w, h); + } } delete [] flipbuffer; } From 2031b2ef989a99c8c79f0f5059905b4180a0fc78 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 22 Dec 2017 12:29:08 -0800 Subject: [PATCH 6/9] GE Debugger: Fix some crashes while stepping. Mostly on Vulkan, but possibly on other backends. --- GPU/Common/FramebufferCommon.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 3a997f59ae..6c9a05135c 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -1967,8 +1967,11 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 } else { buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); } - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w); - return true; + // No need to free on failure, that's the caller's job (it likely will reuse a buffer.) + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w); + // That may have unbound the framebuffer, rebind to avoid crashes when debugging. + RebindFramebuffer(); + return retval; } bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) { @@ -1993,21 +1996,22 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G } bool flipY = (g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !useBufferedRendering_) ? true : false; + // No need to free on failure, the caller/destructor will do that. Usually this is a reused buffer, anyway. buffer.Allocate(w, h, GPU_DBG_FORMAT_8BIT, flipY); - if (draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w)) { - return true; - } else { - buffer.Free(); - return false; - } + bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w); + // That may have unbound the framebuffer, rebind to avoid crashes when debugging. + RebindFramebuffer(); + return retval; } bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { int w, h; draw_->GetFramebufferDimensions(nullptr, &w, &h); buffer.Allocate(w, h, GE_FORMAT_8888, false, true); - draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w); - return true; + bool retval = draw_->CopyFramebufferToMemorySync(nullptr, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w); + // That may have unbound the framebuffer, rebind to avoid crashes when debugging. + RebindFramebuffer(); + return retval; } // This function takes an already correctly-sized framebuffer and packs it into RAM. @@ -2110,7 +2114,7 @@ void FramebufferManagerCommon::RebindFramebuffer() { if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); } else { - // Should this even happen? + // Should this even happen? It could while debugging, but maybe we can just skip binding at all. draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); } gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); From a32ccd3eb8571d07550d30f5a3e129cd5ee1367b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 23 Dec 2017 01:31:04 -0800 Subject: [PATCH 7/9] GE Debugger: Fix preview when zooming. Before, the coordinates were only right when scaled to fit. When you zoomed in and panned, it would show in the wrong place because it wasn't accounting for the flipped backbuffer. --- Windows/GEDebugger/VertexPreview.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 75577a1a3c..8bad6b3331 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -189,8 +189,9 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); glBindTexture(GL_TEXTURE_2D, 0); - glViewport((GLint)x, (GLint)y, (GLsizei)fw, (GLsizei)fh); - glScissor((GLint)x, (GLint)y, (GLsizei)fw, (GLsizei)fh); + // The surface is upside down, so vertical offsets are negated. + glViewport((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); + glScissor((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); BindPreviewProgram(previewProgram); // TODO: Probably there's a better way and place to do this. @@ -277,8 +278,9 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); glBindTexture(GL_TEXTURE_2D, 0); - glViewport((GLint)x, (GLint)y, (GLsizei)fw, (GLsizei)fh); - glScissor((GLint)x, (GLint)y, (GLsizei)fw, (GLsizei)fh); + // The surface is upside down, so vertical offsets are flipped. + glViewport((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); + glScissor((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); BindPreviewProgram(texPreviewProgram); if (texPreviewVao == 0 && gl_extensions.ARB_vertex_array_object) { From c55db7a4963945a3857adeca9c8dab770c988a27 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 23 Dec 2017 01:57:03 -0800 Subject: [PATCH 8/9] GE Debugger: Keep prim preview on pan/zoom. --- Windows/GEDebugger/GEDebugger.cpp | 20 +- Windows/GEDebugger/GEDebugger.h | 5 +- Windows/GEDebugger/SimpleGLWindow.cpp | 26 ++- Windows/GEDebugger/SimpleGLWindow.h | 36 ++-- Windows/GEDebugger/VertexPreview.cpp | 289 +++++++++++++++----------- 5 files changed, 225 insertions(+), 151 deletions(-) diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 86cf69d1b2..1ffe5bdda5 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -167,6 +167,9 @@ void CGEDebugger::SetupPreviews() { return true; }); + primaryWindow->SetRedrawCallback([&] { + HandleRedraw(1); + }); primaryWindow->Clear(); } if (secondWindow == nullptr) { @@ -188,6 +191,9 @@ void CGEDebugger::SetupPreviews() { return true; }); + secondWindow->SetRedrawCallback([&] { + HandleRedraw(2); + }); secondWindow->Clear(); } } @@ -258,19 +264,18 @@ void CGEDebugger::UpdatePreviews() { state = gpuDebug->GetGState(); } + updating_ = true; UpdateTextureLevel(textureLevel_); UpdatePrimaryPreview(state); UpdateSecondPreview(state); + u32 primOp = PrimPreviewOp(); + if (primOp != 0) { + UpdatePrimPreview(primOp, 3); + } + DisplayList list; if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list)) { - const u32 op = Memory::Read_U32(list.pc); - const u32 cmd = op >> 24; - // TODO: Bezier/spline? - if (cmd == GE_CMD_PRIM && !showClut_) { - UpdatePrimPreview(op); - } - displayList->setDisplayList(list); } @@ -282,6 +287,7 @@ void CGEDebugger::UpdatePreviews() { matrices->Update(); lists->Update(); watch->Update(); + updating_ = false; } u32 CGEDebugger::TexturePreviewFlags(const GPUgstate &state) { diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index d520931054..c541337de2 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -70,8 +70,10 @@ private: void UpdatePreviews(); void UpdatePrimaryPreview(const GPUgstate &state); void UpdateSecondPreview(const GPUgstate &state); - void UpdatePrimPreview(u32 op); + u32 PrimPreviewOp(); + void UpdatePrimPreview(u32 op, int which); void CleanupPrimPreview(); + void HandleRedraw(int which); void UpdateSize(WORD width, WORD height); void SavePosition(); void SetBreakNext(BreakNextType type); @@ -106,6 +108,7 @@ private: const GPUDebugBuffer *primaryBuffer_ = nullptr; const GPUDebugBuffer *secondBuffer_ = nullptr; + bool updating_ = false; int minWidth_; int minHeight_; }; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index cd848cb03a..eab3370301 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -68,8 +68,7 @@ static const char basic_vs[] = "}\n"; SimpleGLWindow::SimpleGLWindow(HWND wnd) - : hWnd_(wnd), valid_(false), drawProgram_(nullptr), vao_(0), tex_(0), flags_(0), zoom_(false), - dragging_(false), offsetX_(0), offsetY_(0), reformatBuf_(nullptr), hoverCallback_(nullptr) { + : hWnd_(wnd) { SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this); } @@ -365,10 +364,23 @@ void SimpleGLWindow::GetContentSize(float &x, float &y, float &fw, float &fh) { void SimpleGLWindow::Redraw(bool andSwap) { DrawChecker(); - if (tw_ == 0 && th_ == 0) { + auto swapWithCallback = [andSwap, this]() { if (andSwap) { - Swap(); + swapped_ = false; + if (redrawCallback_ && !inRedrawCallback_) { + inRedrawCallback_ = true; + redrawCallback_(); + inRedrawCallback_ = false; + } + // In case the callback swaps, don't do it twice. + if (!swapped_) { + Swap(); + } } + }; + + if (tw_ == 0 && th_ == 0) { + swapWithCallback(); return; } @@ -412,7 +424,7 @@ void SimpleGLWindow::Redraw(bool andSwap) { glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, vao_ ? 0 : indices); if (andSwap) { - Swap(); + swapWithCallback(); } } @@ -423,7 +435,9 @@ void SimpleGLWindow::Clear() { } void SimpleGLWindow::Begin() { - Redraw(false); + if (!inRedrawCallback_) { + Redraw(false); + } if (vao_) { glBindVertexArray(0); diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index 5b08fcb95c..7cc305d9ca 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -81,6 +81,7 @@ struct SimpleGLWindow { } void Swap() { + swapped_ = true; SwapBuffers(hDC_); } @@ -106,6 +107,10 @@ struct SimpleGLWindow { void GetContentSize(float &x, float &y, float &fw, float &fh); + void SetRedrawCallback(std::function callback) { + redrawCallback_ = callback; + } + void SetHoverCallback(std::function hoverCallback) { hoverCallback_ = hoverCallback; } @@ -134,7 +139,7 @@ protected: HWND hWnd_; HDC hDC_; HGLRC hGLRC_; - bool valid_; + bool valid_ = false; // Width and height of the window. int w_; int h_; @@ -143,25 +148,28 @@ protected: int th_; bool tflipped_; - GLSLProgram *drawProgram_; - GLuint vao_; - GLuint ibuf_; - GLuint vbuf_; - GLuint checker_; - GLuint tex_; - u32 flags_; + GLSLProgram *drawProgram_ = nullptr; + GLuint vao_ = 0; + GLuint ibuf_ = 0; + GLuint vbuf_ = 0; + GLuint checker_ = 0; + GLuint tex_ = 0; + u32 flags_ = 0; // Disable shrink (toggled by double click.) - bool zoom_; - bool dragging_; + bool zoom_ = false; + bool dragging_ = false; + bool inRedrawCallback_ = false; + bool swapped_ = false; int dragStartX_; int dragStartY_; u32 dragLastUpdate_; // Offset to position the texture is drawn at. - int offsetX_; - int offsetY_; - u32 *reformatBuf_; - u32 reformatBufSize_; + int offsetX_ = 0; + int offsetY_ = 0; + u32 *reformatBuf_ = nullptr; + u32 reformatBufSize_ = 0; + std::function redrawCallback_; std::function hoverCallback_; std::function rightClickCallback_; HMENU rightClickMenu_; diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 8bad6b3331..4e91a35b6b 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -151,7 +151,21 @@ static void ExpandRectangles(std::vector &vertices, std::vector< count *= 3; } -void CGEDebugger::UpdatePrimPreview(u32 op) { +u32 CGEDebugger::PrimPreviewOp() { + DisplayList list; + if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list)) { + const u32 op = Memory::Read_U32(list.pc); + const u32 cmd = op >> 24; + // TODO: Bezier/spline? + if (cmd == GE_CMD_PRIM && !showClut_) { + return op; + } + } + + return 0; +} + +void CGEDebugger::UpdatePrimPreview(u32 op, int which) { const u32 prim_type = (op >> 16) & 0x7; int count = op & 0xFFFF; if (prim_type >= 7) { @@ -162,7 +176,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { ERROR_LOG(G3D, "Invalid debugging environment, shutting down?"); return; } - if (count == 0) { + if (count == 0 || which == 0) { return; } @@ -182,18 +196,6 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { float fw, fh; float x, y; - primaryWindow->Begin(); - primaryWindow->GetContentSize(x, y, fw, fh); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - glBindTexture(GL_TEXTURE_2D, 0); - // The surface is upside down, so vertical offsets are negated. - glViewport((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); - glScissor((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); - BindPreviewProgram(previewProgram); - // TODO: Probably there's a better way and place to do this. u16 minIndex = 0; u16 maxIndex = count - 1; @@ -210,125 +212,155 @@ void CGEDebugger::UpdatePrimPreview(u32 op) { } } - const float invTexWidth = 1.0f / gstate_c.curTextureWidth; - const float invTexHeight = 1.0f / gstate_c.curTextureHeight; + auto wrapCoord = [](float &coord) { + if (coord < 0.0f) { + coord += ceilf(-coord); + } + if (coord > 1.0f) { + coord -= floorf(coord); + } + }; + + const float invTexWidth = 1.0f / gpuDebug->GetGState().getTextureWidth(0); + const float invTexHeight = 1.0f / gpuDebug->GetGState().getTextureHeight(0); + const float invRealTexWidth = 1.0f / gstate_c.curTextureWidth; + const float invRealTexHeight = 1.0f / gstate_c.curTextureHeight; + bool clampS = gpuDebug->GetGState().isTexCoordClampedS(); + bool clampT = gpuDebug->GetGState().isTexCoordClampedT(); for (u16 i = minIndex; i <= maxIndex; ++i) { vertices[i].u *= invTexWidth; vertices[i].v *= invTexHeight; - if (vertices[i].u > 1.0f || vertices[i].u < 0.0f) - vertices[i].u -= floor(vertices[i].u); - if (vertices[i].v > 1.0f || vertices[i].v < 0.0f) - vertices[i].v -= floor(vertices[i].v); + if (!clampS) + wrapCoord(vertices[i].u); + if (!clampT) + wrapCoord(vertices[i].v); } - if (previewVao == 0 && gl_extensions.ARB_vertex_array_object) { - glGenVertexArrays(1, &previewVao); - glBindVertexArray(previewVao); - glEnableVertexAttribArray(previewProgram->a_position); + if (which & 1) { + primaryWindow->Begin(); + primaryWindow->GetContentSize(x, y, fw, fh); - glGenBuffers(1, &ibuf); - glGenBuffers(1, &vbuf); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); - glBindBuffer(GL_ARRAY_BUFFER, vbuf); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + glBindTexture(GL_TEXTURE_2D, 0); + // The surface is upside down, so vertical offsets are negated. + glViewport((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); + glScissor((GLint)x, (GLint)-(y + fh - primaryWindow->Height()), (GLsizei)fw, (GLsizei)fh); + BindPreviewProgram(previewProgram); - glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (void *)(2 * sizeof(float))); + if (previewVao == 0 && gl_extensions.ARB_vertex_array_object) { + glGenVertexArrays(1, &previewVao); + glBindVertexArray(previewVao); + glEnableVertexAttribArray(previewProgram->a_position); + + glGenBuffers(1, &ibuf); + glGenBuffers(1, &vbuf); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); + glBindBuffer(GL_ARRAY_BUFFER, vbuf); + + glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (void *)(2 * sizeof(float))); + } + + if (vbuf != 0) { + glBindBuffer(GL_ARRAY_BUFFER, vbuf); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GPUDebugVertex), vertices.data(), GL_STREAM_DRAW); + } + + if (ibuf != 0 && !indices.empty()) { + glBindVertexArray(previewVao); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(u16), indices.data(), GL_STREAM_DRAW); + } + + float scale[] = { + 480.0f / (float)PSP_CoreParameter().renderWidth, + 272.0f / (float)PSP_CoreParameter().renderHeight, + }; + + Matrix4x4 ortho; + ortho.setOrtho(-(float)gstate_c.curRTOffsetX, (primaryWindow->TexWidth() - (int)gstate_c.curRTOffsetX) * scale[0], primaryWindow->TexHeight() * scale[1], 0, -1, 1); + glUniformMatrix4fv(previewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); + if (previewVao != 0) { + glBindVertexArray(previewVao); + } else { + glEnableVertexAttribArray(previewProgram->a_position); + glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data() + 2); + } + + if (indices.empty()) { + glDrawArrays(glprim[prim], 0, count); + } else { + glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, previewVao != 0 ? 0 : indices.data()); + } + + if (previewVao == 0) { + glDisableVertexAttribArray(previewProgram->a_position); + } + + primaryWindow->End(); } - if (vbuf != 0) { - glBindBuffer(GL_ARRAY_BUFFER, vbuf); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GPUDebugVertex), vertices.data(), GL_STREAM_DRAW); + if (which & 2) { + secondWindow->Begin(); + secondWindow->GetContentSize(x, y, fw, fh); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + glBindTexture(GL_TEXTURE_2D, 0); + // The surface is upside down, so vertical offsets are flipped. + glViewport((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); + glScissor((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); + BindPreviewProgram(texPreviewProgram); + + if (texPreviewVao == 0 && gl_extensions.ARB_vertex_array_object) { + glGenVertexArrays(1, &texPreviewVao); + glBindVertexArray(texPreviewVao); + glEnableVertexAttribArray(texPreviewProgram->a_position); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); + glBindBuffer(GL_ARRAY_BUFFER, vbuf); + + glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), 0); + } + + // TODO: For some reason we have to re-upload the data? + if (vbuf != 0) { + glBindBuffer(GL_ARRAY_BUFFER, vbuf); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GPUDebugVertex), vertices.data(), GL_STREAM_DRAW); + } + + if (ibuf != 0 && !indices.empty()) { + glBindVertexArray(texPreviewVao); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(u16), indices.data(), GL_STREAM_DRAW); + } + + Matrix4x4 ortho; + ortho.setOrtho(0.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureXOffset * invRealTexWidth, 1.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, 0.0f - (float)gstate_c.curTextureYOffset * invRealTexHeight, -1.0f, 1.0f); + glUniformMatrix4fv(texPreviewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); + if (texPreviewVao != 0) { + glBindVertexArray(texPreviewVao); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); + glBindBuffer(GL_ARRAY_BUFFER, vbuf); + glEnableVertexAttribArray(texPreviewProgram->a_position); + glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), 0); + } else { + glEnableVertexAttribArray(texPreviewProgram->a_position); + glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data()); + } + + if (indices.empty()) { + glDrawArrays(glprim[prim], 0, count); + } else { + glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, texPreviewVao != 0 ? 0 : indices.data()); + } + + if (texPreviewVao == 0) { + glDisableVertexAttribArray(previewProgram->a_position); + } + + secondWindow->End(); } - - if (ibuf != 0 && !indices.empty()) { - glBindVertexArray(previewVao); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(u16), indices.data(), GL_STREAM_DRAW); - } - - float scale[] = { - 480.0f / (float)PSP_CoreParameter().renderWidth, - 272.0f / (float)PSP_CoreParameter().renderHeight, - }; - - Matrix4x4 ortho; - ortho.setOrtho(-(float)gstate_c.curRTOffsetX, (primaryWindow->TexWidth() - (int)gstate_c.curRTOffsetX) * scale[0], primaryWindow->TexHeight() * scale[1], 0, -1, 1); - glUniformMatrix4fv(previewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); - if (previewVao != 0) { - glBindVertexArray(previewVao); - } else { - glEnableVertexAttribArray(previewProgram->a_position); - glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data() + 2); - } - - if (indices.empty()) { - glDrawArrays(glprim[prim], 0, count); - } else { - glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, previewVao != 0 ? 0 : indices.data()); - } - - if (previewVao == 0) { - glDisableVertexAttribArray(previewProgram->a_position); - } - - primaryWindow->End(); - - secondWindow->Begin(); - secondWindow->GetContentSize(x, y, fw, fh); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - glBindTexture(GL_TEXTURE_2D, 0); - // The surface is upside down, so vertical offsets are flipped. - glViewport((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); - glScissor((GLint)x, (GLint)-(y + fh - secondWindow->Height()), (GLsizei)fw, (GLsizei)fh); - BindPreviewProgram(texPreviewProgram); - - if (texPreviewVao == 0 && gl_extensions.ARB_vertex_array_object) { - glGenVertexArrays(1, &texPreviewVao); - glBindVertexArray(texPreviewVao); - glEnableVertexAttribArray(texPreviewProgram->a_position); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); - glBindBuffer(GL_ARRAY_BUFFER, vbuf); - - glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), 0); - } - - // TODO: For some reason we have to re-upload the data? - if (vbuf != 0) { - glBindBuffer(GL_ARRAY_BUFFER, vbuf); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GPUDebugVertex), vertices.data(), GL_STREAM_DRAW); - } - - if (ibuf != 0 && !indices.empty()) { - glBindVertexArray(texPreviewVao); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(u16), indices.data(), GL_STREAM_DRAW); - } - - ortho.setOrtho(0.0f - (float)gstate_c.curTextureXOffset * invTexWidth, 1.0f - (float)gstate_c.curTextureXOffset * invTexWidth, 1.0f - (float)gstate_c.curTextureYOffset * invTexHeight, 0.0f - (float)gstate_c.curTextureYOffset * invTexHeight, -1.0f, 1.0f); - glUniformMatrix4fv(texPreviewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr()); - if (texPreviewVao != 0) { - glBindVertexArray(texPreviewVao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); - glBindBuffer(GL_ARRAY_BUFFER, vbuf); - glEnableVertexAttribArray(texPreviewProgram->a_position); - glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), 0); - } else { - glEnableVertexAttribArray(texPreviewProgram->a_position); - glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data()); - } - - if (indices.empty()) { - glDrawArrays(glprim[prim], 0, count); - } else { - glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, texPreviewVao != 0 ? 0 : indices.data()); - } - - if (texPreviewVao == 0) { - glDisableVertexAttribArray(previewProgram->a_position); - } - - secondWindow->End(); } void CGEDebugger::CleanupPrimPreview() { @@ -339,3 +371,14 @@ void CGEDebugger::CleanupPrimPreview() { glsl_destroy(texPreviewProgram); } } + +void CGEDebugger::HandleRedraw(int which) { + if (updating_) { + return; + } + + u32 op = PrimPreviewOp(); + if (op) { + UpdatePrimPreview(op, which); + } +} From 3c5816e2aafd7841ff314b1f27cfb6358cc9e962 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 23 Dec 2017 02:16:43 -0800 Subject: [PATCH 9/9] GE Debugger: Allow enable/disable of prim preview. --- Windows/GEDebugger/GEDebugger.cpp | 16 ++++++++++++++++ Windows/GEDebugger/GEDebugger.h | 1 + Windows/GEDebugger/SimpleGLWindow.cpp | 1 + Windows/GEDebugger/SimpleGLWindow.h | 1 + Windows/GEDebugger/VertexPreview.cpp | 1 + Windows/ppsspp.rc | 1 + Windows/resource.h | 3 ++- 7 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 1ffe5bdda5..2b1639971f 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -157,10 +157,18 @@ void CGEDebugger::SetupPreviews() { PrimaryPreviewHover(x, y); }); primaryWindow->SetRightClickMenu(subMenu, [&] (int cmd) { + HMENU subMenu = GetSubMenu(g_hPopupMenus, POPUP_SUBMENU_ID_GEDBG_PREVIEW); switch (cmd) { + case 0: + // Setup. + CheckMenuItem(subMenu, ID_GEDBG_ENABLE_PREVIEW, MF_BYCOMMAND | ((previewsEnabled_ & 1) ? MF_CHECKED : MF_UNCHECKED)); + break; case ID_GEDBG_EXPORT_IMAGE: PreviewExport(primaryBuffer_); break; + case ID_GEDBG_ENABLE_PREVIEW: + previewsEnabled_ ^= 1; + primaryWindow->Redraw(); default: break; } @@ -181,10 +189,18 @@ void CGEDebugger::SetupPreviews() { SecondPreviewHover(x, y); }); secondWindow->SetRightClickMenu(subMenu, [&] (int cmd) { + HMENU subMenu = GetSubMenu(g_hPopupMenus, POPUP_SUBMENU_ID_GEDBG_PREVIEW); switch (cmd) { + case 0: + // Setup. + CheckMenuItem(subMenu, ID_GEDBG_ENABLE_PREVIEW, MF_BYCOMMAND | ((previewsEnabled_ & 2) ? MF_CHECKED : MF_UNCHECKED)); + break; case ID_GEDBG_EXPORT_IMAGE: PreviewExport(secondBuffer_); break; + case ID_GEDBG_ENABLE_PREVIEW: + previewsEnabled_ ^= 2; + secondWindow->Redraw(); default: break; } diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index c541337de2..f47afc4236 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -109,6 +109,7 @@ private: const GPUDebugBuffer *secondBuffer_ = nullptr; bool updating_ = false; + int previewsEnabled_ = 3; int minWidth_; int minHeight_; }; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index eab3370301..f9c06b5c02 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -563,6 +563,7 @@ bool SimpleGLWindow::RightClick(int mouseX, int mouseY) { POINT pt{mouseX, mouseY}; ClientToScreen(hWnd_, &pt); + rightClickCallback_(0); int result = TrackPopupMenuEx(rightClickMenu_, TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hWnd_, 0); if (result != 0) { rightClickCallback_(result); diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index 7cc305d9ca..8628ab5eef 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -115,6 +115,7 @@ struct SimpleGLWindow { hoverCallback_ = hoverCallback; } + // Called first with 0 that it's opening, then the selected item. void SetRightClickMenu(HMENU menu, std::function callback) { rightClickCallback_ = callback; rightClickMenu_ = menu; diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 4e91a35b6b..1f78554d91 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -176,6 +176,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { ERROR_LOG(G3D, "Invalid debugging environment, shutting down?"); return; } + which &= previewsEnabled_; if (count == 0 || which == 0) { return; } diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 58b2d4ed4b..867613bd9d 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -657,6 +657,7 @@ BEGIN POPUP "gepreviewoptions" BEGIN MENUITEM "Export Image...", ID_GEDBG_EXPORT_IMAGE + MENUITEM "Show Prim Preview" ID_GEDBG_ENABLE_PREVIEW END END diff --git a/Windows/resource.h b/Windows/resource.h index 32710e3859..ba90e1ac79 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -335,6 +335,7 @@ #define ID_HELP_GITHUB 40168 #define IDC_GEDBG_RECORD 40169 #define ID_GEDBG_EXPORT_IMAGE 40170 +#define ID_GEDBG_ENABLE_PREVIEW 40171 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -347,7 +348,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 -#define _APS_NEXT_COMMAND_VALUE 40171 +#define _APS_NEXT_COMMAND_VALUE 40172 #define _APS_NEXT_CONTROL_VALUE 1200 #define _APS_NEXT_SYMED_VALUE 101 #endif