diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index 14c8732580..ec587411dc 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -33,7 +33,8 @@ struct alignas(16) PixelShaderConstants float4 zslope; std::array 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 diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index b657d7721c..3027aab154 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -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"; diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 64ed656f3f..39eb86eb59 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -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) 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]);