From 7656e2b9d961fcf092958781fffab840ab6d6c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 8 May 2022 23:54:08 +0200 Subject: [PATCH 1/4] Increase the difficulty of the GPU driver test Trying to make the situation more similar to the Midnight Club map problem, but still failing to repro in the GPU test, though it repros fine in-game. --- UI/GPUDriverTestScreen.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 93ed51976d..10a6640520 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -321,6 +321,7 @@ void GPUDriverTestScreen::DiscardTest() { InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw); BlendState *blendOff = draw->CreateBlendState({ false, 0xF }); + BlendState *blendOffNoColor = draw->CreateBlendState({ false, 0x8 }); // Write depth, write stencil. DepthStencilStateDesc dsDesc{}; @@ -331,8 +332,8 @@ void GPUDriverTestScreen::DiscardTest() { dsDesc.front.compareMask = 0xFF; dsDesc.front.compareOp = Comparison::ALWAYS; dsDesc.front.passOp = StencilOp::REPLACE; - dsDesc.front.failOp = StencilOp::ZERO; - dsDesc.front.depthFailOp = StencilOp::ZERO; + dsDesc.front.failOp = StencilOp::REPLACE; // These two shouldn't matter, because the test that fails is discard, not stencil. + dsDesc.front.depthFailOp = StencilOp::REPLACE; dsDesc.front.writeMask = 0xFF; dsDesc.back = dsDesc.front; DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc); @@ -353,6 +354,9 @@ void GPUDriverTestScreen::DiscardTest() { dsDesc.stencilEnabled = true; dsDesc.depthCompare = Comparison::ALWAYS; dsDesc.front.compareOp = Comparison::EQUAL; + dsDesc.front.failOp = StencilOp::KEEP; + dsDesc.front.depthFailOp = StencilOp::KEEP; + dsDesc.front.writeMask = 0x0; dsDesc.back = dsDesc.front; DepthStencilState *stencilEqualDepthAlways = draw->CreateDepthStencilState(dsDesc); @@ -393,7 +397,7 @@ void GPUDriverTestScreen::DiscardTest() { PipelineDesc discardDesc{ Primitive::TRIANGLE_LIST, { draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discardFragShader_ }, - inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc, + inputLayout, depthStencilWrite, blendOffNoColor, rasterNoCull, &vsColBufDesc, }; discardWriteDepthStencil_ = draw->CreateGraphicsPipeline(discardDesc); discardDesc.depthStencil = depthWrite; @@ -501,7 +505,7 @@ void GPUDriverTestScreen::DiscardTest() { dc.Flush(); dc.BeginPipeline(writePipelines[j], samplerNearest_); - // Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then leave 0xFF as the stencil value and draw the rectangles at depth 0.5. + // Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then set 0xFF as the stencil value and draw the rectangles at depth 0.5. draw->SetStencilRef(0x0); dc.SetCurZ(0.1f); dc.FillRect(UI::Drawable(bgColorBAD), bounds); From 78ad81db9ed2a1a1391ec6c0227f81e6b635aa07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 9 May 2022 01:15:40 +0200 Subject: [PATCH 2/4] Show detected GPU driver bugs in system info --- Common/GPU/thin3d.cpp | 13 +++++++++++++ Common/GPU/thin3d.h | 6 ++++++ UI/DevScreens.cpp | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index c611cca0f1..8ae1ded37d 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -592,5 +592,18 @@ void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_ } } +const char *Bugs::GetBugName(uint32_t bug) { + switch (bug) { + case NO_DEPTH_CANNOT_DISCARD_STENCIL: return "NO_DEPTH_CANNOT_DISCARD_STENCIL"; + case DUAL_SOURCE_BLENDING_BROKEN: return "DUAL_SOURCE_BLENDING_BROKEN"; + case ANY_MAP_BUFFER_RANGE_SLOW: return "ANY_MAP_BUFFER_RANGE_SLOW"; + case PVR_GENMIPMAP_HEIGHT_GREATER: return "PVR_GENMIPMAP_HEIGHT_GREATER"; + case BROKEN_NAN_IN_CONDITIONAL: return "BROKEN_NAN_IN_CONDITIONAL"; + case COLORWRITEMASK_BROKEN_WITH_DEPTHTEST: return "COLORWRITEMASK_BROKEN_WITH_DEPTHTEST"; + case BROKEN_FLAT_IN_SHADER: return "BROKEN_FLAT_IN_SHADER"; + case EQUAL_WZ_CORRUPTS_DEPTH: return "EQUAL_WZ_CORRUPTS_DEPTH"; + case MALI_STENCIL_DISCARD_BUG: return "MALI_STENCIL_DISCARD_BUG"; + } +} } // namespace Draw diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 60e70b4c28..2a3ea9d09d 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -308,6 +308,10 @@ public: void Infest(uint32_t bug) { flags_ |= (1 << bug); } + uint32_t MaxBugIndex() const { + return (uint32_t)MAX_BUG; + } + const char *GetBugName(uint32_t bug); enum : uint32_t { NO_DEPTH_CANNOT_DISCARD_STENCIL = 0, @@ -318,6 +322,8 @@ public: COLORWRITEMASK_BROKEN_WITH_DEPTHTEST = 5, BROKEN_FLAT_IN_SHADER = 6, EQUAL_WZ_CORRUPTS_DEPTH = 7, + MALI_STENCIL_DISCARD_BUG = 8, + MAX_BUG, }; protected: diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 71961b8d21..11bbb70c00 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -682,6 +682,26 @@ void SystemInfoScreen::CreateViews() { cpuExtensions->Add(new TextView(exts[i], new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); } + ViewGroup *driverBugsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); + driverBugsScroll->SetTag("DevSystemInfoDriverBugs"); + LinearLayout *driverBugs = new LinearLayoutList(ORIENT_VERTICAL); + driverBugs->SetSpacing(0); + driverBugsScroll->Add(driverBugs); + + tabHolder->AddTab(si->T("Driver bugs"), driverBugsScroll); + + bool anyDriverBugs = false; + for (int i = 0; i < (int)draw->GetBugs().MaxBugIndex(); i++) { + if (draw->GetBugs().Has(i)) { + anyDriverBugs = true; + driverBugs->Add(new TextView(draw->GetBugs().GetBugName(i), new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); + } + } + + if (!anyDriverBugs) { + driverBugs->Add(new TextView(si->T("No GPU driver bugs detected"), new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); + } + ViewGroup *gpuExtensionsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); gpuExtensionsScroll->SetTag("DevSystemInfoOGLExt"); LinearLayout *gpuExtensions = new LinearLayoutList(ORIENT_VERTICAL); From d0ea3b32844db43d92ef4b95261a393a908e3607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 9 May 2022 01:15:56 +0200 Subject: [PATCH 3/4] Work around the Mali stencil discard bug the same way as the Adreno one. --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 5 +++++ GPU/Common/ShaderId.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 66b800dae1..db01e817c0 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -823,6 +823,11 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) // corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case // is detected. See: https://github.com/hrydgard/ppsspp/issues/11937 bugs_.Infest(Bugs::EQUAL_WZ_CORRUPTS_DEPTH); + + if (IsHashMaliDriverVersion(deviceProps) || VK_VERSION_MAJOR(deviceProps.driverVersion) <= 16) { + // At least one driver at the upper end of the range is known to be likely to suffer from the bug causing issue #13833 (Midnight Club map broken). + bugs_.Infest(Bugs::MALI_STENCIL_DISCARD_BUG); + } } caps_.deviceID = deviceProps.deviceID; diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 291c1afa8b..230de66e65 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -341,6 +341,10 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) { if (g_Config.bVendorBugChecksEnabled) { if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled()); + } else if (bugs.Has(Draw::Bugs::MALI_STENCIL_DISCARD_BUG)) { + // Very similar driver bug to the Adreno one, with the same workaround (though might look into if there are cheaper ones!) + // Keeping the conditions separate since it can probably be made tighter. + id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled()); } } } From 8922be2015154b3aa7b06e2011c05863b22af23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 16 Apr 2022 23:47:05 +0200 Subject: [PATCH 4/4] Out of performance paranoia, limit the Mali workaround to known affected games --- Core/Compatibility.cpp | 1 + Core/Compatibility.h | 1 + GPU/Common/ShaderId.cpp | 3 ++- assets/compat.ini | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index f1be3b94fe..db48c4f4c9 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -81,6 +81,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "MpegAvcWarmUp", &flags_.MpegAvcWarmUp); CheckSetting(iniFile, gameID, "BlueToAlpha", &flags_.BlueToAlpha); CheckSetting(iniFile, gameID, "CenteredLines", &flags_.CenteredLines); + CheckSetting(iniFile, gameID, "MaliDepthStencilBugWorkaround", &flags_.MaliDepthStencilBugWorkaround); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 37173adc6d..9340c36411 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -80,6 +80,7 @@ struct CompatFlags { bool MpegAvcWarmUp; bool BlueToAlpha; bool CenteredLines; + bool MaliDepthStencilBugWorkaround; }; class IniFile; diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 230de66e65..cbfbeeffa3 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -3,6 +3,7 @@ #include "Common/GPU/thin3d.h" #include "Common/StringUtils.h" +#include "Core/System.h" #include "Core/Config.h" #include "GPU/ge_constants.h" @@ -341,7 +342,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) { if (g_Config.bVendorBugChecksEnabled) { if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled()); - } else if (bugs.Has(Draw::Bugs::MALI_STENCIL_DISCARD_BUG)) { + } else if (bugs.Has(Draw::Bugs::MALI_STENCIL_DISCARD_BUG) && PSP_CoreParameter().compat.flags().MaliDepthStencilBugWorkaround) { // Very similar driver bug to the Adreno one, with the same workaround (though might look into if there are cheaper ones!) // Keeping the conditions separate since it can probably be made tighter. id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled()); diff --git a/assets/compat.ini b/assets/compat.ini index 1f0e2b2178..5b6cfadeed 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -586,6 +586,23 @@ NPJH50304 = true ULES00703 = true ULAS42095 = true +[MaliDepthStencilBugWorkaround] +# See issue #13833 where the map is supposed to be round but is not. + +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true +# Midnight Club 3 : DUB edition +ULUS10021 = true +ULES00108 = true + +# Tales of Phantasia - Narikiri Dungeon X. See #15526 +ULJS00293 = true + [RequireDefaultCPUClock] # GOW : Ghost of Sparta UCUS98737 = true