From e51ea856150bab6fad10401614c3de1e54c89520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 21 Jul 2018 22:47:29 +0200 Subject: [PATCH 01/58] Be extra careful about never ever binding null textures when drawing backgrounds. See #11243 --- UI/MainScreen.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index cbd9bf8a2d..5d1d521aac 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1079,17 +1079,20 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f return false; } + Draw::Texture *texture = nullptr; if (ginfo->pic1.texture) { - dc.GetDrawContext()->BindTexture(0, ginfo->pic1.texture->GetTexture()); + texture = ginfo->pic1.texture->GetTexture(); } else if (ginfo->pic0.texture) { - dc.GetDrawContext()->BindTexture(0, ginfo->pic0.texture->GetTexture()); + texture = ginfo->pic0.texture->GetTexture(); } uint32_t color = whiteAlpha(ease(progress)) & 0xFFc0c0c0; - dc.Draw()->DrawTexRect(dc.GetBounds(), 0,0,1,1, color); - dc.Flush(); - dc.RebindTexture(); - + if (texture) { + dc.GetDrawContext()->BindTexture(0, texture); + dc.Draw()->DrawTexRect(dc.GetBounds(), 0, 0, 1, 1, color); + dc.Flush(); + dc.RebindTexture(); + } return true; } From 5ad948df73ecf0d28c04ff86ef46944c715acc41 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 27 Jul 2018 20:04:36 -0700 Subject: [PATCH 02/58] Vulkan: Avoid discard when we can blend. Where possible, replace alpha and color testing with a zero alpha value. This allows early fragment tests more often, which may help #11227. It may also generally help performance on PowerVR devices. --- GPU/Common/GPUStateUtils.cpp | 16 +++++++++++++ GPU/Common/GPUStateUtils.h | 1 + GPU/Common/ShaderId.cpp | 3 +++ GPU/Common/ShaderId.h | 3 ++- GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 24 +++++++++++--------- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 4f2b4dd3bd..0194464d91 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -113,6 +113,22 @@ bool IsAlphaTestTriviallyTrue() { } } +bool NeedsTestDiscard() { + // We assume this is called only when enabled and not trivially true (may also be for color testing.) + if (gstate.isStencilTestEnabled() || gstate.isDepthTestEnabled()) + return true; + if (!gstate.isAlphaBlendEnabled()) + return true; + if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) + return true; + if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) + return true; + if (!safeDestFactors[(int)gstate.getBlendFuncB()]) + return true; + + return false; +} + bool IsAlphaTestAgainstZero() { return gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; } diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index e6b231d8e1..f6a4e11c21 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -44,6 +44,7 @@ bool IsAlphaTestTriviallyTrue(); bool IsColorTestAgainstZero(); bool IsColorTestTriviallyTrue(); bool IsAlphaTestAgainstZero(); +bool NeedsTestDiscard(); StencilValueType ReplaceAlphaWithStencilType(); ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend); diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 4a33f7c216..9a6d9afb82 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -268,12 +268,15 @@ void ComputeFragmentShaderID(ShaderID *id_out) { id.SetBit(FS_BIT_ALPHA_TEST); id.SetBits(FS_BIT_ALPHA_TEST_FUNC, 3, gstate.getAlphaTestFunction()); id.SetBit(FS_BIT_ALPHA_AGAINST_ZERO, IsAlphaTestAgainstZero()); + id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard()); } if (enableColorTest) { // 4 bits total. id.SetBit(FS_BIT_COLOR_TEST); id.SetBits(FS_BIT_COLOR_TEST_FUNC, 2, gstate.getColorTestFunction()); id.SetBit(FS_BIT_COLOR_AGAINST_ZERO, IsColorTestAgainstZero()); + // This is alos set in enableAlphaTest - color test is uncommon, but we can skip discard the same way. + id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard()); } id.SetBit(FS_BIT_ENABLE_FOG, enableFog); diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 7d2e1b1cdd..740e321fe8 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -86,7 +86,8 @@ enum { FS_BIT_BLENDFUNC_B = 42, // 4 bits FS_BIT_FLATSHADE = 46, FS_BIT_BGRA_TEXTURE = 47, - // 48+ are free. + FS_BIT_TEST_DISCARD_TO_ZERO = 48, + // 49+ are free. }; struct ShaderID { diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index a8d3100098..d35ade99e5 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -56,6 +56,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { bool enableAlphaTest = id.Bit(FS_BIT_ALPHA_TEST); bool alphaTestAgainstZero = id.Bit(FS_BIT_ALPHA_AGAINST_ZERO); + bool testForceToZero = id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO); bool enableColorTest = id.Bit(FS_BIT_COLOR_TEST); bool colorTestAgainstZero = id.Bit(FS_BIT_COLOR_AGAINST_ZERO); bool enableColorDoubling = id.Bit(FS_BIT_COLOR_DOUBLE); @@ -82,7 +83,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { bool isModeClear = id.Bit(FS_BIT_CLEARMODE); const char *shading = doFlatShading ? "flat" : ""; - bool earlyFragmentTests = !enableAlphaTest && !enableColorTest && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); if (earlyFragmentTests) { WRITE(p, "layout (early_fragment_tests) in;\n"); @@ -347,27 +348,28 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { // So we have to scale to account for the difference. std::string alphaTestXCoord = "0"; + const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "discard;"; if (enableAlphaTest) { if (alphaTestAgainstZero) { // When testing against 0 (extremely common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. if (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) { - WRITE(p, " if (v.a < 0.002) discard;\n"); + WRITE(p, " if (v.a < 0.002) %s\n", discardStatement); } else if (alphaTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. Happens sometimes, actually... - WRITE(p, " if (v.a > 0.002) discard;\n"); + WRITE(p, " if (v.a > 0.002) %s\n", discardStatement); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; if (alphaTestFuncs[alphaTestFunc][0] != '#') { - WRITE(p, " if ((roundAndScaleTo255i(v.a) & base.alphacolormask.a) %s base.alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if ((roundAndScaleTo255i(v.a) & base.alphacolormask.a) %s base.alphacolorref.a) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } else { // This means NEVER. See above. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } } @@ -378,22 +380,22 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { // Have my doubts that this special case is actually worth it, but whatever. // 0.002 is approximately half of 1.0 / 255.0. if (colorTestFunc == GE_COMP_NOTEQUAL) { - WRITE(p, " if (v.r + v.g + v.b < 0.002) discard;\n"); + WRITE(p, " if (v.r + v.g + v.b < 0.002) %s\n", discardStatement); } else if (colorTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. - WRITE(p, " if (v.r + v.g + v.b > 0.002) discard;\n"); + WRITE(p, " if (v.r + v.g + v.b > 0.002) %s\n", discardStatement); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; if (colorTestFuncs[colorTestFunc][0] != '#') { WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); - WRITE(p, " if ((v_scaled & base.alphacolormask.rgb) %s (base.alphacolorref.rgb & base.alphacolormask.rgb)) discard;\n", colorTestFuncs[colorTestFunc]); + WRITE(p, " if ((v_scaled & base.alphacolormask.rgb) %s (base.alphacolorref.rgb & base.alphacolormask.rgb)) %s\n", colorTestFuncs[colorTestFunc], discardStatement); } else { - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } } From 8e49fa988c002976b24f0f7e7411fd9726239360 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 27 Jul 2018 20:06:41 -0700 Subject: [PATCH 03/58] GLES: Avoid discard when we can blend. May improve performance on PowerVR. --- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 36 +++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 20cfebbfe5..0c11d82344 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -151,6 +151,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform bool enableAlphaTest = id.Bit(FS_BIT_ALPHA_TEST); bool alphaTestAgainstZero = id.Bit(FS_BIT_ALPHA_AGAINST_ZERO); + bool testForceToZero = id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO); bool enableColorTest = id.Bit(FS_BIT_COLOR_TEST); bool colorTestAgainstZero = id.Bit(FS_BIT_COLOR_AGAINST_ZERO); bool enableColorDoubling = id.Bit(FS_BIT_COLOR_DOUBLE); @@ -510,39 +511,40 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } } + const char *discardStatement = testForceToZero ? "v.a = 0.0;" : "discard;"; if (enableAlphaTest) { if (alphaTestAgainstZero) { // When testing against 0 (extremely common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. if (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) { - WRITE(p, " if (v.a < 0.002) discard;\n"); + WRITE(p, " if (v.a < 0.002) %s\n", discardStatement); } else if (alphaTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. Happens sometimes, actually... - WRITE(p, " if (v.a > 0.002) discard;\n"); + WRITE(p, " if (v.a > 0.002) %s\n", discardStatement); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { WRITE(p, " float aResult = %s(testtex, vec2(%s, 0)).a;\n", texture, alphaTestXCoord.c_str()); - WRITE(p, " if (aResult < 0.5) discard;\n"); + WRITE(p, " if (aResult < 0.5) %s\n", discardStatement); } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; if (alphaTestFuncs[alphaTestFunc][0] != '#') { if (bitwiseOps) { - WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) discard;\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { // Work around bad PVR driver problem where equality check + discard just doesn't work. if (alphaTestFunc != GE_COMP_NOTEQUAL) { - WRITE(p, " if (roundTo255thf(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if (roundTo255thf(v.a) %s u_alphacolorref.a) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } } else { - WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } } else { // This means NEVER. See above. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } } @@ -552,14 +554,14 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform // When testing against 0 (common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. if (colorTestFunc == GE_COMP_NOTEQUAL) { - WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) discard;\n"); + WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) %s\n", discardStatement); } else if (colorTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. - WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) discard;\n"); + WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) %s\n", discardStatement); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { WRITE(p, " float rResult = %s(testtex, vec2(vScale256.r, 0)).r;\n", texture); @@ -567,10 +569,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " float bResult = %s(testtex, vec2(vScale256.b, 0)).b;\n", texture); if (colorTestFunc == GE_COMP_EQUAL) { // Equal means all parts must be equal. - WRITE(p, " if (rResult < 0.5 || gResult < 0.5 || bResult < 0.5) discard;\n"); + WRITE(p, " if (rResult < 0.5 || gResult < 0.5 || bResult < 0.5) %s\n", discardStatement); } else { // Not equal means any part must be not equal. - WRITE(p, " if (rResult < 0.5 && gResult < 0.5 && bResult < 0.5) discard;\n"); + WRITE(p, " if (rResult < 0.5 && gResult < 0.5 && bResult < 0.5) %s\n", discardStatement); } } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; @@ -580,14 +582,14 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); const char *maskedFragColor = "ivec3(v_scaled.r & u_alphacolormask.r, v_scaled.g & u_alphacolormask.g, v_scaled.b & u_alphacolormask.b)"; const char *maskedColorRef = "ivec3(int(u_alphacolorref.r) & u_alphacolormask.r, int(u_alphacolorref.g) & u_alphacolormask.g, int(u_alphacolorref.b) & u_alphacolormask.b)"; - WRITE(p, " if (%s %s %s) discard;\n", maskedFragColor, colorTestFuncs[colorTestFunc], maskedColorRef); + WRITE(p, " if (%s %s %s) %s\n", maskedFragColor, colorTestFuncs[colorTestFunc], maskedColorRef, discardStatement); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { - WRITE(p, " if (roundTo255thv(v.rgb) %s u_alphacolorref.rgb) discard;\n", colorTestFuncs[colorTestFunc]); + WRITE(p, " if (roundTo255thv(v.rgb) %s u_alphacolorref.rgb) %s\n", colorTestFuncs[colorTestFunc], discardStatement); } else { - WRITE(p, " if (roundAndScaleTo255v(v.rgb) %s u_alphacolorref.rgb) discard;\n", colorTestFuncs[colorTestFunc]); + WRITE(p, " if (roundAndScaleTo255v(v.rgb) %s u_alphacolorref.rgb) %s\n", colorTestFuncs[colorTestFunc], discardStatement); } } else { - WRITE(p, " discard;\n"); + WRITE(p, " %s\n", discardStatement); } } } From 5ccd3ee4dcf4048815cc5f43837f4f9c15358f88 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 27 Jul 2018 20:10:26 -0700 Subject: [PATCH 04/58] GPU: Allow skipping discard when write disabled. Even if we depth test, if we don't write, we can still force alpha to zero. --- GPU/Common/GPUStateUtils.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 0194464d91..9da2049d61 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -115,7 +115,9 @@ bool IsAlphaTestTriviallyTrue() { bool NeedsTestDiscard() { // We assume this is called only when enabled and not trivially true (may also be for color testing.) - if (gstate.isStencilTestEnabled() || gstate.isDepthTestEnabled()) + if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) + return true; + if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) return true; if (!gstate.isAlphaBlendEnabled()) return true; From 42f4d7b40f0c86f996c764be0386d179dbb2aca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 28 Jul 2018 11:09:01 +0200 Subject: [PATCH 05/58] OpenGL: Fix bug where we could end up calling glUniformMatrix without a bound program. Found by GL debug callback on NV. This adds a bit of extra checking that's only enabled in _DEBUG builds. --- GPU/Common/FramebufferCommon.cpp | 13 +++++++++++-- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/GLES/ShaderManagerGLES.h | 2 +- GPU/GLES/StencilBufferGLES.cpp | 1 + GPU/GLES/TextureCacheGLES.cpp | 3 ++- ext/native/thin3d/GLQueueRunner.cpp | 2 ++ ext/native/thin3d/GLRenderManager.cpp | 7 +++++++ ext/native/thin3d/GLRenderManager.h | 28 +++++++++++++++++++++++++++ 8 files changed, 53 insertions(+), 5 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index b8b1b7a48a..af1162b315 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -582,6 +582,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe DownloadFramebufferOnSwitch(prevVfb); } textureCache_->ForgetLastTexture(); + shaderManager_->DirtyLastShader(); // Copy depth pixel value from the read framebuffer to the draw framebuffer if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { @@ -600,6 +601,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { + shaderManager_->DirtyLastShader(); if (gl_extensions.IsGLES) { // Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering // to it. This broke stuff before, so now it only clears on the first use of an @@ -839,6 +841,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) { void FramebufferManagerCommon::CopyDisplayToOutput() { DownloadFramebufferOnSwitch(currentRenderVfb_); + shaderManager_->DirtyLastShader(); currentRenderVfb_ = 0; @@ -846,6 +849,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { + shaderManager_->DirtyLastShader(); draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); } gstate_c.Dirty(DIRTY_BLEND_STATE); @@ -910,6 +914,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { } if (!vfb) { + shaderManager_->DirtyLastShader(); if (useBufferedRendering_) { // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); @@ -925,6 +930,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { DEBUG_LOG(FRAMEBUF, "Found no FBO to display! displayFBPtr = %08x", displayFramebufPtr_); // No framebuffer to display! Clear to black. if (useBufferedRendering_) { + shaderManager_->DirtyLastShader(); // Bind and clear the backbuffer. This should be the first time during the frame that it's bound. draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); } @@ -963,6 +969,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight; if (!usePostShader_) { + shaderManager_->DirtyLastShader(); draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); @@ -987,13 +994,13 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { } } else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { // An additional pass, post-processing shader to the extra FBO. + shaderManager_->DirtyLastShader(); // dirty lastShader_ draw_->BindFramebufferAsRenderTarget(extraFBOs_[0], { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0); int fbo_w, fbo_h; draw_->GetFramebufferDimensions(extraFBOs_[0], &fbo_w, &fbo_h); SetViewport2D(0, 0, fbo_w, fbo_h); draw_->SetScissorRect(0, 0, fbo_w, fbo_h); - shaderManager_->DirtyLastShader(); // dirty lastShader_ PostShaderUniforms uniforms{}; CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, renderWidth_, renderHeight_, &uniforms); BindPostShader(uniforms); @@ -1031,6 +1038,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); } } else { + shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0); draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); @@ -1040,7 +1048,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { std::swap(v0, v1); DrawTextureFlags flags = (!postShaderIsUpscalingFilter_ && g_Config.iBufFilter == SCALE_LINEAR) ? DRAWTEX_LINEAR : DRAWTEX_NEAREST; - shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing PostShaderUniforms uniforms{}; CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, vfb->renderWidth, vfb->renderHeight, &uniforms); BindPostShader(uniforms); @@ -1181,6 +1188,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, return; } + shaderManager_->DirtyLastShader(); vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format); @@ -2128,6 +2136,7 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo } void FramebufferManagerCommon::RebindFramebuffer() { + shaderManager_->DirtyLastShader(); if (currentRenderVfb_ && currentRenderVfb_->fbo) { draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); } else { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index e9ed8a58d6..703b823cbe 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -625,7 +625,7 @@ void ShaderManagerGLES::DirtyShader() { shaderSwitchDirtyUniforms_ = 0; } -void ShaderManagerGLES::DirtyLastShader() { // disables vertex arrays +void ShaderManagerGLES::DirtyLastShader() { lastShader_ = nullptr; lastVShaderSame_ = false; } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 33d187301b..fdcd2ce98b 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -166,7 +166,7 @@ public: void DeviceRestore(Draw::DrawContext *draw); void DirtyShader(); - void DirtyLastShader() override; // disables vertex arrays + void DirtyLastShader() override; int GetNumVertexShaders() const { return (int)vsCache_.size(); } int GetNumFragmentShaders() const { return (int)fsCache_.size(); } diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index d8effd95ae..dee08b4577 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -110,6 +110,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe // Common when creating buffers, it's already 0. We're done. return false; } + shaderManagerGL_->DirtyLastShader(); // Let's not bother with the shader if it's just zero. if (dstBuffer->fbo) { diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index e390ed322a..555160352c 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -473,11 +473,12 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram depal = depalShaderCache_->GetDepalettizeShader(clutMode, framebuffer->drawnFormat); } if (depal) { + shaderManager_->DirtyLastShader(); + const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); GLRTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); Draw::Framebuffer *depalFBO = framebufferManagerGL_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); - shaderManager_->DirtyLastShader(); render_->SetScissor(GLRect2D{ 0, 0, (int)framebuffer->renderWidth, (int)framebuffer->renderHeight }); render_->SetViewport(GLRViewport{ 0.0f, 0.0f, (float)framebuffer->renderWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f }); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 1ae55e39f6..d3ad94095e 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -749,6 +749,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } case GLRRenderCommand::UNIFORM4I: { + assert(curProgram); int loc = c.uniform4.loc ? *c.uniform4.loc : -1; if (c.uniform4.name) { loc = curProgram->GetUniformLoc(c.uniform4.name); @@ -774,6 +775,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } case GLRRenderCommand::UNIFORMMATRIX: { + assert(curProgram); int loc = c.uniform4.loc ? *c.uniform4.loc : -1; if (c.uniform4.name) { loc = curProgram->GetUniformLoc(c.uniform4.name); diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index 75de166d37..8751b9b7d3 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -228,6 +228,9 @@ void GLRenderManager::StopThread() { void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil) { assert(insideFrame_); +#ifdef _DEBUG + curProgram_ = nullptr; +#endif // Eliminate dupes. if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == GLRStepType::RENDER) { if (color != GLRRenderPassAction::CLEAR && depth != GLRRenderPassAction::CLEAR && stencil != GLRRenderPassAction::CLEAR) { @@ -360,6 +363,10 @@ void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, i void GLRenderManager::BeginFrame() { VLOG("BeginFrame"); +#ifdef _DEBUG + curProgram_ = nullptr; +#endif + int curFrame = GetCurFrame(); FrameData &frameData = frameData_[curFrame]; diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 16bc24a732..0a09068b90 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -551,6 +551,9 @@ public: _dbg_assert_(G3D, program != nullptr); data.program.program = program; curRenderStep_->commands.push_back(data); +#ifdef _DEBUG + curProgram_ = program; +#endif } void BindPixelPackBuffer(GLRBuffer *buffer) { // Want to support an offset but can't in ES 2.0. We supply an offset when binding the buffers instead. @@ -604,6 +607,9 @@ public: void SetUniformI(GLint *loc, int count, const int *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORM4I }; data.uniform4.loc = loc; data.uniform4.count = count; @@ -613,6 +619,9 @@ public: void SetUniformI1(GLint *loc, int udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORM4I }; data.uniform4.loc = loc; data.uniform4.count = 1; @@ -622,6 +631,9 @@ public: void SetUniformF(GLint *loc, int count, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.loc = loc; data.uniform4.count = count; @@ -631,6 +643,9 @@ public: void SetUniformF1(GLint *loc, const float udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.loc = loc; data.uniform4.count = 1; @@ -640,6 +655,9 @@ public: void SetUniformF(const char *name, int count, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORM4F }; data.uniform4.name = name; data.uniform4.count = count; @@ -649,6 +667,9 @@ public: void SetUniformM4x4(GLint *loc, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORMMATRIX }; data.uniformMatrix4.loc = loc; memcpy(data.uniformMatrix4.m, udata, sizeof(float) * 16); @@ -657,6 +678,9 @@ public: void SetUniformM4x4(const char *name, const float *udata) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); +#ifdef _DEBUG + assert(curProgram_); +#endif GLRRenderData data{ GLRRenderCommand::UNIFORMMATRIX }; data.uniformMatrix4.name = name; memcpy(data.uniformMatrix4.m, udata, sizeof(float) * 16); @@ -937,4 +961,8 @@ private: int targetWidth_ = 0; int targetHeight_ = 0; + +#ifdef _DEBUG + GLRProgram *curProgram_ = nullptr; +#endif }; From c4717fae2f69baa8ce393d0ae400df1d1afb8681 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 28 Jul 2018 09:37:12 -0700 Subject: [PATCH 06/58] Savedata: Reset data size when retrying hash. It's even possible we might've not loaded the key before, so let's play it safe and reset everything. The previous fix only worked in some games, when dataSize was larger than necessary. --- Core/Dialog/SavedataParam.cpp | 27 ++++++++++++++++++--------- Core/Dialog/SavedataParam.h | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 3182f3b3df..dfb436dca7 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -642,20 +642,28 @@ int SavedataParam::DetermineCryptMode(const SceUtilitySavedataParam *param) cons return decryptMode; } -void SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, u8 *saveData, int &saveSize, int prevCryptMode, const u8 *expectedHash, bool &saveDone) { +void SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, const u8 *saveData, int &saveSize, int prevCryptMode, const u8 *expectedHash, bool &saveDone) { + int orig_size = saveSize; int align_len = align16(saveSize); u8 *data_base = new u8[align_len]; u8 *cryptKey = new u8[0x10]; - memset(cryptKey, 0, 0x10); int decryptMode = DetermineCryptMode(param); const int detectedMode = decryptMode; - bool hasKey = decryptMode > 1; - if (hasKey) { - memcpy(cryptKey, param->key, 0x10); - } - memset(data_base + saveSize, 0, align_len - saveSize); - memcpy(data_base, saveData, saveSize); + bool hasKey; + + auto resetData = [&](int mode) { + saveSize = orig_size; + align_len = align16(saveSize); + hasKey = mode > 1; + + if (hasKey) { + memcpy(cryptKey, param->key, 0x10); + } + memcpy(data_base, saveData, saveSize); + memset(data_base + saveSize, 0, align_len - saveSize); + }; + resetData(decryptMode); if (decryptMode != prevCryptMode) { if (prevCryptMode == 1 && param->key[0] == 0) { @@ -688,12 +696,13 @@ void SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, u8 int err = DecryptSave(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); // Perhaps the file had the wrong mode.... if (err != 0 && detectedMode != decryptMode) { - hasKey = detectedMode > 1; + resetData(detectedMode); err = DecryptSave(detectedMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, expectedHash); } // TODO: Should return an error, but let's just try with a bad hash. if (err != 0 && expectedHash != nullptr) { WARN_LOG(SCEUTILITY, "Incorrect hash on save data, likely corrupt"); + resetData(decryptMode); err = DecryptSave(decryptMode, data_base, &saveSize, &align_len, hasKey ? cryptKey : nullptr, nullptr); } diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 0a26f1aeb1..e509463712 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -361,7 +361,7 @@ private: void ClearFileInfo(SaveFileInfo &saveInfo, const std::string &saveName); int LoadSaveData(SceUtilitySavedataParam *param, const std::string &saveDirName, const std::string& dirPath, bool secureMode); - void LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, u8 *saveData, int &saveSize, int prevCryptMode, const u8 *expectedHash, bool &saveDone); + void LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, const u8 *saveData, int &saveSize, int prevCryptMode, const u8 *expectedHash, bool &saveDone); void LoadNotCryptedSave(SceUtilitySavedataParam *param, u8 *data, u8 *saveData, int &saveSize); void LoadSFO(SceUtilitySavedataParam *param, const std::string& dirPath); void LoadFile(const std::string& dirPath, const std::string& filename, PspUtilitySavedataFileData *fileData); From fba0de59c10a51dd43bfdc838f9c8562d93cb2c0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:03:55 -0700 Subject: [PATCH 07/58] GPU: Restrict alpha test to zero for dest blend. We could end up with the wrong blending in other cases, because the exiting color will get multiplied. Luckily, this is still the common case. --- GPU/Common/GPUStateUtils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 9da2049d61..47605f64b7 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -125,7 +125,12 @@ bool NeedsTestDiscard() { return true; if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) return true; - if (!safeDestFactors[(int)gstate.getBlendFuncB()]) + // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. + if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { + if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) + return true; + } + if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) return true; return false; From 78dc07e7a3af43147944f4f3be87a25dc2c69ef1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:07:29 -0700 Subject: [PATCH 08/58] Headless: Fix graphics tests for Vulkan/Direct3D. Otherwise we hang because there's no thread to ever end. --- GPU/GLES/TextureCacheGLES.cpp | 1 + headless/WindowsHeadlessHost.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 555160352c..659f9540fe 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -862,6 +862,7 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); // Not a framebuffer, so let's assume these are right. + // TODO: But they may definitely not be, if the texture was scaled. int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 9bfe3d7832..f2172f7238 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -163,7 +163,7 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte void WindowsHeadlessHost::ShutdownGraphics() { gfx_->StopThread(); - while (threadState_ != RenderThreadState::STOPPED) + while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE) sleep_ms(1); gfx_->Shutdown(); From 7885a88c0ca408039e3645d51b823dd67baaa9ce Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:37:04 -0700 Subject: [PATCH 09/58] GPU: Optimize > 0 alpha test using discard rules. It should be equally unsafe to use src color as dest blend factor, or use blending with a subtract or min/max equation. --- GPU/Common/GPUStateUtils.cpp | 82 ++++++++++++------------------------ 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 47605f64b7..0353e3ac96 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -40,20 +40,28 @@ bool CanUseHardwareTransform(int prim) { return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; } -// Dest factors where it's safe to eliminate the alpha test under certain conditions -static const bool safeDestFactors[16] = { - true, // GE_DSTBLEND_SRCCOLOR, - true, // GE_DSTBLEND_INVSRCCOLOR, - false, // GE_DSTBLEND_SRCALPHA, - true, // GE_DSTBLEND_INVSRCALPHA, - true, // GE_DSTBLEND_DSTALPHA, - true, // GE_DSTBLEND_INVDSTALPHA, - false, // GE_DSTBLEND_DOUBLESRCALPHA, - false, // GE_DSTBLEND_DOUBLEINVSRCALPHA, - true, // GE_DSTBLEND_DOUBLEDSTALPHA, - true, // GE_DSTBLEND_DOUBLEINVDSTALPHA, - true, //GE_DSTBLEND_FIXB, -}; +bool NeedsTestDiscard() { + // We assume this is called only when enabled and not trivially true (may also be for color testing.) + if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) + return true; + if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) + return true; + if (!gstate.isAlphaBlendEnabled()) + return true; + if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) + return true; + // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. + if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { + if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) + return true; + } + if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) + return true; + if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) + return true; + + return false; +} bool IsAlphaTestTriviallyTrue() { switch (gstate.getAlphaTestFunction()) { @@ -80,25 +88,10 @@ bool IsAlphaTestTriviallyTrue() { case GE_COMP_GREATER: { -#if 0 - // Easy way to check the values in the debugger without ruining && early-out - bool doTextureAlpha = gstate.isTextureAlphaUsed(); - bool stencilTest = gstate.isStencilTestEnabled(); - bool depthTest = gstate.isDepthTestEnabled(); - GEComparison depthTestFunc = gstate.getDepthTestFunction(); - int alphaRef = gstate.getAlphaTestRef(); - int blendA = gstate.getBlendFuncA(); - bool blendEnabled = gstate.isAlphaBlendEnabled(); - int blendB = gstate.getBlendFuncA(); -#endif - return (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed())) || ( - (!gstate.isStencilTestEnabled() && - !gstate.isDepthTestEnabled() && - (!gstate.isLogicOpEnabled() || gstate.getLogicOp() == GE_LOGIC_COPY) && - gstate.getAlphaTestRef() == 0 && - gstate.isAlphaBlendEnabled() && - gstate.getBlendFuncA() == GE_SRCBLEND_SRCALPHA && - safeDestFactors[(int)gstate.getBlendFuncB()])); + // If the texture and vertex only use 1.0 alpha, then the ref value doesn't matter. + if (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed())) + return true; + return gstate.getAlphaTestRef() == 0 && !NeedsTestDiscard(); } case GE_COMP_LEQUAL: @@ -113,29 +106,6 @@ bool IsAlphaTestTriviallyTrue() { } } -bool NeedsTestDiscard() { - // We assume this is called only when enabled and not trivially true (may also be for color testing.) - if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) - return true; - if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) - return true; - if (!gstate.isAlphaBlendEnabled()) - return true; - if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) - return true; - if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) - return true; - // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. - if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { - if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) - return true; - } - if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) - return true; - - return false; -} - bool IsAlphaTestAgainstZero() { return gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; } From 85e742149a92007da2b8fcf63a48c4d3c2e0ac63 Mon Sep 17 00:00:00 2001 From: Sven <40953353+RetroSven@users.noreply.github.com> Date: Tue, 31 Jul 2018 23:57:10 -0400 Subject: [PATCH 10/58] add libretro hooks for memory pointers to allow usage of new retroarch cheat code searching and rumble-on-memory change features --- libretro/libretro.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index e5cedb7298..cca5331e86 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -15,6 +15,7 @@ #include "Core/HLE/__sceAudio.h" #include "Core/HW/MemoryStick.h" #include "Core/Host.h" +#include "Core/MemMap.h" #include "Core/System.h" #include "Log.h" #include "LogManager.h" @@ -714,12 +715,16 @@ bool retro_unserialize(const void *data, size_t size) { } void *retro_get_memory_data(unsigned id) { - (void)id; + if ( id == RETRO_MEMORY_SYSTEM_RAM ) { + return Memory::GetPointerUnchecked(PSP_GetKernelMemoryBase()) ; + } return NULL; } size_t retro_get_memory_size(unsigned id) { - (void)id; + if ( id == RETRO_MEMORY_SYSTEM_RAM ) { + return Memory::g_MemorySize ; + } return 0; } From 5b7f355b2b4c35eeb57042af636a22f6ebc4e6d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 5 Aug 2018 10:42:29 +0200 Subject: [PATCH 11/58] Update glslang again. Might fix #11276 --- ext/glslang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/glslang b/ext/glslang index 806af25f74..29619b2312 160000 --- a/ext/glslang +++ b/ext/glslang @@ -1 +1 @@ -Subproject commit 806af25f749b4d7cd861eaebc32474b3a7d102c0 +Subproject commit 29619b2312f7bc862221749f3f4d37c3e6a0dee2 From 77f0499f7f4f1dc4105fe05d29005261294dce8e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 17:11:51 -0700 Subject: [PATCH 12/58] GPU: Rename clipping flag to depth clamp. It seems to just to depth clamp. When depth clamp happens, it affects clipping a little, but only for vertices that needed clamping. --- GPU/Common/GPUStateUtils.cpp | 2 +- GPU/GPUState.h | 5 +++-- GPU/Software/Clipper.cpp | 9 +++++++-- GPU/Software/TransformUnit.cpp | 2 +- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 0353e3ac96..824d3827b1 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -676,7 +676,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float minz = gstate.getDepthRangeMin(); float maxz = gstate.getDepthRangeMax(); - if (gstate.isClippingEnabled() && (minz == 0 || maxz == 65535)) { + if (gstate.isDepthClampEnabled() && (minz == 0 || maxz == 65535)) { // Here, we should "clamp." But clamping per fragment would be slow. // So, instead, we just increase the available range and hope. // If depthSliceFactor is 4, it means (75% / 2) of the depth lies in each direction. diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 06b14867c4..a73023927f 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -58,7 +58,7 @@ struct GPUgstate { region2, lightingEnable, lightEnable[4], - clipEnable, + depthClampEnable, cullfaceEnable, textureMapEnable, // 0x1E GE_CMD_TEXTUREMAPENABLE fogEnable, @@ -392,8 +392,9 @@ struct GPUgstate { int getRegionX2() const { return (region2 & 0x3FF); } int getRegionY2() const { return (region2 >> 10) & 0x3FF; } + bool isDepthClampEnabled() const { return depthClampEnable & 1; } + // Note that the X1/Y1/Z1 here does not mean the upper-left corner, but half the dimensions. X2/Y2/Z2 are the center. - bool isClippingEnabled() const { return clipEnable & 1; } float getViewportXScale() const { return getFloat24(viewportxscale); } float getViewportYScale() const { return getFloat24(viewportyscale); } float getViewportZScale() const { return getFloat24(viewportzscale); } diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 2dcb1dd919..85c9fc6efd 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -39,6 +39,7 @@ enum { static inline int CalcClipMask(const ClipCoords& v) { int mask = 0; + // This checks `x / w` compared to 1 or -1, skipping the division. if (v.x > v.w) mask |= CLIP_POS_X_BIT; if (v.x < -v.w) mask |= CLIP_NEG_X_BIT; if (v.y > v.w) mask |= CLIP_POS_Y_BIT; @@ -255,7 +256,9 @@ void ProcessLine(VertexData& v0, VertexData& v1) return; } - if (mask && gstate.isClippingEnabled()) { + if (mask && gstate.isDepthClampEnabled()) { + // TODO: Validate if this logic is correct / should be in depthClampEnabled. + // discard if any vertex is outside the near clipping plane if (mask & CLIP_NEG_Z_BIT) return; @@ -303,7 +306,9 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) mask |= CalcClipMask(v1.clippos); mask |= CalcClipMask(v2.clippos); - if (mask && gstate.isClippingEnabled()) { + if (mask && gstate.isDepthClampEnabled()) { + // TODO: Validate if this logic is correct / should be in depthClampEnabled. + // discard if any vertex is outside the near clipping plane if (mask & CLIP_NEG_Z_BIT) return; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index f1e7e9581b..911bdbf94f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -105,7 +105,7 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool * float z = coords.z * zScale / coords.w + zCenter; // This matches hardware tests - depth is clamped when this flag is on. - if (gstate.isClippingEnabled()) { + if (gstate.isDepthClampEnabled()) { if (z < 0.f) z = 0.f; if (z > 65535.f) diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 1e78e352ef..68bc711a1d 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -247,7 +247,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag // Set cull bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE; - key.depthClampEnable = gstate.isClippingEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); } } From 921727f1632bd56c5ab8d94aff34685f6488939b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 17:12:46 -0700 Subject: [PATCH 13/58] GE Debugger: Fix preview crash. In some cases on first draw (e.g. from a test), this might be null and crash. It was supposed to be the other program. --- Windows/GEDebugger/VertexPreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Windows/GEDebugger/VertexPreview.cpp b/Windows/GEDebugger/VertexPreview.cpp index 42e006efd0..3dd9c8486b 100644 --- a/Windows/GEDebugger/VertexPreview.cpp +++ b/Windows/GEDebugger/VertexPreview.cpp @@ -494,7 +494,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) { } if (texPreviewVao == 0) { - glDisableVertexAttribArray(previewProgram->a_position); + glDisableVertexAttribArray(texPreviewProgram->a_position); } secondWindow->End(); From cd6b1f73c1a87c2e9b6e0f8c9ec810e061dba43c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 17:15:44 -0700 Subject: [PATCH 14/58] SoftGPU: Drop verts only when depth not clamped. Depth clamping bypasses the 4096x4096 box check. --- GPU/Software/TransformUnit.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 911bdbf94f..7bd578a25f 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -106,14 +106,16 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool * // This matches hardware tests - depth is clamped when this flag is on. if (gstate.isDepthClampEnabled()) { + // Note: if the depth is clamped, the outside_range_flag should NOT be set, even for x and y. if (z < 0.f) z = 0.f; - if (z > 65535.f) + else if (z > 65535.f) z = 65535.f; - } - - if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0 || z < 0 || z > 65535.f)) + else if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0)) + *outside_range_flag = true; + } else if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0 || z < 0 || z > 65535.f)) { *outside_range_flag = true; + } // 16 = 0xFFFF / 4095.9375 // Round up at 0.625 to the nearest subpixel. From e22cc7ef6d057b4a7907f373ac3d2254609df57d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 17:47:05 -0700 Subject: [PATCH 15/58] SoftGPU: Always clip, without special neg z case. Depth clamping doesn't change whether it clips. Also, avoid culling when a vertex is behind the near plane. --- GPU/Software/Clipper.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 85c9fc6efd..851747807d 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -256,13 +256,7 @@ void ProcessLine(VertexData& v0, VertexData& v1) return; } - if (mask && gstate.isDepthClampEnabled()) { - // TODO: Validate if this logic is correct / should be in depthClampEnabled. - - // discard if any vertex is outside the near clipping plane - if (mask & CLIP_NEG_Z_BIT) - return; - + if (mask) { CLIP_LINE(CLIP_POS_X_BIT, -1, 0, 0, 1); CLIP_LINE(CLIP_NEG_X_BIT, 1, 0, 0, 1); CLIP_LINE(CLIP_POS_Y_BIT, 0, -1, 0, 1); @@ -306,13 +300,7 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2) mask |= CalcClipMask(v1.clippos); mask |= CalcClipMask(v2.clippos); - if (mask && gstate.isDepthClampEnabled()) { - // TODO: Validate if this logic is correct / should be in depthClampEnabled. - - // discard if any vertex is outside the near clipping plane - if (mask & CLIP_NEG_Z_BIT) - return; - + if (mask) { for (int i = 0; i < 3; i += 3) { int vlist[2][2*6+1]; int *inlist = vlist[0], *outlist = vlist[1]; From 44be615cf5612b883fb5cee9b6adade00def858f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 19:52:20 -0700 Subject: [PATCH 16/58] GE Debugger: Arrange matrices properly. They were all off before for 4x3. --- Windows/GEDebugger/TabVertices.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Windows/GEDebugger/TabVertices.cpp b/Windows/GEDebugger/TabVertices.cpp index e878105fdd..f1f7e2f164 100644 --- a/Windows/GEDebugger/TabVertices.cpp +++ b/Windows/GEDebugger/TabVertices.cpp @@ -369,7 +369,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) { if (row >= MATRIXLIST_ROW_BONE_0_0) { int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3; int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3; - int offset = (row - MATRIXLIST_ROW_BONE_0_0) * 4 + col - 1; + int offset = b * 12 + r + (col - 1) * 3; switch (col) { case MATRIXLIST_COL_NAME: @@ -382,7 +382,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) { } } else if (row >= MATRIXLIST_ROW_TGEN_0) { int r = row - MATRIXLIST_ROW_TGEN_0; - int offset = r * 4 + col - 1; + int offset = r + (col - 1) * 4; switch (col) { case MATRIXLIST_COL_NAME: @@ -395,7 +395,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) { } } else if (row >= MATRIXLIST_ROW_PROJ_0) { int r = row - MATRIXLIST_ROW_PROJ_0; - int offset = r * 4 + col - 1; + int offset = r + (col - 1) * 4; switch (col) { case MATRIXLIST_COL_NAME: @@ -408,7 +408,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) { } } else if (row >= MATRIXLIST_ROW_VIEW_0) { int r = row - MATRIXLIST_ROW_VIEW_0; - int offset = r * 4 + col - 1; + int offset = r + (col - 1) * 3; switch (col) { case MATRIXLIST_COL_NAME: @@ -421,7 +421,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) { } } else { int r = row - MATRIXLIST_ROW_WORLD_0; - int offset = r * 4 + col - 1; + int offset = r + (col - 1) * 3; switch (col) { case MATRIXLIST_COL_NAME: From 31d5c39858060d7d04861fa3af2d4fe877def37d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 5 Aug 2018 20:07:45 -0700 Subject: [PATCH 17/58] SoftGPU: Fix some minor rounding on viewport cull. Had some tests failing when on the edge due to this. --- GPU/Software/TransformUnit.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 7bd578a25f..5810a36c2d 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -104,16 +104,21 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool * float y = coords.y * yScale / coords.w + yCenter; float z = coords.z * zScale / coords.w + zCenter; + // Account for rounding for X and Y. + const float SCREEN_BOUND = 4095.0f + (15.0f / 16.0f) + 0.375f; + // TODO: Validate actual rounding range. + const float DEPTH_BOUND = 65535.5f; + // This matches hardware tests - depth is clamped when this flag is on. if (gstate.isDepthClampEnabled()) { // Note: if the depth is clamped, the outside_range_flag should NOT be set, even for x and y. if (z < 0.f) z = 0.f; - else if (z > 65535.f) - z = 65535.f; - else if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0)) + else if (z > 65535.0f) + z = 65535.0f; + else if (outside_range_flag && (x >= SCREEN_BOUND || y >= SCREEN_BOUND || x < 0 || y < 0)) *outside_range_flag = true; - } else if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0 || z < 0 || z > 65535.f)) { + } else if (outside_range_flag && (x > 4095.9675f || y >= SCREEN_BOUND || x < 0 || y < 0 || z < 0 || z >= DEPTH_BOUND)) { *outside_range_flag = true; } From 06ad9b829fa0005997aace7b3f054831271c021b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 9 Aug 2018 07:12:32 -0700 Subject: [PATCH 18/58] SoftGPU: Oops, correct rounding to make sense. Was too hasty in that last commit. --- GPU/Software/TransformUnit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 5810a36c2d..05f1853119 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -105,8 +105,8 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool * float z = coords.z * zScale / coords.w + zCenter; // Account for rounding for X and Y. - const float SCREEN_BOUND = 4095.0f + (15.0f / 16.0f) + 0.375f; // TODO: Validate actual rounding range. + const float SCREEN_BOUND = 4095.0f + (15.5f / 16.0f); const float DEPTH_BOUND = 65535.5f; // This matches hardware tests - depth is clamped when this flag is on. @@ -118,7 +118,7 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool * z = 65535.0f; else if (outside_range_flag && (x >= SCREEN_BOUND || y >= SCREEN_BOUND || x < 0 || y < 0)) *outside_range_flag = true; - } else if (outside_range_flag && (x > 4095.9675f || y >= SCREEN_BOUND || x < 0 || y < 0 || z < 0 || z >= DEPTH_BOUND)) { + } else if (outside_range_flag && (x > SCREEN_BOUND || y >= SCREEN_BOUND || x < 0 || y < 0 || z < 0 || z >= DEPTH_BOUND)) { *outside_range_flag = true; } From c32ffa1db077ca3f8044abe7c027167a9fe36956 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 11 Aug 2018 16:33:39 -0700 Subject: [PATCH 19/58] GE Debugger: Rename depth clamp more places. Was still showing clip enable in disasm. --- GPU/GPUCommon.cpp | 2 +- GPU/GeDisasm.cpp | 4 ++-- GPU/Null/NullGpu.cpp | 4 ++-- GPU/Software/SoftGpu.cpp | 2 +- GPU/ge_constants.h | 2 +- Windows/GEDebugger/TabState.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1b9bb46283..6339504d0d 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -193,7 +193,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE }, { GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE }, { GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_CLIPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE }, + { GE_CMD_DEPTHCLAMPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE }, // Z clip { GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_VIEWPORTSCISSOR_STATE }, diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index d334385691..4faaca6a43 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -297,8 +297,8 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { } break; - case GE_CMD_CLIPENABLE: - snprintf(buffer, bufsize, "Clip enable: %i", data); + case GE_CMD_DEPTHCLAMPENABLE: + snprintf(buffer, bufsize, "Depth clamp enable: %i", data); break; case GE_CMD_CULLFACEENABLE: diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 29a50f2054..c4b345d96e 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -137,8 +137,8 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) { } break; - case GE_CMD_CLIPENABLE: - DEBUG_LOG(G3D, "DL Clip Enable: %i (ignoring)", data); + case GE_CMD_DEPTHCLAMPENABLE: + DEBUG_LOG(G3D, "DL Depth Clamp Enable: %i (ignoring)", data); //we always clip, this is opengl break; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 5d3b20c8e3..381a40403a 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -506,7 +506,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_REGION2: break; - case GE_CMD_CLIPENABLE: + case GE_CMD_DEPTHCLAMPENABLE: break; case GE_CMD_CULLFACEENABLE: diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index c0b1bc067e..b765af5bcb 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -43,7 +43,7 @@ enum GECommand { GE_CMD_LIGHTENABLE1 = 0x19, GE_CMD_LIGHTENABLE2 = 0x1A, GE_CMD_LIGHTENABLE3 = 0x1B, - GE_CMD_CLIPENABLE = 0x1C, + GE_CMD_DEPTHCLAMPENABLE = 0x1C, GE_CMD_CULLFACEENABLE = 0x1D, GE_CMD_TEXTUREMAPENABLE = 0x1E, GE_CMD_FOGENABLE = 0x1F, diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 494cf3e999..3b3241b947 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -100,7 +100,7 @@ static const TabStateRow stateFlagsRows[] = { { L"Light 1 enable", GE_CMD_LIGHTENABLE1, CMD_FMT_FLAG }, { L"Light 2 enable", GE_CMD_LIGHTENABLE2, CMD_FMT_FLAG }, { L"Light 3 enable", GE_CMD_LIGHTENABLE3, CMD_FMT_FLAG }, - { L"Clip enable", GE_CMD_CLIPENABLE, CMD_FMT_FLAG }, + { L"Depth clamp enable", GE_CMD_DEPTHCLAMPENABLE, CMD_FMT_FLAG }, { L"Cullface enable", GE_CMD_CULLFACEENABLE, CMD_FMT_FLAG }, { L"Texture map enable", GE_CMD_TEXTUREMAPENABLE, CMD_FMT_FLAG }, { L"Fog enable", GE_CMD_FOGENABLE, CMD_FMT_FLAG }, From 718053e7fce9370f927c2def2fd27207a5c450e2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 11 Aug 2018 16:35:58 -0700 Subject: [PATCH 20/58] Savedata: Return error codes on WRITEDATA/MAKEDATA. --- Core/Dialog/PSPSaveDialog.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index cb68396f6a..e47f51dcf7 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -1101,21 +1101,14 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { // TODO: Should reset the directory's other files. case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA: case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: - if (param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE) == 0) { - result = 0; - } else if (MemoryStick_FreeSpace() == 0) { + result = param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE); + if (result == SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE) { result = SCE_UTILITY_SAVEDATA_ERROR_RW_MEMSTICK_FULL; - } else { - result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; } break; case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA: case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: - if (param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE) == 0) { - result = 0; - } else { - result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; - } + result = param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE); break; case SCE_UTILITY_SAVEDATA_TYPE_READDATA: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: From 42feade4607d692569534a41881c10d33f29a52f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 11 Aug 2018 16:36:28 -0700 Subject: [PATCH 21/58] Savedata: Return error when bufSize is too small. Mirrors what a PSP does. --- Core/Dialog/SavedataParam.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index dfb436dca7..9a57a427f8 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -362,6 +362,10 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD if (!param) { return SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE; } + if (param->dataSize > param->dataBufSize) { + ERROR_LOG_REPORT(SCEUTILITY, "Savedata buffer overflow: %d / %d", param->dataSize, param->dataBufSize); + return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; + } if (param->secureVersion > 3) { ERROR_LOG_REPORT(SCEUTILITY, "Savedata version requested on save: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_SAVE_PARAM; From c0ccc9449d33eba35f2891f8054c9ed4de44c4b6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 11 Aug 2018 16:39:11 -0700 Subject: [PATCH 22/58] Savedata: Use size, not bufSize, for icons. Verified by tests. Should help #8810. --- Core/Dialog/SavedataParam.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 9a57a427f8..a6240ac13a 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -524,26 +524,26 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD if (param->icon0FileData.buf.IsValid()) { std::string icon0path = dirPath + "/" + ICON0_FILENAME; - WritePSPFile(icon0path, param->icon0FileData.buf, param->icon0FileData.bufSize); + WritePSPFile(icon0path, param->icon0FileData.buf, param->icon0FileData.size); } // SAVE ICON1 if (param->icon1FileData.buf.IsValid()) { std::string icon1path = dirPath + "/" + ICON1_FILENAME; - WritePSPFile(icon1path, param->icon1FileData.buf, param->icon1FileData.bufSize); + WritePSPFile(icon1path, param->icon1FileData.buf, param->icon1FileData.size); } // SAVE PIC1 if (param->pic1FileData.buf.IsValid()) { std::string pic1path = dirPath + "/" + PIC1_FILENAME; - WritePSPFile(pic1path, param->pic1FileData.buf, param->pic1FileData.bufSize); + WritePSPFile(pic1path, param->pic1FileData.buf, param->pic1FileData.size); } // Save SND if (param->snd0FileData.buf.IsValid()) { std::string snd0path = dirPath + "/" + SND0_FILENAME; - WritePSPFile(snd0path, param->snd0FileData.buf, param->snd0FileData.bufSize); + WritePSPFile(snd0path, param->snd0FileData.buf, param->snd0FileData.size); } return 0; From b64bb2e8ce93a5fc9566e73bb74827a7664c97fa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 11 Aug 2018 16:52:44 -0700 Subject: [PATCH 23/58] Savedata: Also validate icon/subdata size. --- Core/Dialog/SavedataParam.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index a6240ac13a..a137e779f7 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -366,6 +366,17 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD ERROR_LOG_REPORT(SCEUTILITY, "Savedata buffer overflow: %d / %d", param->dataSize, param->dataBufSize); return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; } + auto validateSize = [](const PspUtilitySavedataFileData &data) { + if (data.buf.IsValid() && data.bufSize < data.size) { + ERROR_LOG_REPORT(SCEUTILITY, "Savedata subdata buffer overflow: %d / %d", data.size, data.bufSize); + return false; + } + return true; + }; + if (!validateSize(param->icon0FileData) || !validateSize(param->icon1FileData) || !validateSize(param->pic1FileData) || !validateSize(param->snd0FileData)) { + return SCE_UTILITY_SAVEDATA_ERROR_RW_BAD_PARAMS; + } + if (param->secureVersion > 3) { ERROR_LOG_REPORT(SCEUTILITY, "Savedata version requested on save: %d", param->secureVersion); return SCE_UTILITY_SAVEDATA_ERROR_SAVE_PARAM; From 048afb6d24199d7dc9c241cb8a10aa3251985f68 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Aug 2018 08:24:33 -0700 Subject: [PATCH 24/58] UI: Resolve symlinks when adding things to recent. See #11131. This also normalizes paths, captialization, etc. as necessary. --- Common/FileUtil.cpp | 22 ++++++++++++++ Common/FileUtil.h | 3 ++ Core/Config.cpp | 34 ++++++++++++---------- Core/Config.h | 1 + Core/FileSystems/VirtualDiscFileSystem.cpp | 2 +- UI/GameInfoCache.cpp | 5 +--- UI/GameScreen.cpp | 23 ++++----------- 7 files changed, 52 insertions(+), 38 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 1a9629f35b..2588d73bc6 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -100,6 +100,28 @@ bool OpenCPPFile(std::fstream & stream, const std::string &filename, std::ios::o return stream.is_open(); } +std::string ResolvePath(const std::string &path) { +#ifdef _WIN32 + HANDLE hFile = CreateFile(ConvertUTF8ToWString(path).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + return path; + + wchar_t buf[1024] = {0}; + int result = GetFinalPathNameByHandle(hFile, buf, (int)ARRAY_SIZE(buf) - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + if (result >= ARRAY_SIZE(buf)) + return path; + + // Undo the \\?\C:\ syntax that's normally returned. + if (buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' && isalpha(buf[4]) && buf[5] == ':') + return ConvertWStringToUTF8(buf).substr(4); + return ConvertWStringToUTF8(buf); +#else + char buf[PATH_MAX + 1]; + if (realpath(path.c_str(), buf) == nullptr) + return path; + return buf; +#endif +} // Remove any ending forward slashes from directory paths // Modifies argument. diff --git a/Common/FileUtil.h b/Common/FileUtil.h index 07ac398fb7..31e0e7a373 100644 --- a/Common/FileUtil.h +++ b/Common/FileUtil.h @@ -58,6 +58,9 @@ struct FileDetails { FILE *OpenCFile(const std::string &filename, const char *mode); bool OpenCPPFile(std::fstream & stream, const std::string &filename, std::ios::openmode mode); +// Resolves symlinks and similar. +std::string ResolvePath(const std::string &path); + // Returns true if file filename exists bool Exists(const std::string &filename); diff --git a/Core/Config.cpp b/Core/Config.cpp index e7c22fe0ad..e6bf5440ea 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1209,30 +1209,34 @@ void Config::AddRecent(const std::string &file) { if (iMaxRecent <= 0) return; -#ifdef _WIN32 - std::string filename = ReplaceAll(file, "\\", "/"); -#else - std::string filename = file; -#endif - + const std::string filename = File::ResolvePath(file); for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) { -#ifdef _WIN32 - if (!strcmpIgnore((*str).c_str(), filename.c_str(), "\\", "/")) { -#else - if (!strcmp((*str).c_str(), filename.c_str())) { -#endif + const std::string recent = File::ResolvePath(*str); + if (filename == recent) { recentIsos.erase(str); - recentIsos.insert(recentIsos.begin(), filename); - if ((int)recentIsos.size() > iMaxRecent) - recentIsos.resize(iMaxRecent); - return; + // We'll add it back below. } } + recentIsos.insert(recentIsos.begin(), filename); if ((int)recentIsos.size() > iMaxRecent) recentIsos.resize(iMaxRecent); } +void Config::RemoveRecent(const std::string &file) { + // Don't bother with this if the user disabled recents (it's -1). + if (iMaxRecent <= 0) + return; + + const std::string filename = File::ResolvePath(file); + for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) { + const std::string recent = File::ResolvePath(*str); + if (filename == recent) { + recentIsos.erase(str); + } + } +} + void Config::CleanRecent() { std::vector cleanedRecent; for (size_t i = 0; i < recentIsos.size(); i++) { diff --git a/Core/Config.h b/Core/Config.h index d39957e7fb..10ae5c23d8 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -428,6 +428,7 @@ public: // Utility functions for "recent" management void AddRecent(const std::string &file); + void RemoveRecent(const std::string &file); void CleanRecent(); static void DownloadCompletedCallback(http::Download &download); diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index 5d555e4adc..b07946ebf9 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -44,7 +44,7 @@ VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::str : basePath(_basePath),currentBlockIndex(0) { #ifdef _WIN32 - if (!endsWith(basePath, "\\")) + if (!endsWith(basePath, "\\") && !endsWith(basePath, "/")) basePath = basePath + "\\"; #else if (!endsWith(basePath, "/")) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index caa8f396e3..f2a5e9f431 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -66,10 +66,7 @@ bool GameInfo::Delete() { // Just delete the one file (TODO: handle two-disk games as well somehow). const char *fileToRemove = filePath_.c_str(); File::Delete(fileToRemove); - auto i = std::find(g_Config.recentIsos.begin(), g_Config.recentIsos.end(), fileToRemove); - if (i != g_Config.recentIsos.end()) { - g_Config.recentIsos.erase(i); - } + g_Config.RemoveRecent(filePath_); return true; } case IdentifiedFileType::PSP_PBP_DIRECTORY: diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index cf0f8c0ba5..d10584463e 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -354,31 +354,18 @@ bool GameScreen::isRecentGame(const std::string &gamePath) { if (g_Config.iMaxRecent <= 0) return false; + const std::string resolved = File::ResolvePath(gamePath); for (auto it = g_Config.recentIsos.begin(); it != g_Config.recentIsos.end(); ++it) { -#ifdef _WIN32 - if (!strcmpIgnore((*it).c_str(), gamePath.c_str(), "\\","/")) -#else - if (!strcmp((*it).c_str(), gamePath.c_str())) -#endif + const std::string recent = File::ResolvePath(*it); + if (resolved == recent) return true; } return false; } UI::EventReturn GameScreen::OnRemoveFromRecent(UI::EventParams &e) { - if (g_Config.iMaxRecent <= 0) - return UI::EVENT_DONE; - for (auto it = g_Config.recentIsos.begin(); it != g_Config.recentIsos.end(); ++it) { -#ifdef _WIN32 - if (!strcmpIgnore((*it).c_str(), gamePath_.c_str(), "\\","/")) { -#else - if (!strcmp((*it).c_str(), gamePath_.c_str())) { -#endif - g_Config.recentIsos.erase(it); - screenManager()->switchScreen(new MainScreen()); - return UI::EVENT_DONE; - } - } + g_Config.RemoveRecent(gamePath_); + screenManager()->switchScreen(new MainScreen()); return UI::EVENT_DONE; } From b9bed664b0f4a4a8cf9d245fd7d82555d6070bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Aug 2018 19:49:07 +0200 Subject: [PATCH 25/58] Update README.md with discord link --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7affcbac26..d6769b23ec 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ Originally released under the GPL 2.0 (and later) in November 2012 Official website: https://www.ppsspp.org/ +Discord: +https://discord.gg/5NJB6dD + No BIOS file required to play, PPSSPP is an "HLE" emulator. Default settings balance good compatibility and speed. To contribute, see [the development page](https://www.ppsspp.org/development.html). Help testing, investigating, or fixing is always welcome. See [the list of issues](https://github.com/hrydgard/ppsspp/issues). From eddaf9793834dfba80605a04e0455fef93fb21af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Aug 2018 00:05:00 +0200 Subject: [PATCH 26/58] Add submodules, namespace json to prepare for the addition of rapidjson (sigh) --- .gitmodules | 6 ++++++ Core/Config.cpp | 4 ++-- Core/Debugger/WebSocket/WebSocketUtils.h | 2 ++ UI/RemoteISOScreen.cpp | 2 ++ UI/Store.cpp | 5 +++-- UI/Store.h | 7 +++++-- ext/discord-rpc | 1 + ext/native/json/json_reader.cpp | 4 ++++ ext/native/json/json_reader.h | 5 +++++ ext/native/json/json_writer.cpp | 5 +++++ ext/native/json/json_writer.h | 7 ++++++- ext/rapidjson | 1 + 12 files changed, 42 insertions(+), 7 deletions(-) create mode 160000 ext/discord-rpc create mode 160000 ext/rapidjson diff --git a/.gitmodules b/.gitmodules index 57a0d7933e..d39e459a44 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,9 @@ [submodule "ext/SPIRV-Cross"] path = ext/SPIRV-Cross url = https://github.com/KhronosGroup/SPIRV-Cross.git +[submodule "ext/discord-rpc"] + path = ext/discord-rpc + url = https://github.com/discordapp/discord-rpc.git +[submodule "ext/rapidjson"] + path = ext/rapidjson + url = https://github.com/Tencent/rapidjson.git diff --git a/Core/Config.cpp b/Core/Config.cpp index e7c22fe0ad..6b16d7cb3f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1162,8 +1162,8 @@ void Config::DownloadCompletedCallback(http::Download &download) { return; } - JsonReader reader(data.c_str(), data.size()); - const JsonGet root = reader.root(); + json::JsonReader reader(data.c_str(), data.size()); + const json::JsonGet root = reader.root(); if (!root) { ERROR_LOG(LOADER, "Failed to parse json"); return; diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h index e49647dcf8..70c08828b2 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.h +++ b/Core/Debugger/WebSocket/WebSocketUtils.h @@ -24,6 +24,8 @@ #include "net/websocket_server.h" #include "Common/Log.h" +using namespace json; + static inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) { const JsonNode *value = data.get("ticket"); if (value) diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 31d8f9f966..7e4238b96c 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -82,6 +82,8 @@ static bool FindServer(std::string &resultHost, int &resultPort) { std::string json; result.TakeAll(&json); + using namespace json; + JsonReader reader(json.c_str(), json.size()); if (!reader.ok()) { return false; diff --git a/UI/Store.cpp b/UI/Store.cpp index da2d2f1a4f..58e780dbda 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -391,6 +391,7 @@ void StoreScreen::update() { } void StoreScreen::ParseListing(std::string json) { + using namespace json; JsonReader reader(json.c_str(), json.size()); if (!reader.ok() || !reader.root()) { ELOG("Error parsing JSON from store"); @@ -540,8 +541,8 @@ std::string StoreScreen::GetStoreJsonURL(std::string storePath) const { return path; } -std::string StoreScreen::GetTranslatedString(const JsonGet json, std::string key, const char *fallback) const { - JsonGet dict = json.getDict("en_US"); +std::string StoreScreen::GetTranslatedString(const json::JsonGet json, std::string key, const char *fallback) const { + json::JsonGet dict = json.getDict("en_US"); if (dict && json.hasChild(lang_.c_str(), JSON_OBJECT)) { if (json.getDict(lang_.c_str()).hasChild(key.c_str(), JSON_STRING)) { dict = json.getDict(lang_.c_str()); diff --git a/UI/Store.h b/UI/Store.h index e7786c7c9c..c935bcb042 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -29,7 +29,10 @@ // set game specific settings, etc. // Uses GameInfoCache heavily to implement the functionality. -struct JsonGet; +namespace json { + struct JsonGet; +} + class ProductItemView; enum EntryType { @@ -79,7 +82,7 @@ private: std::vector FilterEntries(); std::string GetStoreJsonURL(std::string storePath) const; - std::string GetTranslatedString(const JsonGet json, std::string key, const char *fallback = nullptr) const; + std::string GetTranslatedString(const json::JsonGet json, std::string key, const char *fallback = nullptr) const; std::shared_ptr listing_; std::shared_ptr image_; diff --git a/ext/discord-rpc b/ext/discord-rpc new file mode 160000 index 0000000000..3d3ae7129d --- /dev/null +++ b/ext/discord-rpc @@ -0,0 +1 @@ +Subproject commit 3d3ae7129d17643bc706da0a2eea85aafd10ab3a diff --git a/ext/native/json/json_reader.cpp b/ext/native/json/json_reader.cpp index 83fbe94fa4..eaf9d0ae08 100644 --- a/ext/native/json/json_reader.cpp +++ b/ext/native/json/json_reader.cpp @@ -2,6 +2,8 @@ #include "file/vfs.h" #include "json/json_reader.h" +namespace json { + JsonReader::JsonReader(const std::string &filename) { size_t buf_size; buffer_ = (char *)VFSReadFile(filename.c_str(), &buf_size); @@ -117,3 +119,5 @@ bool JsonGet::getBool(const char *child_name, bool default_value) const { } return default_value; } + +} // namespace json diff --git a/ext/native/json/json_reader.h b/ext/native/json/json_reader.h index b9e8de5e53..a18915f488 100644 --- a/ext/native/json/json_reader.h +++ b/ext/native/json/json_reader.h @@ -1,9 +1,12 @@ #include #include + #include "base/basictypes.h" #include "base/logging.h" #include "ext/gason/gason.h" +namespace json { + struct JsonGet { JsonGet(const JsonValue &value) : value_(value) { } @@ -83,3 +86,5 @@ private: DISALLOW_COPY_AND_ASSIGN(JsonReader); }; + +} // namespace json diff --git a/ext/native/json/json_writer.cpp b/ext/native/json/json_writer.cpp index 7d1c47a620..7440cf731d 100644 --- a/ext/native/json/json_writer.cpp +++ b/ext/native/json/json_writer.cpp @@ -1,9 +1,12 @@ #include #include #include + #include "json/json_reader.h" #include "json/json_writer.h" +namespace json { + JsonWriter::JsonWriter(int flags) { pretty_ = (flags & PRETTY) != 0; str_.imbue(std::locale::classic()); @@ -383,3 +386,5 @@ static void json_stringify_array(JsonWriter &writer, const JsonNode *node) { break; } } + +} // namespace json diff --git a/ext/native/json/json_writer.h b/ext/native/json/json_writer.h index 22c712c856..d82b7151cf 100644 --- a/ext/native/json/json_writer.h +++ b/ext/native/json/json_writer.h @@ -13,6 +13,10 @@ #include #include +struct JsonNode; + +namespace json { + class JsonWriter { public: JsonWriter(int flags = NORMAL); @@ -79,5 +83,6 @@ private: bool pretty_; }; -struct JsonNode; std::string json_stringify(const JsonNode *json); + +} // namespace json diff --git a/ext/rapidjson b/ext/rapidjson new file mode 160000 index 0000000000..73063f5002 --- /dev/null +++ b/ext/rapidjson @@ -0,0 +1 @@ +Subproject commit 73063f5002612c6bf64fe24f851cd5cc0d83eef9 From 785858dbf8238173bfb8d33f74b1fbb85120ae0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Aug 2018 00:08:56 +0200 Subject: [PATCH 27/58] Basic Discord presence integration. --- Core/Config.cpp | 1 + Core/Config.h | 2 + UI/DiscordIntegration.cpp | 114 ++++++++++++ UI/DiscordIntegration.h | 28 +++ UI/EmuScreen.cpp | 6 + UI/GameSettingsScreen.cpp | 1 + UI/NativeApp.cpp | 7 + UI/UI.vcxproj | 10 +- UI/UI.vcxproj.filters | 2 + Windows/MainWindow.cpp | 2 +- Windows/PPSSPP.sln | 19 +- ext/discord-rpc-build/discord-rpc.vcxproj | 176 ++++++++++++++++++ .../discord-rpc.vcxproj.filters | 23 +++ 13 files changed, 385 insertions(+), 6 deletions(-) create mode 100644 UI/DiscordIntegration.cpp create mode 100644 UI/DiscordIntegration.h create mode 100644 ext/discord-rpc-build/discord-rpc.vcxproj create mode 100644 ext/discord-rpc-build/discord-rpc.vcxproj.filters diff --git a/Core/Config.cpp b/Core/Config.cpp index 6b16d7cb3f..5d10bfadb9 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -396,6 +396,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("CheckForNewVersion", &g_Config.bCheckForNewVersion, true), ConfigSetting("Language", &g_Config.sLanguageIni, &DefaultLangRegion), ConfigSetting("ForceLagSync", &g_Config.bForceLagSync, false, true, true), + ConfigSetting("DiscordPresence", &g_Config.bDiscordPresence, true, true, false), // Or maybe it makes sense to have it per-game? Race conditions abound... ReportedConfigSetting("NumWorkerThreads", &g_Config.iNumWorkerThreads, &DefaultNumWorkers, true, true), ConfigSetting("AutoLoadSaveState", &g_Config.iAutoLoadSaveState, 0, true, true), diff --git a/Core/Config.h b/Core/Config.h index d39957e7fb..110eae6052 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -117,6 +117,8 @@ public: std::vector vPinnedPaths; std::string sLanguageIni; + bool bDiscordPresence; // Enables setting the Discord presence to the current game (or menu) + // GFX int iGPUBackend; // We have separate device parameters for each backend so it doesn't get erased if you switch backends. diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp new file mode 100644 index 0000000000..0f7d4e6544 --- /dev/null +++ b/UI/DiscordIntegration.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include "ppsspp_config.h" +#include "Common/Log.h" +#include "Core/Config.h" +#include "DiscordIntegration.h" + +#include "ext/discord-rpc/include/discord_rpc.h" + +// TODO: Enable on more platforms. Make optional. + +#ifdef _WIN32 + +const bool g_DiscordEnabled = true; + +#else + +const bool g_DiscordEnabled = true; + +#endif + + +Discord g_Discord; + +static const char *ppsspp_app_id = "423397985041383434"; + +// No context argument? What? +static void handleDiscordError(int errCode, const char *message) { + ERROR_LOG(SYSTEM, "Discord error code %d: '%s'", message); +} + +Discord::~Discord() { + assert(!initialized_); +} + +bool Discord::IsEnabled() const { + return g_DiscordEnabled && g_Config.bDiscordPresence; +} + +void Discord::Init() { + assert(IsEnabled()); + assert(!initialized_); + + DiscordEventHandlers eventHandlers{}; + eventHandlers.errored = &handleDiscordError; + Discord_Initialize(ppsspp_app_id, &eventHandlers, 0, nullptr); + + initialized_ = true; +} + +void Discord::Shutdown() { + assert(initialized_); + Discord_Shutdown(); + initialized_ = false; +} + +void Discord::Update() { + if (!IsEnabled()) { + if (initialized_) { + Shutdown(); + } + return; + } else { + if (!initialized_) { + Init(); + } + } + +#ifdef DISCORD_DISABLE_IO_THREAD + Discord_UpdateConnection(); +#endif + Discord_RunCallbacks(); +} + +void Discord::SetPresenceGame(const char *gameTitle) { + if (!IsEnabled()) + return; + + if (!initialized_) { + Init(); + } + + DiscordRichPresence discordPresence{}; + discordPresence.state = gameTitle; + discordPresence.details = "Playing"; + discordPresence.startTimestamp = time(0); +#ifdef GOLD + discordPresence.largeImageKey = "icon_gold_png"; +#else + discordPresence.largeImageKey = "icon_regular_png"; +#endif + Discord_UpdatePresence(&discordPresence); +} + +void Discord::SetPresenceMenu() { + if (!IsEnabled()) + return; + + if (!initialized_) { + Init(); + } + + DiscordRichPresence discordPresence{}; + discordPresence.state = "In menu"; + discordPresence.details = ""; + discordPresence.startTimestamp = time(0); +#ifdef GOLD + discordPresence.largeImageKey = "icon_gold_png"; +#else + discordPresence.largeImageKey = "icon_regular_png"; +#endif + Discord_UpdatePresence(&discordPresence); +} diff --git a/UI/DiscordIntegration.h b/UI/DiscordIntegration.h new file mode 100644 index 0000000000..cd700d59ea --- /dev/null +++ b/UI/DiscordIntegration.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +// Simple wrapper around the Discord api. + +// All platforms should call it, but we only actually take action on +// platforms where we want it enabled (only PC initially). + +// All you need to call is FrameCallback, Shutdown, and UpdatePresence. + +class Discord { +public: + ~Discord(); + void Update(); // Call every frame or at least regularly. Will initialize if necessary. + void Shutdown(); + + void SetPresenceGame(const char *gameTitle); + void SetPresenceMenu(); + +private: + void Init(); + bool IsEnabled() const; + + bool initialized_ = false; +}; + +extern Discord g_Discord; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b4e761e980..391216dd73 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -77,6 +77,7 @@ #include "UI/GameSettingsScreen.h" #include "UI/InstallZipScreen.h" #include "UI/ProfilerDraw.h" +#include "UI/DiscordIntegration.h" #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) #include "Windows/MainWindow.h" @@ -192,6 +193,10 @@ void EmuScreen::bootGame(const std::string &filename) { g_Config.loadGameConfig(info->id); // Reset views in case controls are in a different place. RecreateViews(); + + g_Discord.SetPresenceGame(info->GetTitle().c_str()); + } else { + g_Discord.SetPresenceGame("(unknown)"); } invalid_ = true; @@ -333,6 +338,7 @@ EmuScreen::~EmuScreen() { startDumping = false; } #endif + g_Discord.SetPresenceMenu(); } void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8ccec4b5e7..5e289b6151 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -642,6 +642,7 @@ void GameSettingsScreen::CreateViews() { networkingSettings->Add(new Choice(n->T("Adhoc Multiplayer forum")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides); networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)"))); + networkingSettings->Add(new CheckBox(&g_Config.bDiscordPresence, n->T("Send Discord Presence information"))); #if !defined(MOBILE_DEVICE) && !defined(USING_QT_UI) networkingSettings->Add(new PopupTextInputChoice(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), "", 255, screenManager())); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index bd9c3937ee..10850b33df 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -98,6 +98,7 @@ #include "UI/TiltEventProcessor.h" #include "UI/BackgroundAudio.h" #include "UI/TextureUtil.h" +#include "UI/DiscordIntegration.h" #if !defined(MOBILE_DEVICE) #include "Common/KeyMap.h" @@ -352,6 +353,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch InitFastMath(cpu_info.bNEON); SetupAudioFormats(); + g_Discord.SetPresenceMenu(); + // Make sure UI state is MENU. ResetUIState(); @@ -1028,6 +1031,8 @@ void NativeUpdate() { g_DownloadManager.Update(); screenManager->update(); + + g_Discord.Update(); } bool NativeIsAtTopLevel() { @@ -1213,6 +1218,8 @@ void NativeShutdown() { net::Shutdown(); + g_Discord.Shutdown(); + delete logger; logger = nullptr; diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 06f979c86b..905c9d9384 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -24,6 +24,7 @@ + @@ -54,6 +55,7 @@ + @@ -80,11 +82,17 @@ + + + {beb0a821-3c7f-410f-a525-63afbc69bf8f} + + {004B8D11-2BE3-4BD9-AB40-2BE04CF2096F} Win32Proj UI - + + diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 8332d11762..0b5c2dd240 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -70,6 +70,7 @@ Screens + @@ -141,6 +142,7 @@ Screens + diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 83b5286771..848b8cb5fa 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -913,7 +913,7 @@ namespace MainWindow InputDevice::StopPolling(); MainThread_Stop(); coreState = CORE_POWERUP; - ResetUIState(); + UpdateUIState(UISTATE_MENU); MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL); InputDevice::BeginPolling(); break; diff --git a/Windows/PPSSPP.sln b/Windows/PPSSPP.sln index 13abef5350..4d4cdc49e7 100644 --- a/Windows/PPSSPP.sln +++ b/Windows/PPSSPP.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPWindows", "PPSSPP.vcxproj", "{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}" ProjectSection(ProjectDependencies) = postProject @@ -77,6 +77,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "..\ext\glslang.v EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRV-Cross", "..\ext\SPIRV-Cross.vcxproj", "{4328A62C-F1E9-47ED-B816-A1A81DAF4363}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "discord-rpc", "..\ext\discord-rpc-build\discord-rpc.vcxproj", "{BEB0A821-3C7F-410F-A525-63AFBC69BF8F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -105,7 +107,6 @@ Global {F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|Win32.Build.0 = Debug|Win32 {F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|x64.ActiveCfg = Debug|x64 {F761046E-6C38-4428-A5F1-38391A37BB34}.Debug|x64.Build.0 = Debug|x64 - {F761046E-6C38-4428-A5F1-38391A37BB34}.Release|ARM.ActiveCfg = Release|Win32 {F761046E-6C38-4428-A5F1-38391A37BB34}.Release|Win32.ActiveCfg = Release|Win32 {F761046E-6C38-4428-A5F1-38391A37BB34}.Release|Win32.Build.0 = Release|Win32 {F761046E-6C38-4428-A5F1-38391A37BB34}.Release|x64.ActiveCfg = Release|x64 @@ -114,7 +115,6 @@ Global {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|Win32.Build.0 = Debug|Win32 {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|x64.ActiveCfg = Debug|x64 {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Debug|x64.Build.0 = Debug|x64 - {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|ARM.ActiveCfg = Release|Win32 {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|Win32.ActiveCfg = Release|Win32 {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|Win32.Build.0 = Release|Win32 {457F45D2-556F-47BC-A31D-AFF0D15BEAED}.Release|x64.ActiveCfg = Release|x64 @@ -191,8 +191,19 @@ Global {4328A62C-F1E9-47ED-B816-A1A81DAF4363}.Release|Win32.Build.0 = Release|Win32 {4328A62C-F1E9-47ED-B816-A1A81DAF4363}.Release|x64.ActiveCfg = Release|x64 {4328A62C-F1E9-47ED-B816-A1A81DAF4363}.Release|x64.Build.0 = Release|x64 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Debug|Win32.ActiveCfg = Debug|Win32 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Debug|Win32.Build.0 = Debug|Win32 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Debug|x64.ActiveCfg = Debug|x64 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Debug|x64.Build.0 = Debug|x64 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Release|Win32.ActiveCfg = Release|Win32 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Release|Win32.Build.0 = Release|Win32 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Release|x64.ActiveCfg = Release|x64 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2FD47774-A031-48F4-B645-A49A3140A29B} + EndGlobalSection EndGlobal diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj b/ext/discord-rpc-build/discord-rpc.vcxproj new file mode 100644 index 0000000000..d7ca25ed8b --- /dev/null +++ b/ext/discord-rpc-build/discord-rpc.vcxproj @@ -0,0 +1,176 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + 15.0 + {BEB0A821-3C7F-410F-A525-63AFBC69BF8F} + Win32Proj + discordrpc + 10.0.17134.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + true + + + true + + + false + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + Disabled + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include + MultiThreadedDebug + + + Windows + true + + + + + Level3 + Disabled + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include + MultiThreadedDebug + + + Windows + true + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include + MultiThreaded + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj.filters b/ext/discord-rpc-build/discord-rpc.vcxproj.filters new file mode 100644 index 0000000000..ac36b4d139 --- /dev/null +++ b/ext/discord-rpc-build/discord-rpc.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9c22f6ed55fabf299523c1a62989f55427ebd019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Aug 2018 00:25:08 +0200 Subject: [PATCH 28/58] Don't forget to update the other build systems and try to fix the builds. --- CMakeLists.txt | 1 + UI/DiscordIntegration.cpp | 26 +++++++++++++++++++------- UWP/UI_UWP/UI_UWP.vcxproj | 4 +++- UWP/UI_UWP/UI_UWP.vcxproj.filters | 4 +++- android/jni/Android.mk | 1 + 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bffaa11320..2e34d5fe76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -822,6 +822,7 @@ endif() list(APPEND NativeAppSource android/jni/TestRunner.cpp + UI/DiscordIntegration.cpp UI/NativeApp.cpp UI/BackgroundAudio.cpp UI/DevScreens.cpp diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index 0f7d4e6544..c57a9a6df9 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -6,21 +6,23 @@ #include "Core/Config.h" #include "DiscordIntegration.h" -#include "ext/discord-rpc/include/discord_rpc.h" - -// TODO: Enable on more platforms. Make optional. #ifdef _WIN32 -const bool g_DiscordEnabled = true; +#define ENABLE_DISCORD #else -const bool g_DiscordEnabled = true; - #endif + +#ifdef ENABLE_DISCORD +#include "ext/discord-rpc/include/discord_rpc.h" +#endif + +// TODO: Enable on more platforms. Make optional. + Discord g_Discord; static const char *ppsspp_app_id = "423397985041383434"; @@ -35,23 +37,27 @@ Discord::~Discord() { } bool Discord::IsEnabled() const { - return g_DiscordEnabled && g_Config.bDiscordPresence; + return g_Config.bDiscordPresence; } void Discord::Init() { assert(IsEnabled()); assert(!initialized_); +#ifdef ENABLE_DISCORD DiscordEventHandlers eventHandlers{}; eventHandlers.errored = &handleDiscordError; Discord_Initialize(ppsspp_app_id, &eventHandlers, 0, nullptr); +#endif initialized_ = true; } void Discord::Shutdown() { assert(initialized_); +#ifdef ENABLE_DISCORD Discord_Shutdown(); +#endif initialized_ = false; } @@ -67,10 +73,12 @@ void Discord::Update() { } } +#ifdef ENABLE_DISCORD #ifdef DISCORD_DISABLE_IO_THREAD Discord_UpdateConnection(); #endif Discord_RunCallbacks(); +#endif } void Discord::SetPresenceGame(const char *gameTitle) { @@ -81,6 +89,7 @@ void Discord::SetPresenceGame(const char *gameTitle) { Init(); } +#ifdef ENABLE_DISCORD DiscordRichPresence discordPresence{}; discordPresence.state = gameTitle; discordPresence.details = "Playing"; @@ -91,6 +100,7 @@ void Discord::SetPresenceGame(const char *gameTitle) { discordPresence.largeImageKey = "icon_regular_png"; #endif Discord_UpdatePresence(&discordPresence); +#endif } void Discord::SetPresenceMenu() { @@ -101,6 +111,7 @@ void Discord::SetPresenceMenu() { Init(); } +#ifdef ENABLE_DISCORD DiscordRichPresence discordPresence{}; discordPresence.state = "In menu"; discordPresence.details = ""; @@ -111,4 +122,5 @@ void Discord::SetPresenceMenu() { discordPresence.largeImageKey = "icon_regular_png"; #endif Discord_UpdatePresence(&discordPresence); +#endif } diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index 7fda5b55f9..3b54be0228 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -304,6 +304,7 @@ + @@ -337,6 +338,7 @@ + @@ -376,4 +378,4 @@ - \ No newline at end of file + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index 2dda8c4b86..b3ee44e3c8 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -7,6 +7,7 @@ + @@ -40,6 +41,7 @@ + @@ -65,4 +67,4 @@ - \ No newline at end of file + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 2b837a0ef2..b6a7c18f53 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -485,6 +485,7 @@ LOCAL_SRC_FILES := \ $(SRC)/android/jni/native_audio.cpp \ $(SRC)/android/jni/native-audio-so.cpp \ $(SRC)/UI/BackgroundAudio.cpp \ + $(SRC)/UI/DiscordIntegration.cpp \ $(SRC)/UI/DevScreens.cpp \ $(SRC)/UI/DisplayLayoutEditor.cpp \ $(SRC)/UI/DisplayLayoutScreen.cpp \ From 7a058180bbfd2d9080a8587b8640f5fbd02d78aa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Aug 2018 19:27:26 -0700 Subject: [PATCH 29/58] Io: Prevent cur/parent dir in listing of root. See #9344. Matches tests. --- Core/FileSystems/DirectoryFileSystem.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 71e91d06d8..2b8a18f1bb 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -825,6 +825,8 @@ static std::string SimulateVFATBug(std::string filename) { std::vector DirectoryFileSystem::GetDirListing(std::string path) { std::vector myVector; + bool listingRoot = path == "/" || path == "\\"; + #ifdef _WIN32 WIN32_FIND_DATA findData; HANDLE hFind; @@ -849,7 +851,7 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777; // TODO: is this just for .. or all subdirectories? Need to add a directory to the test // to find out. Also why so different than the old test results? - if (!wcscmp(findData.cFileName, L"..") ) + if (!wcscmp(findData.cFileName, L"..")) entry.size = 4096; else entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32); @@ -857,7 +859,8 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { tmFromFiletime(entry.atime, findData.ftLastAccessTime); tmFromFiletime(entry.ctime, findData.ftCreationTime); tmFromFiletime(entry.mtime, findData.ftLastWriteTime); - myVector.push_back(entry); + if (!listingRoot || (wcscmp(findData.cFileName, L"..") && wcscmp(findData.cFileName, L"."))) + myVector.push_back(entry); int retval = FindNextFile(hFind, &findData); if (!retval) @@ -897,7 +900,8 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { localtime_r((time_t*)&s.st_atime,&entry.atime); localtime_r((time_t*)&s.st_ctime,&entry.ctime); localtime_r((time_t*)&s.st_mtime,&entry.mtime); - myVector.push_back(entry); + if (!listingRoot || (wcscmp(findData.cFileName, L"..") && wcscmp(findData.cFileName, L"."))) + myVector.push_back(entry); } closedir(dp); #endif From 70318fda375a3ed322afbfb54ebad6999bde4203 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Aug 2018 19:49:08 -0700 Subject: [PATCH 30/58] GLES: Enable shader depal with Vulkan fixes. --- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 42 ++++++++++++++---------- GPU/GLES/TextureCacheGLES.cpp | 6 +--- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 0c11d82344..674cbaa42d 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -346,29 +346,37 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform doTextureProjection = false; } - if (doTextureProjection) { - WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord); - if (shaderDepal) { - WRITE(p, " vec4 t1 = %sProjOffset(tex, %s, ivec2(1, 0));\n", texture, texcoord); - WRITE(p, " vec4 t2 = %sProjOffset(tex, %s, ivec2(0, 1));\n", texture, texcoord); - WRITE(p, " vec4 t3 = %sProjOffset(tex, %s, ivec2(1, 1));\n", texture, texcoord); + if (!shaderDepal) { + if (doTextureProjection) { + WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord); + } else { + WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord); } } else { - WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord); - if (shaderDepal) { - WRITE(p, " vec4 t1 = %sOffset(tex, %s.xy, ivec2(1, 0));\n", texture, texcoord); - WRITE(p, " vec4 t2 = %sOffset(tex, %s.xy, ivec2(0, 1));\n", texture, texcoord); - WRITE(p, " vec4 t3 = %sOffset(tex, %s.xy, ivec2(1, 1));\n", texture, texcoord); + if (doTextureProjection) { + // We don't use textureProj because we need better control and it's probably not much of a savings anyway. + WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord); + } else { + WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); } - } - - if (shaderDepal) { + WRITE(p, " vec2 tsize = textureSize(tex, 0);\n"); + WRITE(p, " vec2 fraction;\n"); + WRITE(p, " bool bilinear = (u_depal >> 31) != 0;\n"); + WRITE(p, " if (bilinear) {\n"); + WRITE(p, " uv_round = uv * tsize - vec2(0.5, 0.5);\n"); + WRITE(p, " fraction = fract(uv_round);\n"); + WRITE(p, " uv_round = (uv_round - fraction + vec2(0.5, 0.5)) / tsize;\n"); // We want to take our four point samples at pixel centers. + WRITE(p, " } else {\n"); + WRITE(p, " uv_round = uv;\n"); + WRITE(p, " }\n"); + WRITE(p, " vec4 t = %s(tex, uv_round);\n", texture); + WRITE(p, " vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", texture); + WRITE(p, " vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", texture); + WRITE(p, " vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", texture); WRITE(p, " int depalMask = (u_depal & 0xFF);\n"); WRITE(p, " int depalShift = ((u_depal >> 8) & 0xFF);\n"); WRITE(p, " int depalOffset = (((u_depal >> 16) & 0xFF) << 4);\n"); WRITE(p, " int depalFmt = ((u_depal >> 24) & 0x3);\n"); - WRITE(p, " bool bilinear = (u_depal >> 31) != 0;\n"); - WRITE(p, " vec2 fraction = fract(%s.xy * vec2(textureSize(tex, 0).xy));\n", texcoord); WRITE(p, " ivec4 col; int index0; int index1; int index2; int index3;\n"); WRITE(p, " switch (depalFmt) {\n"); // We might want to include fmt in the shader ID if this is a performance issue. WRITE(p, " case 0:\n"); // 565 @@ -422,7 +430,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " };\n"); WRITE(p, " index0 = ((index0 >> depalShift) & depalMask) | depalOffset;\n"); WRITE(p, " t = texelFetch(pal, ivec2(index0, 0), 0);\n"); - WRITE(p, " if (bilinear) {\n"); + WRITE(p, " if (bilinear && !(index0 == index1 && index1 == index2 && index2 == index3)) {\n"); WRITE(p, " index1 = ((index1 >> depalShift) & depalMask) | depalOffset;\n"); WRITE(p, " index2 = ((index2 >> depalShift) & depalMask) | depalOffset;\n"); WRITE(p, " index3 = ((index3 >> depalShift) & depalMask) | depalOffset;\n"); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 659f9540fe..5f1c3e4a0f 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -443,11 +443,7 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram DepalShader *depal = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; -#if 0 - bool useShaderDepal = gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300); -#else - bool useShaderDepal = false; -#endif + bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300); if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { if (useShaderDepal) { From ac5467ca67cda4e5f64dda1e749cf16380c68fcd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 13 Aug 2018 04:33:52 -0700 Subject: [PATCH 31/58] Io: Linux buildfix. Fixes #11300. --- Core/FileSystems/DirectoryFileSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 2b8a18f1bb..27a15f352e 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -900,7 +900,7 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { localtime_r((time_t*)&s.st_atime,&entry.atime); localtime_r((time_t*)&s.st_ctime,&entry.ctime); localtime_r((time_t*)&s.st_mtime,&entry.mtime); - if (!listingRoot || (wcscmp(findData.cFileName, L"..") && wcscmp(findData.cFileName, L"."))) + if (!listingRoot || (strcmp(dirp->d_name, "..") && strcmp(dirp->d_name, "."))) myVector.push_back(entry); } closedir(dp); From a2530be18d95b2dfc615ab6fc2724c3579bafe47 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 13 Aug 2018 05:01:19 -0700 Subject: [PATCH 32/58] Io: Fallback to long/full path on Windows XP. --- Common/FileUtil.cpp | 55 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 2588d73bc6..8152762ad3 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -102,19 +102,56 @@ bool OpenCPPFile(std::fstream & stream, const std::string &filename, std::ios::o std::string ResolvePath(const std::string &path) { #ifdef _WIN32 - HANDLE hFile = CreateFile(ConvertUTF8ToWString(path).c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - return path; + typedef DWORD (WINAPI *getFinalPathNameByHandleW_f)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags); + static getFinalPathNameByHandleW_f getFinalPathNameByHandleW = nullptr; - wchar_t buf[1024] = {0}; - int result = GetFinalPathNameByHandle(hFile, buf, (int)ARRAY_SIZE(buf) - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - if (result >= ARRAY_SIZE(buf)) - return path; + if (!getFinalPathNameByHandleW) { + // We leak this, but that's okay since the process should hold onto this DLL for the entire lifetime anyway. + HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); + getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); + } + + static const int BUF_SIZE = 32768; + wchar_t *buf = new wchar_t[BUF_SIZE]; + memset(buf, 0, BUF_SIZE); + + std::wstring input = ConvertUTF8ToWString(path); + if (getFinalPathNameByHandleW) { + HANDLE hFile = CreateFile(input.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); + } else { + int result = GetFinalPathNameByHandle(hFile, buf, BUF_SIZE - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + if (result >= BUF_SIZE || result == 0) + wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); + } + } else { + wchar_t *longBuf = new wchar_t[BUF_SIZE]; + memset(buf, 0, BUF_SIZE); + + int result = GetLongPathNameW(input.c_str(), longBuf, BUF_SIZE - 1); + if (result >= BUF_SIZE || result == 0) + wcscpy_s(longBuf, BUF_SIZE - 1, input.c_str()); + + result = GetFullPathNameW(longBuf, BUF_SIZE - 1, buf, nullptr); + if (result >= BUF_SIZE || result == 0) + wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); + + delete [] longBuf; + + // Normalize slashes just in case. + for (int i = 0; i < BUF_SIZE; ++i) { + if (buf[i] == '\\') + buf[i] = '/'; + } + } // Undo the \\?\C:\ syntax that's normally returned. + std::string output = ConvertWStringToUTF8(buf); if (buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' && isalpha(buf[4]) && buf[5] == ':') - return ConvertWStringToUTF8(buf).substr(4); - return ConvertWStringToUTF8(buf); + output = output.substr(4); + delete [] buf; + return output; #else char buf[PATH_MAX + 1]; if (realpath(path.c_str(), buf) == nullptr) From 35e1d0c84147881c3baf5831b0462bd7d604f265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Aug 2018 20:14:34 +0200 Subject: [PATCH 33/58] Discord: Translated some messages --- UI/DiscordIntegration.cpp | 15 ++++++++++----- UI/EmuScreen.cpp | 4 +++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index c57a9a6df9..cc5b21b0cb 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -5,7 +5,7 @@ #include "Common/Log.h" #include "Core/Config.h" #include "DiscordIntegration.h" - +#include "i18n/i18n.h" #ifdef _WIN32 @@ -13,10 +13,10 @@ #else +// TODO + #endif - - #ifdef ENABLE_DISCORD #include "ext/discord-rpc/include/discord_rpc.h" #endif @@ -90,9 +90,12 @@ void Discord::SetPresenceGame(const char *gameTitle) { } #ifdef ENABLE_DISCORD + I18NCategory *sc = GetI18NCategory("Screen"); + DiscordRichPresence discordPresence{}; discordPresence.state = gameTitle; - discordPresence.details = "Playing"; + std::string details = sc->T("Playing"); + discordPresence.details = details.c_str(); discordPresence.startTimestamp = time(0); #ifdef GOLD discordPresence.largeImageKey = "icon_gold_png"; @@ -112,8 +115,10 @@ void Discord::SetPresenceMenu() { } #ifdef ENABLE_DISCORD + I18NCategory *sc = GetI18NCategory("Screen"); + DiscordRichPresence discordPresence{}; - discordPresence.state = "In menu"; + discordPresence.state = sc->T("In menu"); discordPresence.details = ""; discordPresence.startTimestamp = time(0); #ifdef GOLD diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 391216dd73..e34a8e10c7 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -187,6 +187,8 @@ void EmuScreen::bootGame(const std::string &filename) { if (!bootAllowStorage(filename)) return; + I18NCategory *sc = GetI18NCategory("Screen"); + //pre-emptive loading of game specific config if possible, to get all the settings std::shared_ptr info = g_gameInfoCache->GetInfo(nullptr, filename, 0); if (info && !info->id.empty()) { @@ -196,7 +198,7 @@ void EmuScreen::bootGame(const std::string &filename) { g_Discord.SetPresenceGame(info->GetTitle().c_str()); } else { - g_Discord.SetPresenceGame("(unknown)"); + g_Discord.SetPresenceGame(sc->T("Untitled PSP game")); } invalid_ = true; From c0ba66cf3c9aeafad2bf902772d13007bf2e9fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Aug 2018 23:08:46 +0200 Subject: [PATCH 34/58] Revert some of the sln and vcxproj changes, hoping to appease Travis --- Windows/PPSSPP.sln | 4 ++-- ext/discord-rpc-build/discord-rpc.vcxproj | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Windows/PPSSPP.sln b/Windows/PPSSPP.sln index 4d4cdc49e7..918e2910d6 100644 --- a/Windows/PPSSPP.sln +++ b/Windows/PPSSPP.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2026 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPWindows", "PPSSPP.vcxproj", "{567AF8DB-42C1-4D08-96CD-D70A2DFEFC6B}" ProjectSection(ProjectDependencies) = postProject diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj b/ext/discord-rpc-build/discord-rpc.vcxproj index d7ca25ed8b..52c18de82b 100644 --- a/ext/discord-rpc-build/discord-rpc.vcxproj +++ b/ext/discord-rpc-build/discord-rpc.vcxproj @@ -1,5 +1,5 @@ - + Debug @@ -39,7 +39,6 @@ - 15.0 {BEB0A821-3C7F-410F-A525-63AFBC69BF8F} Win32Proj discordrpc @@ -49,26 +48,26 @@ StaticLibrary true - v141 + $(DefaultPlatformToolset)_xp Unicode StaticLibrary false - v141 + $(DefaultPlatformToolset)_xp true Unicode StaticLibrary true - v141 + $(DefaultPlatformToolset)_xp Unicode StaticLibrary false - v141 + $(DefaultPlatformToolset)_xp true Unicode @@ -173,4 +172,4 @@ - \ No newline at end of file + From 404594da57216e63b819eed1f566e38ca2a27827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Aug 2018 20:40:42 +0200 Subject: [PATCH 35/58] Fix crash bug when cleaning duplicates of recent files --- Core/Config.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 02da5ff142..ae0e1ffa43 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1211,10 +1211,10 @@ void Config::AddRecent(const std::string &file) { return; const std::string filename = File::ResolvePath(file); - for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) { - const std::string recent = File::ResolvePath(*str); + for (auto iter = recentIsos.begin(); iter != recentIsos.end(); ++iter) { + const std::string recent = File::ResolvePath(*iter); if (filename == recent) { - recentIsos.erase(str); + iter = recentIsos.erase(iter); // We'll add it back below. } } From 75827004e17598d8eb2806a48ec8978b3a95a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Aug 2018 21:26:42 +0200 Subject: [PATCH 36/58] Properly fix the iterator bug, oops. --- Core/Config.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index ae0e1ffa43..048bb4baad 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1211,11 +1211,14 @@ void Config::AddRecent(const std::string &file) { return; const std::string filename = File::ResolvePath(file); - for (auto iter = recentIsos.begin(); iter != recentIsos.end(); ++iter) { + for (auto iter = recentIsos.begin(); iter != recentIsos.end();) { const std::string recent = File::ResolvePath(*iter); if (filename == recent) { + // Note that the increment-erase idiom doesn't work with vectors. iter = recentIsos.erase(iter); // We'll add it back below. + } else { + iter++; } } @@ -1230,10 +1233,13 @@ void Config::RemoveRecent(const std::string &file) { return; const std::string filename = File::ResolvePath(file); - for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) { - const std::string recent = File::ResolvePath(*str); + for (auto iter = recentIsos.begin(); iter != recentIsos.end();) { + const std::string recent = File::ResolvePath(*iter); if (filename == recent) { - recentIsos.erase(str); + // Note that the increment-erase idiom doesn't work with vectors. + iter = recentIsos.erase(iter); + } else { + iter++; } } } From 6f173b9134dd3148681d5022bff2d8230a0bc0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Aug 2018 21:27:07 +0200 Subject: [PATCH 37/58] Harmonize some VS project settings. --- Common/Common.vcxproj | 2 -- Core/Core.vcxproj | 2 -- GPU/GPU.vcxproj | 2 -- UI/UI.vcxproj | 6 +++--- Windows/PPSSPP.vcxproj | 4 +--- Windows/PPSSPP.vcxproj.filters | 5 +---- ext/SPIRV-Cross.vcxproj | 5 +++++ ext/discord-rpc-build/discord-rpc.vcxproj | 19 ++++++++++--------- .../discord-rpc.vcxproj.filters | 1 - ext/glslang.vcxproj | 6 ++---- ext/libarmips.vcxproj | 11 ++++++++--- ext/libkirk/libkirk.vcxproj | 9 +++++---- ext/native/native.vcxproj | 4 ++-- ext/zlib/zlib.vcxproj | 4 +--- headless/Headless.vcxproj | 9 +++------ unittest/UnitTests.vcxproj | 9 +++++---- 16 files changed, 46 insertions(+), 52 deletions(-) diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index cf033d00ea..1c378870d1 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -80,7 +80,6 @@ true false false - ProgramDatabase Windows @@ -108,7 +107,6 @@ true false false - ProgramDatabase Windows diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index c0751c917a..f85082b0d2 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -78,7 +78,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h @@ -101,7 +100,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 96fd523c37..296a2081b0 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -93,7 +93,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h @@ -116,7 +115,6 @@ false _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) MultiThreadedDebug - ProgramDatabase Common/DbgNew.h diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 905c9d9384..4d1650482b 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -147,7 +147,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h $(EXTERNAL_COMPILE_OPTIONS) @@ -172,7 +171,6 @@ false MultiThreadedDebug false - ProgramDatabase Common/DbgNew.h $(EXTERNAL_COMPILE_OPTIONS) @@ -196,7 +194,7 @@ USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext false - Speed + Size true false MultiThreaded @@ -229,6 +227,8 @@ MultiThreaded true $(EXTERNAL_COMPILE_OPTIONS) + false + Size Windows diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 7fa9fc4525..e7057f6f41 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -125,7 +125,6 @@ Sync Use Level3 - ProgramDatabase ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug @@ -162,7 +161,6 @@ Sync Use Level3 - ProgramDatabase ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib stdafx.h;Common/DbgNew.h MultiThreadedDebug @@ -559,4 +557,4 @@ - + \ No newline at end of file diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 8cfb5cdbb3..80851fdc34 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -311,9 +311,6 @@ Other Platforms\Qt - - Other Platforms\Qt\Debugger - Windows\System @@ -428,4 +425,4 @@ Resource Files - + \ No newline at end of file diff --git a/ext/SPIRV-Cross.vcxproj b/ext/SPIRV-Cross.vcxproj index 1211cdd119..a3dc1386f3 100644 --- a/ext/SPIRV-Cross.vcxproj +++ b/ext/SPIRV-Cross.vcxproj @@ -93,6 +93,7 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) false MultiThreadedDebug + true Windows @@ -107,6 +108,7 @@ _DEBUG;_LIB;%(PreprocessorDefinitions) false MultiThreadedDebug + true Windows @@ -123,6 +125,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded false + true Windows @@ -141,6 +144,8 @@ NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded false + true + false Windows diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj b/ext/discord-rpc-build/discord-rpc.vcxproj index 52c18de82b..771c6e4f7d 100644 --- a/ext/discord-rpc-build/discord-rpc.vcxproj +++ b/ext/discord-rpc-build/discord-rpc.vcxproj @@ -34,7 +34,6 @@ - @@ -42,7 +41,8 @@ {BEB0A821-3C7F-410F-A525-63AFBC69BF8F} Win32Proj discordrpc - 10.0.17134.0 + + @@ -55,7 +55,6 @@ StaticLibrary false $(DefaultPlatformToolset)_xp - true Unicode @@ -68,7 +67,6 @@ StaticLibrary false $(DefaultPlatformToolset)_xp - true Unicode @@ -107,11 +105,13 @@ MaxSpeed true true - true NDEBUG;_LIB;%(PreprocessorDefinitions) true ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreaded + true + false + false Windows @@ -124,11 +124,11 @@ Level3 Disabled - true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreadedDebug + true Windows @@ -139,11 +139,11 @@ Level3 Disabled - true _DEBUG;_LIB;%(PreprocessorDefinitions) true ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreadedDebug + true Windows @@ -156,11 +156,12 @@ MaxSpeed true true - true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true ..\discord-rpc\include;..\discord-rpc\src;..\rapidjson\include MultiThreaded + true + false Windows @@ -172,4 +173,4 @@ - + \ No newline at end of file diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj.filters b/ext/discord-rpc-build/discord-rpc.vcxproj.filters index ac36b4d139..a10d90a63d 100644 --- a/ext/discord-rpc-build/discord-rpc.vcxproj.filters +++ b/ext/discord-rpc-build/discord-rpc.vcxproj.filters @@ -16,7 +16,6 @@ - diff --git a/ext/glslang.vcxproj b/ext/glslang.vcxproj index 3711148daa..95eb3ab485 100644 --- a/ext/glslang.vcxproj +++ b/ext/glslang.vcxproj @@ -22,8 +22,7 @@ {EDFA2E87-8AC1-4853-95D4-D7594FF81947} Win32Proj glslang - - + 7.0 @@ -36,7 +35,6 @@ StaticLibrary false $(DefaultPlatformToolset)_xp - false Unicode @@ -49,7 +47,6 @@ StaticLibrary false $(DefaultPlatformToolset)_xp - false Unicode @@ -141,6 +138,7 @@ MultiThreaded false true + false Windows diff --git a/ext/libarmips.vcxproj b/ext/libarmips.vcxproj index 688f859d77..4662b65ba3 100644 --- a/ext/libarmips.vcxproj +++ b/ext/libarmips.vcxproj @@ -30,7 +30,8 @@ {129E5E2B-39C1-4D84-96FE-DFD22DBB4A25} Win32Proj libarmips - + + @@ -135,9 +136,9 @@ _CRTDBG_MAP_ALLOC;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) MultiThreadedDebug armips - ProgramDatabase + true Windows @@ -155,9 +156,9 @@ MultiThreadedDebug armips false - ProgramDatabase + true Windows @@ -203,6 +204,8 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded armips + true + false Windows @@ -223,6 +226,8 @@ armips false true + true + false Windows diff --git a/ext/libkirk/libkirk.vcxproj b/ext/libkirk/libkirk.vcxproj index f59b9668a9..86f944aea9 100644 --- a/ext/libkirk/libkirk.vcxproj +++ b/ext/libkirk/libkirk.vcxproj @@ -21,7 +21,8 @@ {3BAAE095-E0AB-4B0E-B5DF-CE39C8AE31DE} libkirk - + + @@ -69,13 +70,12 @@ Level3 - Default + EnableFastChecks _CRTDBG_MAP_ALLOC;_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS true false false MultiThreadedDebug - ProgramDatabase ../../Common/DbgNew.h @@ -90,7 +90,6 @@ false MultiThreadedDebug false - ProgramDatabase ../../Common/DbgNew.h _CRTDBG_MAP_ALLOC;_USING_V110_SDK71_;%(PreprocessorDefinitions) @@ -130,6 +129,8 @@ false MultiThreaded true + Speed + false true diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 8fb5a42746..21b09ed6d7 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -82,7 +82,6 @@ Level3 _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); - ProgramDatabase true false false @@ -109,7 +108,6 @@ false MultiThreadedDebug false - ProgramDatabase ../../Common/DbgNew.h @@ -135,6 +133,7 @@ true false MultiThreaded + false Windows @@ -163,6 +162,7 @@ MultiThreaded false true + false Windows diff --git a/ext/zlib/zlib.vcxproj b/ext/zlib/zlib.vcxproj index a8b71dbed9..cc73897541 100644 --- a/ext/zlib/zlib.vcxproj +++ b/ext/zlib/zlib.vcxproj @@ -106,7 +106,6 @@ StreamingSIMDExtensions2 Fast Default - ProgramDatabase true false false @@ -132,7 +131,6 @@ false false MultiThreadedDebug - ProgramDatabase ../../Common/DbgNew.h @@ -195,4 +193,4 @@ - \ No newline at end of file + diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 4018293068..e4412a822c 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -23,7 +23,8 @@ Win32Proj Headless PPSSPPHeadless - + + @@ -93,14 +94,13 @@ Level3 _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native - Default + EnableFastChecks StreamingSIMDExtensions2 Fast true false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h @@ -132,7 +132,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h @@ -155,7 +154,6 @@ Level3 NotUsing - MaxSpeed true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS @@ -190,7 +188,6 @@ Level3 NotUsing - MaxSpeed true true USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj index 215e9a9378..38b7be99b3 100644 --- a/unittest/UnitTests.vcxproj +++ b/unittest/UnitTests.vcxproj @@ -23,7 +23,8 @@ Win32Proj UnitTests UnitTest - + + @@ -94,7 +95,6 @@ false false MultiThreadedDebug - ProgramDatabase Common/DbgNew.h @@ -117,7 +117,6 @@ false MultiThreadedDebug false - ProgramDatabase Common/DbgNew.h @@ -139,7 +138,7 @@ USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions) ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib false - Speed + Size true false MultiThreaded @@ -169,6 +168,8 @@ false MultiThreaded true + Size + false Console From f038b6489a14c883377e1fccdd6f0a44a70749e6 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Wed, 15 Aug 2018 18:35:07 +0200 Subject: [PATCH 38/58] Add sceUsbAcc stubs, improves EyePet(fixes endless loop on boot) --- CMakeLists.txt | 2 ++ Core/Core.vcxproj | 2 ++ Core/Core.vcxproj.filters | 6 +++++ Core/HLE/HLETables.cpp | 2 ++ Core/HLE/sceUsbAcc.cpp | 46 +++++++++++++++++++++++++++++++++++++++ Core/HLE/sceUsbAcc.h | 21 ++++++++++++++++++ android/jni/Android.mk | 1 + 7 files changed, 80 insertions(+) create mode 100644 Core/HLE/sceUsbAcc.cpp create mode 100644 Core/HLE/sceUsbAcc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e34d5fe76..010b77f441 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1610,6 +1610,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/sceUmd.h Core/HLE/sceUsb.cpp Core/HLE/sceUsb.h + Core/HLE/sceUsbAcc.cpp + Core/HLE/sceUsbAcc.h Core/HLE/sceUsbCam.cpp Core/HLE/sceUsbCam.h Core/HLE/sceUsbGps.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index f85082b0d2..068241f0c6 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -196,6 +196,7 @@ + @@ -558,6 +559,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index b398758157..ba79121304 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -731,6 +731,9 @@ Debugger\WebSocket + + HLE\Libraries + @@ -1355,6 +1358,9 @@ Core + + HLE\Libraries + diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 129fc69354..ed1331f3ad 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -66,6 +66,7 @@ #include "sceSsl.h" #include "sceUmd.h" #include "sceUsb.h" +#include "sceUsbAcc.h" #include "sceUsbCam.h" #include "sceUsbGps.h" #include "sceUtility.h" @@ -296,6 +297,7 @@ void RegisterAllModules() { Register_sceNetUpnp(); Register_sceNetIfhandle(); Register_KUBridge(); + Register_sceUsbAcc(); // add new modules here. } diff --git a/Core/HLE/sceUsbAcc.cpp b/Core/HLE/sceUsbAcc.cpp new file mode 100644 index 0000000000..93d6add3cb --- /dev/null +++ b/Core/HLE/sceUsbAcc.cpp @@ -0,0 +1,46 @@ +// 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 "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceUsbAcc.h" + +// Assuming https://github.com/joel16/usbacc/blob/master/usbacc.c is correct +// sceUsbAccGetAuthStat should return 0 or one of the two errors on failure +// sceUsbAccGetInfo should return 0 or one of the 3 errors on failure +// we don't have to deal with physical Usb connection, so let's just always pass + +static int sceUsbAccGetAuthStat() { + INFO_LOG(HLE, "UNIMPL sceUsbAccGetAuthStat"); + return 0; +} + +static int sceUsbAccGetInfo(u32 addr) { + INFO_LOG(HLE, "UNIMPL sceUsbAccGetInfo"); + return 0; +} + +const HLEFunction sceUsbAcc[] = +{ + {0X79A1C743, &WrapI_V, "sceUsbAccGetAuthStat", 'i', "" }, + {0X0CD7D4AA, &WrapI_U, "sceUsbAccGetInfo", 'i', "x" }, +}; + +void Register_sceUsbAcc() +{ + RegisterModule("sceUsbAcc", ARRAY_SIZE(sceUsbAcc), sceUsbAcc); +} diff --git a/Core/HLE/sceUsbAcc.h b/Core/HLE/sceUsbAcc.h new file mode 100644 index 0000000000..da84904d1f --- /dev/null +++ b/Core/HLE/sceUsbAcc.h @@ -0,0 +1,21 @@ +// 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/. + +#pragma once + +void Register_sceUsbAcc(); + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index b6a7c18f53..171ca31310 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -385,6 +385,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/sceSsl.cpp \ $(SRC)/Core/HLE/sceUmd.cpp \ $(SRC)/Core/HLE/sceUsb.cpp \ + $(SRC)/Core/HLE/sceUsbAcc.cpp \ $(SRC)/Core/HLE/sceUsbCam.cpp \ $(SRC)/Core/HLE/sceUsbGps.cpp \ $(SRC)/Core/HLE/sceUtility.cpp \ From e34378a1c15e2530c91a849cd0e2d04e7221bb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 18 Aug 2018 10:11:15 +0200 Subject: [PATCH 39/58] Enable Discord integration for Mac and Linux. --- CMakeLists.txt | 3 +++ GPU/Common/ShaderTranslation.cpp | 4 ++-- UI/DiscordIntegration.cpp | 5 +++-- ext/CMakeLists.txt | 1 + ext/discord-rpc-build/CMakeLists.txt | 30 ++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 ext/discord-rpc-build/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 010b77f441..459ad3ee38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1757,6 +1757,9 @@ if(FFmpeg_FOUND) ) endif() +# Discord integration +target_link_libraries(${CoreLibName} discord-rpc) + setup_target_project(${CoreLibName} Core) # Generate git-version.cpp at build time. diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index b253a96f6b..862ba286c6 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -310,7 +310,7 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade spirv_cross::CompilerGLSL::Options options; options.version = 140; options.es = true; - glsl.set_options(options); + glsl.set_common_options(options); // Compile to GLSL, ready to give to GL driver. *dest = glsl.compile(); @@ -324,7 +324,7 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade // Set some options. spirv_cross::CompilerGLSL::Options options; options.version = gl_extensions.GLSLVersion(); - glsl.set_options(options); + glsl.set_common_options(options); // Compile to GLSL, ready to give to GL driver. *dest = glsl.compile(); return true; diff --git a/UI/DiscordIntegration.cpp b/UI/DiscordIntegration.cpp index cc5b21b0cb..54ee337e3f 100644 --- a/UI/DiscordIntegration.cpp +++ b/UI/DiscordIntegration.cpp @@ -7,7 +7,7 @@ #include "DiscordIntegration.h" #include "i18n/i18n.h" -#ifdef _WIN32 +#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) #define ENABLE_DISCORD @@ -29,7 +29,7 @@ static const char *ppsspp_app_id = "423397985041383434"; // No context argument? What? static void handleDiscordError(int errCode, const char *message) { - ERROR_LOG(SYSTEM, "Discord error code %d: '%s'", message); + ERROR_LOG(SYSTEM, "Discord error code %d: '%s'", errCode, message); } Discord::~Discord() { @@ -48,6 +48,7 @@ void Discord::Init() { DiscordEventHandlers eventHandlers{}; eventHandlers.errored = &handleDiscordError; Discord_Initialize(ppsspp_app_id, &eventHandlers, 0, nullptr); + INFO_LOG(SYSTEM, "Discord connection initialized"); #endif initialized_ = true; diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index f506eb6787..4a6b8e45a3 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -12,3 +12,4 @@ add_subdirectory(glslang) add_subdirectory(snappy) add_subdirectory(udis86) add_subdirectory(SPIRV-Cross-build) +add_subdirectory(discord-rpc-build) diff --git a/ext/discord-rpc-build/CMakeLists.txt b/ext/discord-rpc-build/CMakeLists.txt new file mode 100644 index 0000000000..4417fd7282 --- /dev/null +++ b/ext/discord-rpc-build/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required (VERSION 3.2.0) +project (DiscordRPC) + +set(SRC_DIR ../discord-rpc/src) + + +# format +set(ALL_SOURCE_FILES + ${SRC_DIR}/backoff.h + ${SRC_DIR}/connection.h + ${SRC_DIR}/msg_queue.h + ${SRC_DIR}/rpc_connection.h + ${SRC_DIR}/serialization.h + ${SRC_DIR}/discord_rpc.cpp + ${SRC_DIR}/rpc_connection.cpp + ${SRC_DIR}/serialization.cpp + ${SRC_DIR}/discord_register_osx.m + ) + +if(WIN32) + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/connection_win.cpp) + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/discord_register_win.cpp) +else() + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/connection_unix.cpp) + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/discord_register_linux.cpp) +endif() + +add_library(discord-rpc STATIC ${ALL_SOURCE_FILES}) + +target_include_directories(discord-rpc PUBLIC ../discord-rpc/src ../discord-rpc/include ../rapidjson/include) From 8a154dab707f50cd72ee9aa3a81cdeb534965172 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 18 Aug 2018 10:22:55 -0700 Subject: [PATCH 40/58] Windows: Correctly buildfix Windows XP. Should run properly now - dumb mistake. --- Common/FileUtil.cpp | 2 +- Core/Config.cpp | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 8152762ad3..776913f63c 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -121,7 +121,7 @@ std::string ResolvePath(const std::string &path) { if (hFile == INVALID_HANDLE_VALUE) { wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); } else { - int result = GetFinalPathNameByHandle(hFile, buf, BUF_SIZE - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + int result = getFinalPathNameByHandleW(hFile, buf, BUF_SIZE - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); if (result >= BUF_SIZE || result == 0) wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); } diff --git a/Core/Config.cpp b/Core/Config.cpp index 048bb4baad..03e1043ddb 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1210,18 +1210,10 @@ void Config::AddRecent(const std::string &file) { if (iMaxRecent <= 0) return; - const std::string filename = File::ResolvePath(file); - for (auto iter = recentIsos.begin(); iter != recentIsos.end();) { - const std::string recent = File::ResolvePath(*iter); - if (filename == recent) { - // Note that the increment-erase idiom doesn't work with vectors. - iter = recentIsos.erase(iter); - // We'll add it back below. - } else { - iter++; - } - } + // We'll add it back below. This makes sure it's at the front, and only once. + RemoveRecent(file); + const std::string filename = File::ResolvePath(file); recentIsos.insert(recentIsos.begin(), filename); if ((int)recentIsos.size() > iMaxRecent) recentIsos.resize(iMaxRecent); From cd98c4a266d5ea5f7dcd37dea62a5d44c791c0bf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 18 Aug 2018 10:41:59 -0700 Subject: [PATCH 41/58] GLES: Fix direct shader depal on GLES. Was missing a cast and only worked on some desktop before. --- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 674cbaa42d..19dc1ba37d 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -359,7 +359,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); } - WRITE(p, " vec2 tsize = textureSize(tex, 0);\n"); + WRITE(p, " vec2 tsize = vec2(textureSize(tex, 0));\n"); WRITE(p, " vec2 fraction;\n"); WRITE(p, " bool bilinear = (u_depal >> 31) != 0;\n"); WRITE(p, " if (bilinear) {\n"); From 3fc845a265ed39a0de10869ea8fd66af02a75356 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 22 Aug 2018 18:27:20 -0700 Subject: [PATCH 42/58] UI: Delay game config/discord until game info load. This avoids a race condition where the info is not always available, causing game-specific config and Discord presence to set incorrectly. --- UI/EmuScreen.cpp | 11 +++++++---- UI/GameInfoCache.cpp | 7 ++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index e34a8e10c7..feeb5b8cb6 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -189,9 +189,14 @@ void EmuScreen::bootGame(const std::string &filename) { I18NCategory *sc = GetI18NCategory("Screen"); - //pre-emptive loading of game specific config if possible, to get all the settings + invalid_ = true; + + // We don't want to boot with the wrong game specific config, so wait until info is ready. std::shared_ptr info = g_gameInfoCache->GetInfo(nullptr, filename, 0); - if (info && !info->id.empty()) { + if (!info || info->pending) + return; + + if (!info->id.empty()) { g_Config.loadGameConfig(info->id); // Reset views in case controls are in a different place. RecreateViews(); @@ -201,8 +206,6 @@ void EmuScreen::bootGame(const std::string &filename) { g_Discord.SetPresenceGame(sc->T("Untitled PSP game")); } - invalid_ = true; - CoreParameter coreParam{}; coreParam.cpuCore = (CPUCore)g_Config.iCpuCore; coreParam.gpuCore = GPUCORE_GLES; diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index f2a5e9f431..f727aa1363 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -353,8 +353,10 @@ public: } void run() override { - if (!info_->LoadFromPath(gamePath_)) + if (!info_->LoadFromPath(gamePath_)) { + info_->pending = false; return; + } // In case of a remote file, check if it actually exists before locking. if (!info_->GetFileLoader()->Exists()) { info_->pending = false; @@ -381,6 +383,7 @@ public: goto handleELF; } ERROR_LOG(LOADER, "invalid pbp %s\n", pbpLoader->Path().c_str()); + info_->pending = false; info_->working = false; return; } @@ -549,11 +552,13 @@ handleELF: // few files. auto fl = info_->GetFileLoader(); if (!fl) { + info_->pending = false; info_->working = false; return; // Happens with UWP currently, TODO... } BlockDevice *bd = constructBlockDevice(info_->GetFileLoader().get()); if (!bd) { + info_->pending = false; info_->working = false; return; // nothing to do here.. } From 6ef7e069d3e5d2710763cd72fa14c7880dc57df8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 22 Aug 2018 18:28:36 -0700 Subject: [PATCH 43/58] Core: Fix logging of SCEGE category. --- Common/LogManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 65545b1fc0..485a7b47da 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -99,7 +99,7 @@ static const LogNameTableEntry logTable[] = { {LogTypes::SCECTRL, "SCECTRL"}, {LogTypes::SCEDISPLAY, "SCEDISP"}, {LogTypes::SCEFONT, "SCEFONT"}, - {LogTypes::SCEGE, "SCESCEGE"}, + {LogTypes::SCEGE, "SCEGE"}, {LogTypes::SCEINTC, "SCEINTC"}, {LogTypes::SCEIO, "SCEIO"}, {LogTypes::SCEKERNEL, "SCEKERNEL"}, From 28be6cc4ccf4f7b9b56dda253d5b994bbe32a4a8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 24 Aug 2018 20:53:40 -0700 Subject: [PATCH 44/58] Headless: Fix graphics compare tests. Shadowing. --- headless/SDLHeadlessHost.h | 1 - headless/WindowsHeadlessHost.h | 1 - 2 files changed, 2 deletions(-) diff --git a/headless/SDLHeadlessHost.h b/headless/SDLHeadlessHost.h index daa0fe0413..3907f3ab5e 100644 --- a/headless/SDLHeadlessHost.h +++ b/headless/SDLHeadlessHost.h @@ -49,7 +49,6 @@ protected: STOPPED, }; - GraphicsContext *gfx_; volatile RenderThreadState threadState_ = RenderThreadState::IDLE; }; diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h index 853eee1eb5..907b20cdf6 100644 --- a/headless/WindowsHeadlessHost.h +++ b/headless/WindowsHeadlessHost.h @@ -53,6 +53,5 @@ protected: HWND hWnd; HDC hDC; HGLRC hRC; - GraphicsContext *gfx_; volatile RenderThreadState threadState_ = RenderThreadState::IDLE; }; From 44b90f638de21e39f6f4622dec88016bddc4e06b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 24 Aug 2018 20:54:38 -0700 Subject: [PATCH 45/58] SoftGPU: Apply pixel mask for clears. Turns out it's respected even in clear mode. Also, confirm logic op and blending interact. --- GPU/Software/Rasterizer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index f6b6e398e7..ebed8f36de 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -972,7 +972,7 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4 Date: Fri, 24 Aug 2018 21:05:27 -0700 Subject: [PATCH 46/58] GPU: Refactor logic op simulation for better reuse. --- GPU/Common/GPUStateUtils.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 824d3827b1..2b88905d30 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -813,17 +813,7 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) { } // Try to simulate some common logic ops. -void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState) { - StencilValueType stencilType = STENCIL_VALUE_KEEP; - if (replaceAlphaWithStencil == REPLACE_ALPHA_YES) { - stencilType = ReplaceAlphaWithStencilType(); - } - - // Normally, we would add src + 0, but the logic op may have us do differently. - BlendFactor srcBlend = BlendFactor::ONE; - BlendFactor dstBlend = BlendFactor::ZERO; - BlendEq blendEq = BlendEq::ADD; - +static void ApplyLogicOp(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { if (gstate.isLogicOpEnabled()) { switch (gstate.getLogicOp()) { @@ -876,8 +866,22 @@ void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, Gen } } } +} - // We're not blending, but we may still want to blend for stencil. +// Try to simulate some common logic ops. +void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState) { + StencilValueType stencilType = STENCIL_VALUE_KEEP; + if (replaceAlphaWithStencil == REPLACE_ALPHA_YES) { + stencilType = ReplaceAlphaWithStencilType(); + } + + // Normally, we would add src + 0 with blending off, but the logic op may have us do differently. + BlendFactor srcBlend = BlendFactor::ONE; + BlendFactor dstBlend = BlendFactor::ZERO; + BlendEq blendEq = BlendEq::ADD; + ApplyLogicOp(srcBlend, dstBlend, blendEq); + + // We're not blending, but we may still want to "blend" for stencil. // This is only useful for INCR/DECR/INVERT. Others can write directly. switch (stencilType) { case STENCIL_VALUE_INCR_4: From 5c01bf61e6203d60237b0739221303712f777bb1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 24 Aug 2018 21:19:54 -0700 Subject: [PATCH 47/58] GPU: Apply logic op in more cases. It has well defined behavior with alpha blending, so let's apply it even when we're blending. Fixes #11316. --- GPU/Common/GPUStateUtils.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2b88905d30..2e952270c3 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -814,11 +814,15 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) { // Try to simulate some common logic ops. static void ApplyLogicOp(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { + // Note: our shader solution applies logic ops BEFORE blending, not correctly after. + // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { if (gstate.isLogicOpEnabled()) { switch (gstate.getLogicOp()) { case GE_LOGIC_CLEAR: srcBlend = BlendFactor::ZERO; + dstBlend = BlendFactor::ZERO; + blendEq = BlendEq::ADD; break; case GE_LOGIC_AND: case GE_LOGIC_AND_REVERSE: @@ -846,6 +850,7 @@ static void ApplyLogicOp(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq & case GE_LOGIC_NOOP: srcBlend = BlendFactor::ZERO; dstBlend = BlendFactor::ONE; + blendEq = BlendEq::ADD; break; case GE_LOGIC_XOR: WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp()); @@ -860,7 +865,9 @@ static void ApplyLogicOp(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq & WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_SET: + srcBlend = BlendFactor::ONE; dstBlend = BlendFactor::ONE; + blendEq = BlendEq::ADD; WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); break; } @@ -1109,6 +1116,15 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { #endif // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. + BlendEq colorEq; + if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { + colorEq = eqLookup[blendFuncEq]; + } else { + colorEq = eqLookupNoMinMax[blendFuncEq]; + } + + // Attempt to apply the logic op, if any. + ApplyLogicOp(glBlendFuncA, glBlendFuncB, colorEq); // The stencil-to-alpha in fragment shader doesn't apply here (blending is enabled), and we shouldn't // do any blending in the alpha channel as that doesn't seem to happen on PSP. So, we attempt to @@ -1178,11 +1194,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE); } - if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) { - blendState.setEquation(eqLookup[blendFuncEq], alphaEq); - } else { - blendState.setEquation(eqLookupNoMinMax[blendFuncEq], alphaEq); - } + blendState.setEquation(colorEq, alphaEq); } static void ConvertStencilFunc5551(GenericStencilFuncState &state) { From 3f48e446b6f2113ff9e5eeffdb3596353710ae1c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 09:57:37 -0700 Subject: [PATCH 48/58] GPU: Fix texture handling on framebuf detach. We were never creating/recreating the texture, so we ended up with null. Caused all sorts of problems. --- GPU/Common/TextureCacheCommon.cpp | 3 +++ ext/native/thin3d/GLRenderManager.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index b4a0a6f4aa..cadf9abf0d 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -713,6 +713,9 @@ void TextureCacheCommon::DetachFramebuffer(TexCacheEntry *entry, u32 address, Vi const u64 cachekey = entry->CacheKey(); cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); entry->framebuffer = nullptr; + // Force the hash to change in case we had one before. + // Otherwise we never recreate the texture. + entry->hash ^= 1; fbTexInfo_.erase(cachekey); host->GPUNotifyTextureAttachment(entry->addr); } diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index 8751b9b7d3..c2cdb086cd 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -345,6 +345,7 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec } void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) { + _assert_(texture); GLRStep *step = new GLRStep{ GLRStepType::READBACK_IMAGE }; step->readback_image.texture = texture; step->readback_image.mipLevel = mipLevel; From 7fa20d47341deb723b9a2ac7c3a5d60fefbb3106 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 10:01:43 -0700 Subject: [PATCH 49/58] GPU: Download safe size on next create, too. In some cases, games will create a series of framebufs. Before, we weren't downloading them if they were only used once, as intended. --- GPU/Common/FramebufferCommon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index af1162b315..b475ff0c36 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -542,6 +542,8 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer if (!useBufferedRendering_) { // Let's ignore rendering to targets that have not (yet) been displayed. gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; + } else if (currentRenderVfb_) { + DownloadFramebufferOnSwitch(currentRenderVfb_); } textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); From d13f76308d7a43c1f5d1055d895c6d531fe4ec96 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 10:32:32 -0700 Subject: [PATCH 50/58] Ge: Avoid executing invalid pointers. May help #3407 and related errors, as well as crashes and execution of garbage. This stops immediately on a bad pointer, rather than trying to push through. --- Core/HLE/sceGe.cpp | 6 +++--- GPU/GPUCommon.cpp | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index fad468bfa8..dafa5d09b1 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -353,10 +353,10 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 auto optParam = PSPPointer::Create(optParamAddr); u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), optParam, true); - if ((int)listID >= 0) + if ((int)listID >= 0) { listID = LIST_ID_MAGIC ^ listID; - - DEBUG_LOG(SCEGE, "List %i enqueued at head.", listID); + DEBUG_LOG(SCEGE, "List %i enqueued at head.", listID); + } hleEatCycles(480); CoreTiming::ForceCheck(); return listID; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6339504d0d..77a2548291 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -632,8 +632,10 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointerpc, target - 4); currentList->pc = target - 4; // pc will be increased after we return, counteract that } @@ -1184,6 +1185,7 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { currentList->pc = target - 4; // pc will be increased after we return, counteract that } else { ERROR_LOG_REPORT(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + UpdateState(GPUSTATE_ERROR); } } } @@ -1194,12 +1196,11 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) { // Saint Seiya needs correct support for relative calls. const u32 retval = currentList->pc + 4; const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); -#ifdef _DEBUG if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + UpdateState(GPUSTATE_ERROR); return; } -#endif // Bone matrix optimization - many games will CALL a bone matrix (!). // We don't optimize during recording - so the matrix data gets recorded. @@ -1304,6 +1305,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { u32 target = (((signal << 16) | enddata) & 0xFFFFFFFC) - 4; if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata); + UpdateState(GPUSTATE_ERROR); } else { UpdatePC(currentList->pc, target); currentList->pc = target; @@ -1321,6 +1323,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata); } else if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata); + UpdateState(GPUSTATE_ERROR); } else { // TODO: This might save/restore other state... auto &stackEntry = currentList->stack[currentList->stackptr++]; From 6ee0612a105803b208d22d920d8685d50cb5ac4e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 10:38:56 -0700 Subject: [PATCH 51/58] Ge: Keep jump/call optim when fast memory on. This gives a way to validate with fast memory off, and get less crashes. --- GPU/GPUCommon.cpp | 29 +++++++++++++++++++++++++++-- GPU/GPUCommon.h | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 77a2548291..69d733835b 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -420,6 +420,14 @@ void GPUCommon::UpdateCmdInfo() { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } + + if (g_Config.bFastMemory) { + cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_JumpFast; + cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_CallFast; + } else { + cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_Jump; + cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_Call; + } } void GPUCommon::BeginHostFrame() { @@ -1176,6 +1184,12 @@ void GPUCommon::Execute_Jump(u32 op, u32 diff) { currentList->pc = target - 4; // pc will be increased after we return, counteract that } +void GPUCommon::Execute_JumpFast(u32 op, u32 diff) { + const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); + UpdatePC(currentList->pc, target - 4); + currentList->pc = target - 4; // pc will be increased after we return, counteract that +} + void GPUCommon::Execute_BJump(u32 op, u32 diff) { if (!currentList->bboxResult) { // bounding box jump. @@ -1193,14 +1207,25 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { void GPUCommon::Execute_Call(u32 op, u32 diff) { PROFILE_THIS_SCOPE("gpu_call"); - // Saint Seiya needs correct support for relative calls. - const u32 retval = currentList->pc + 4; const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } + DoExecuteCall(target); +} + +void GPUCommon::Execute_CallFast(u32 op, u32 diff) { + PROFILE_THIS_SCOPE("gpu_call"); + + const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); + DoExecuteCall(target); +} + +void GPUCommon::DoExecuteCall(u32 target) { + // Saint Seiya needs correct support for relative calls. + const u32 retval = currentList->pc + 4; // Bone matrix optimization - many games will CALL a bone matrix (!). // We don't optimize during recording - so the matrix data gets recorded. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 36442d50de..63f6661594 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -125,8 +125,10 @@ public: void Execute_Iaddr(u32 op, u32 diff); void Execute_Origin(u32 op, u32 diff); void Execute_Jump(u32 op, u32 diff); + void Execute_JumpFast(u32 op, u32 diff); void Execute_BJump(u32 op, u32 diff); void Execute_Call(u32 op, u32 diff); + void Execute_CallFast(u32 op, u32 diff); void Execute_Ret(u32 op, u32 diff); void Execute_End(u32 op, u32 diff); @@ -287,6 +289,7 @@ protected: virtual void FinishDeferred() {} void DoBlockTransfer(u32 skipDrawReason); + void DoExecuteCall(u32 target); void AdvanceVerts(u32 vertType, int count, int bytesRead) { if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { From 39eedc638612433e647bfb4d1fa39cdfdd3c4497 Mon Sep 17 00:00:00 2001 From: ystlong Date: Sun, 26 Aug 2018 15:27:16 +0800 Subject: [PATCH 52/58] add BTP-BD2F joystick gamecontroller map --- assets/gamecontrollerdb.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/gamecontrollerdb.txt b/assets/gamecontrollerdb.txt index aa97cd20a3..582e756eea 100644 --- a/assets/gamecontrollerdb.txt +++ b/assets/gamecontrollerdb.txt @@ -187,3 +187,4 @@ bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,b 05000000c82d00002038000000010000,8Bitdo NES30 Pro,platform:Linux,a:b1,b:b0,x:b4,y:b3,back:b10,guide:b2,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, 030000005e040000a102000000010000,Xbox 360 Wireless Receiver,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpdown:b14,dpleft:b11,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5, 050000004c050000cc09000001000000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, +03000000bc2000006412000011010000,BETOP CONTROLLER,a:b2,b:b1,y:b0,x:b3,start:b9,guide:b30,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, From 61eb331bad5adea747962c5f7a352d26ef289fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Aug 2018 13:06:17 +0200 Subject: [PATCH 53/58] Update gradle version again --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b32f870af1..7c2a69bf60 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.3' + classpath 'com.android.tools.build:gradle:3.1.4' } } From 3c5b2d69f6732f9922f6ac2412977d08e6ff96ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Aug 2018 19:26:54 +0200 Subject: [PATCH 54/58] Android: When using the hardware scaler, round the size to divisible by 4. Might help #11151 --- android/jni/app-android.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 9206bcd59b..1eb3220d8d 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -871,6 +871,11 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { sz_x = 0; sz_y = 0; } + // Round the size up to the nearest multiple of 4. While this may cause a tiny aspect ratio distortion, + // there's some hope that #11151 is a driver bug that might be worked around this way. If this fixes it, + // it'll be worth trying to round to a multiple of 2 instead. + sz_x = (sz_x + 3) & ~3; + sz_y = (sz_y + 3) & ~3; } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { From e9bc6b159dc91a9a2f84361caa65301e058c36f0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Aug 2018 11:32:04 -0700 Subject: [PATCH 55/58] UI: Use a larger buffer for realpath(). Hopefully will prevent crashes on Mac. --- Common/FileUtil.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 776913f63c..88581332c7 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -24,6 +24,7 @@ #include "ppsspp_config.h" +#include #include "FileUtil.h" #include "StringUtils.h" @@ -152,11 +153,12 @@ std::string ResolvePath(const std::string &path) { output = output.substr(4); delete [] buf; return output; + #else - char buf[PATH_MAX + 1]; - if (realpath(path.c_str(), buf) == nullptr) + std::unique_ptr buf(new char[PATH_MAX + 32768]); + if (realpath(path.c_str(), buf.get()) == nullptr) return path; - return buf; + return buf.get(); #endif } From 274b1eaa0e8f8141c382706fd897a48fcdbee595 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Aug 2018 11:51:06 -0700 Subject: [PATCH 56/58] GPU: Fix typo with wrong type. No behavior change, just fixes a warning. --- GPU/Common/GPUStateUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2e952270c3..a4432fd971 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -48,7 +48,7 @@ bool NeedsTestDiscard() { return true; if (!gstate.isAlphaBlendEnabled()) return true; - if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) + if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_SRCBLEND_DOUBLESRCALPHA) return true; // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { From 8ba1f049dae9772cdfc32496899ffdd8d3186ff7 Mon Sep 17 00:00:00 2001 From: orbea Date: Sun, 26 Aug 2018 12:59:02 -0700 Subject: [PATCH 57/58] Allow choosing to use the system snappy or not. --- CMakeLists.txt | 1 + ext/snappy/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 010b77f441..807923eae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" option(LIBRETRO "Set to ON to generate the libretro target" OFF) # :: Options option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG}) +option(USE_SYSTEM_SNAPPY "Dynamically link against system snappy" ${USE_SYSTEM_SNAPPY}) option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG}) option(USE_SYSTEM_LIBZIP "Dynamically link against system libzip" ${USE_SYSTEM_LIBZIP}) option(USE_WAYLAND_WSI "Set to ON to require Wayland support for Vulkan" ${USE_WAYLAND_WSI}) diff --git a/ext/snappy/CMakeLists.txt b/ext/snappy/CMakeLists.txt index fb1ed966c4..6ab38acd0e 100644 --- a/ext/snappy/CMakeLists.txt +++ b/ext/snappy/CMakeLists.txt @@ -1,6 +1,6 @@ find_package(Snappy) -if(SNAPPY_FOUND) +if(SNAPPY_FOUND AND USE_SYSTEM_SNAPPY) add_library(system_snappy INTERFACE) add_library(Ext::Snappy ALIAS system_snappy) target_link_libraries(system_snappy INTERFACE Snappy::Snappy) From 529b8c602594dbdbe5539441f1f415ff3866872b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Aug 2018 23:10:37 +0200 Subject: [PATCH 58/58] Untested attempt to fix ios/mac discord (no machines around right now) --- CMakeLists.txt | 2 ++ ext/CMakeLists.txt | 2 ++ ext/discord-rpc-build/CMakeLists.txt | 7 ++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 459ad3ee38..f7727f88d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1758,7 +1758,9 @@ if(FFmpeg_FOUND) endif() # Discord integration +if(NOT IOS) target_link_libraries(${CoreLibName} discord-rpc) +endif() setup_target_project(${CoreLibName} Core) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 4a6b8e45a3..ade6594e8f 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -12,4 +12,6 @@ add_subdirectory(glslang) add_subdirectory(snappy) add_subdirectory(udis86) add_subdirectory(SPIRV-Cross-build) +if(NOT IOS) add_subdirectory(discord-rpc-build) +endif() diff --git a/ext/discord-rpc-build/CMakeLists.txt b/ext/discord-rpc-build/CMakeLists.txt index 4417fd7282..a63ec8eecf 100644 --- a/ext/discord-rpc-build/CMakeLists.txt +++ b/ext/discord-rpc-build/CMakeLists.txt @@ -14,9 +14,14 @@ set(ALL_SOURCE_FILES ${SRC_DIR}/discord_rpc.cpp ${SRC_DIR}/rpc_connection.cpp ${SRC_DIR}/serialization.cpp - ${SRC_DIR}/discord_register_osx.m ) +if(APPLE) + set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} + ${SRC_DIR}/discord_register_osx.m + ) +endif() + if(WIN32) set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/connection_win.cpp) set(ALL_SOURCE_FILES ${ALL_SOURCE_FILES} ${SRC_DIR}/discord_register_win.cpp)