Merge pull request #22912 from hrydgard/pvr-dynamic-ubo-crash

Vulkan: Work around a PowerVR crash when a vertex shader doesn't read the lights UBO
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-11-03 19:56:02 +01:00
commit caa91b54b5
4 files changed
+13 -1

No files matched your search

+4
View File
@@ -1140,6 +1140,10 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
} else if (caps_.vendor == GPUVendor::VENDOR_IMGTEC) {
// Not sure about driver versions, so let's just ban, impact is tiny.
bugs_.Infest(Bugs::PVR_BAD_16BIT_TEXFORMATS);
// At draw time, the driver writes the address of every dynamic UBO in the bound descriptor set into a
// table it sized for the ones the shader stage uses, so a stage that skips one runs off the end of it.
// Seen on a BXM-8-256 (Moto G54): a page fault in vkCmdDrawIndexed every few seconds in F1 2009.
bugs_.Infest(Bugs::PVR_UNUSED_DYNAMIC_UBO_OVERRUN);
}
if (!vulkan->Extensions().KHR_depth_stencil_resolve) {
+1
View File
@@ -538,6 +538,7 @@ const char *Bugs::GetBugName(uint32_t bug) {
case ADRENO_RESOURCE_DEADLOCK: return "ADRENO_RESOURCE_DEADLOCK";
case PVR_BAD_16BIT_TEXFORMATS: return "PVR_BAD_16BIT_TEXFORMATS";
case EMPTY_RENDERPASS_BROKEN_MALI: return "EMPTY_RENDERPASS_BROKEN_MALI";
case PVR_UNUSED_DYNAMIC_UBO_OVERRUN: return "PVR_UNUSED_DYNAMIC_UBO_OVERRUN";
default: return "(N/A)";
}
}
+1
View File
@@ -348,6 +348,7 @@ public:
PVR_BAD_16BIT_TEXFORMATS = 14,
NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI = 15,
EMPTY_RENDERPASS_BROKEN_MALI = 16,
PVR_UNUSED_DYNAMIC_UBO_OVERRUN = 17,
MAX_BUG,
};
+7 -1
View File
@@ -133,6 +133,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
int ls0 = id.Bits(VS_BIT_LS0, 2);
int ls1 = id.Bits(VS_BIT_LS1, 2);
bool enableLighting = id.Bit(VS_BIT_LIGHTING_ENABLE);
// See PVR_UNUSED_DYNAMIC_UBO_OVERRUN: every vertex shader reads the lights UBO, which is bound as dynamic either way.
const bool readUnusedLights = compat.shaderLanguage == GLSL_VULKAN && !enableLighting && !doShadeMapping && bugs.Has(Draw::Bugs::PVR_UNUSED_DYNAMIC_UBO_OVERRUN);
int matUpdate = id.Bits(VS_BIT_MATERIAL_UPDATE, 3);
bool lightUberShader = id.Bit(VS_BIT_LIGHT_UBERSHADER) && enableLighting; // checking lighting here for the shader test's benefit, in reality if ubershader is set, lighting is set.
@@ -177,7 +179,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "\n");
WRITE(p, "layout (std140, set = 0, binding = %d) uniform baseVars {\n%s};\n", DRAW_BINDING_DYNUBO_BASE, ub_baseStr);
if (enableLighting || doShadeMapping)
if (enableLighting || doShadeMapping || readUnusedLights)
WRITE(p, "layout (std140, set = 0, binding = %d) uniform lightVars {\n%s};\n", DRAW_BINDING_DYNUBO_LIGHT, ub_vs_lightsStr);
if (useHWTransform)
@@ -1005,6 +1007,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " outPos.y *= -1.0;\n");
}
if (readUnusedLights) {
// Declaring the block isn't enough, it has to be read. The ambient alpha is never below zero.
WRITE(p, " if (u_ambient.w < -1.0) outPos.x += 1.0;\n");
}
// We've named the output gl_Position in HLSL as well.
WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix);