summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/PixelShaderGen.cpp
diff options
context:
space:
mode:
authorStarlightbotanist <starlightbotanist@gmail.com>2026-10-01 13:28:38 -0400
committerStarlightbotanist <starlightbotanist@gmail.com>2026-10-04 00:25:01 -0400
commit4ba37f1dde9ea3da96716f5613498bbb4228fe4c (patch)
tree33120114957a9958e725f2ffb174b0d9c8ad345c /Source/Core/VideoCommon/PixelShaderGen.cpp
parent003c61b78bec7955dbe765afd61abca0c6bfabf2 (diff)
VideoCommon: Work around Adreno TEV zero input miscompilation
Some Qualcomm Android drivers from version 700 onward miscompile specialized TEV pixel shaders when color input A or B is TevColorArg::Zero. Use konstLookup[8].rgb, which PixelShaderManager initializes to zero, to keep these inputs dependent on a uniform value. Use the existing driver bug gate for OpenGL and Vulkan. Other inputs and unaffected drivers retain their original shader expressions.
Diffstat (limited to 'Source/Core/VideoCommon/PixelShaderGen.cpp')
-rw-r--r--Source/Core/VideoCommon/PixelShaderGen.cpp26
1 files changed, 20 insertions, 6 deletions
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp
index 5ce120e9ff..669d80e317 100644
--- a/Source/Core/VideoCommon/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/PixelShaderGen.cpp
@@ -1434,20 +1434,34 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
if (ac.dest >= TevOutput::Color0)
out.SetConstantsUsed(C_COLORS + u32(ac.dest.Value()), C_COLORS + u32(ac.dest.Value()));
+ const char* color_a = tev_c_input_table[cc.a];
+ const char* color_b = tev_c_input_table[cc.b];
+ if ((cc.a == TevColorArg::Zero || cc.b == TevColorArg::Zero) &&
+ DriverDetails::HasBug(DriverDetails::BUG_BROKEN_TEV_COLOR_ZERO))
+ {
+ // The Adreno shader compiler incorrectly optimizes the int3(0,0,0) constant, causing incorrect
+ // colors. To work around this, we trick the compiler by using konstLookup[8], which
+ // PixelShaderManager initializes to zero, to keep these inputs dependent on a uniform value.
+ // Slot 8 is safe because it is part of the invalid konst range (reads as zero on hardware).
+ // It is never written at runtime and therefore stays zero.
+ if (cc.a == TevColorArg::Zero)
+ color_a = "konstLookup[8].rgb";
+ if (cc.b == TevColorArg::Zero)
+ color_b = "konstLookup[8].rgb";
+ }
+
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VECTOR_BITWISE_AND))
{
- out.Write("\ttevin_a = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.a],
- tev_a_input_table[ac.a]);
- out.Write("\ttevin_b = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.b],
- tev_a_input_table[ac.b]);
+ out.Write("\ttevin_a = int4({} & 255, {} & 255);\n", color_a, tev_a_input_table[ac.a]);
+ out.Write("\ttevin_b = int4({} & 255, {} & 255);\n", color_b, tev_a_input_table[ac.b]);
out.Write("\ttevin_c = int4({} & 255, {} & 255);\n", tev_c_input_table[cc.c],
tev_a_input_table[ac.c]);
}
else
{
- out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.a],
+ out.Write("\ttevin_a = int4({}, {})&int4(255, 255, 255, 255);\n", color_a,
tev_a_input_table[ac.a]);
- out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.b],
+ out.Write("\ttevin_b = int4({}, {})&int4(255, 255, 255, 255);\n", color_b,
tev_a_input_table[ac.b]);
out.Write("\ttevin_c = int4({}, {})&int4(255, 255, 255, 255);\n", tev_c_input_table[cc.c],
tev_a_input_table[ac.c]);