Merge pull request #15611 from hrydgard/mali-bug-workaround

Workaround old Mali driver bug with discard + stencil
This commit is contained in:
Unknown W. Brackets 2022-06-18 17:13:58 -07:00 committed by GitHub
commit d07c256a1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 4 deletions

View file

@ -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;

View file

@ -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

View file

@ -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:

View file

@ -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) {

View file

@ -80,6 +80,7 @@ struct CompatFlags {
bool MpegAvcWarmUp;
bool BlueToAlpha;
bool CenteredLines;
bool MaliDepthStencilBugWorkaround;
};
class IniFile;

View file

@ -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,6 +342,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) && 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());
}
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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