mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-10-11 22:49:50 +00:00
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.
This commit is contained in:
@@ -33,7 +33,8 @@ struct alignas(16) PixelShaderConstants
|
||||
float4 zslope;
|
||||
std::array<float, 2> efbscale; // .xy
|
||||
|
||||
// Constants from here onwards are only used in ubershaders, other than pack2.
|
||||
// Constants from here onwards are mainly used in ubershaders. Specialized shaders also use
|
||||
// pack2 and konst.
|
||||
u32 genmode; // .z
|
||||
u32 alphaTest; // .w
|
||||
u32 fogParam3; // .x
|
||||
|
||||
@@ -161,6 +161,10 @@ constexpr BugInfo m_known_bugs[] = {
|
||||
BUG_BROKEN_DYNAMIC_SAMPLER_INDEXING, -1.0, -1.0, true},
|
||||
{API_VULKAN, OS_ANDROID, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN,
|
||||
BUG_SLOW_OPTIMAL_IMAGE_TO_BUFFER_COPY, -1.0, -1.0, true},
|
||||
{API_OPENGL, OS_ANDROID, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN,
|
||||
BUG_BROKEN_TEV_COLOR_ZERO, 700.0, -1.0, true},
|
||||
{API_VULKAN, OS_ANDROID, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN,
|
||||
BUG_BROKEN_TEV_COLOR_ZERO, 0x802bc000, -1.0, true},
|
||||
{API_VULKAN, OS_ALL, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_BROKEN_DEPTH_CLAMP_CONTROL,
|
||||
-1.0, -1.0, true},
|
||||
};
|
||||
@@ -312,6 +316,7 @@ static const char* to_string(Bug bug)
|
||||
case BUG_BROKEN_DISCARD_WITH_EARLY_Z: return "broken-discard-with-early-z";
|
||||
case BUG_BROKEN_DYNAMIC_SAMPLER_INDEXING: return "broken-dynamic-sampler-indexing";
|
||||
case BUG_SLOW_OPTIMAL_IMAGE_TO_BUFFER_COPY: return "slow-optimal-image-to-buffer-copy";
|
||||
case BUG_BROKEN_TEV_COLOR_ZERO: return "broken-tev-color-zero";
|
||||
case BUG_BROKEN_DEPTH_CLAMP_CONTROL: return "broken-depth-clamp-control";
|
||||
}
|
||||
return "Unknown";
|
||||
|
||||
@@ -344,6 +344,14 @@ enum Bug
|
||||
// Ended Version: -1
|
||||
BUG_SLOW_OPTIMAL_IMAGE_TO_BUFFER_COPY,
|
||||
|
||||
// BUG: Some Qualcomm Android drivers miscompile specialized TEV pixel shaders when
|
||||
// color input A or B is Zero.
|
||||
// Use the konst lookup table to provide 0 at runtime and avoid the miscompile.
|
||||
// Affected devices: Qualcomm drivers on Android.
|
||||
// Started Version: 700 (0x802bc000 for Vulkan)
|
||||
// Ended Version: -1
|
||||
BUG_BROKEN_TEV_COLOR_ZERO,
|
||||
|
||||
// BUG: Incorrect implementation of VK_EXT_depth_clamp_control causes incorrect depth values to
|
||||
// be written to the depth buffer.
|
||||
// Affected devices: Official AMD (RADV is unaffected)
|
||||
|
||||
@@ -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]);
|
||||
|
||||
Reference in New Issue
Block a user