[Feat] (MG_Util, MG_Test): enable asynchronous shader compilation by default (P1 stage 7)

kAsyncShaderCompileDefault flips to true, which also advertises
GL_KHR_parallel_shader_compile by default on both backends. Unset
MOBILEGL_ASYNC_SHADER_COMPILE now resolves to ON; =0 remains the complete kill
switch (reverts the threading and withdraws the extension together).

The gate behind the flip (headless Mesa - llvmpipe for Espryt, lavapipe for
Magma - at c6299f75): GL30/31/32/33/40 mustpass plus the
KHR-GL46.parallel_shader_compile group, both backends, async=1 with the
extension advertised. 58,344 case-runs, 8 failures - and every one of the 8
also fails standalone at async=0, in the full async=0 suite arms with an
identical per-case failure set, and under the pre-P1-stage-6 library. Zero
async-attributable deltas; the 8 are Mesa-upgrade drift (4 unique signatures:
Espryt GL40 transform_feedback.draw_xfb{,_feedbackk}_test, Magma
texture_size_promotion.functional + packed_pixels rgb9_e5_format_red on
GL32/33/40), recorded for separate follow-up.

Validation under the flipped default (no env var): 553/553 unit at the default
AND with the kill switch; parallel_shader_compile 3/3 on both backends proving
the default advertises; 44+44 integration scenarios; 71/72 CI trace-replay
fixtures (the one failure is the pre-existing create-indirect lavapipe crash,
identical under the pre-fix library). The lifecycle test's contract updates
with the default: AsyncIsOnByDefaultAndTheOverrideDecidesEitherWay.

Not covered by this gate and deliberately left open: SSO/DSA suites (GL41+,
separate follow-up per review), and real-driver confirmation on NVIDIA/Mali -
the Mali-G77 on-device sweep runs separately as a report-only pass.
This commit is contained in:
BZLZHH
2026-08-09 02:04:59 -04:00
parent c6299f754f
commit 2e6fc1ffc0
2 changed files with 18 additions and 15 deletions
+10 -8
View File
@@ -135,16 +135,18 @@ TEST(ShaderCompilePoolLifecycle, DetectedThreadCountIsPositive) {
EXPECT_GE(DetectShaderCompileThreadCount(), 1u);
}
TEST(ShaderCompilePoolLifecycle, AsyncIsOffByDefaultAndTheOverrideDecidesEitherWay) {
// The shipped default is still off, and an unset MOBILEGL_ASYNC_SHADER_COMPILE resolves
// to it. If the first expectation ever fails without the constant having been
// deliberately flipped, something enabled async by accident.
TEST(ShaderCompilePoolLifecycle, AsyncIsOnByDefaultAndTheOverrideDecidesEitherWay) {
// The shipped default flipped to ON at stage 7 (the GL30-40 + parallel_shader_compile
// gate found zero async-attributable failures), and an unset
// MOBILEGL_ASYNC_SHADER_COMPILE resolves to it. If the first expectation ever fails
// without the constant having been deliberately flipped back, something disabled async
// by accident - the kill switch below is the supported way off.
//
// Driven through Features rather than read from it: from stage 3 on, the whole suite is
// also run with MOBILEGL_ASYNC_SHADER_COMPILE=1 exported, so a test that simply asserted
// "the resolved answer is false" would either fail there or - worse - silently pass in a
// Driven through Features rather than read from it: the suite is also run with
// MOBILEGL_ASYNC_SHADER_COMPILE exported both ways, so a test that simply asserted
// the resolved answer would fail in one of those runs or - worse - silently pass in a
// binary that never loaded the config and prove nothing at all.
EXPECT_FALSE(kAsyncShaderCompileDefault);
EXPECT_TRUE(kAsyncShaderCompileDefault);
const MG_Config::QuirkOverride saved = MG_Config::Features.AsyncShaderCompile;
MG_Config::Features.AsyncShaderCompile = MG_Config::QuirkOverride::Auto;
+8 -7
View File
@@ -18,13 +18,14 @@
// time. Do not add one here.
namespace MobileGL::MG_Util::Async {
// Stage 1 ships the whole machinery switched off: the pool is constructible and tested,
// but nothing in the GL pipeline posts to it. The flip to true happens only after the
// real-client soak in the final stage, because the riskiest part of asynchronous
// compilation is not the joins - it is that Iris and Sodium change their submission
// schedule the moment GL_KHR_parallel_shader_compile is advertised, and a recorded trace
// can never cover that path.
inline constexpr Bool kAsyncShaderCompileDefault = false;
// Stage 7: on by default. The gate behind the flip (2026-08-09, headless Mesa, both
// backends): GL30-40 mustpass + KHR-GL46.parallel_shader_compile at async=1 with the
// extension advertised - 58,344 case-runs, 8 failures, and every one of the 8 also
// fails standalone at async=0 and under the pre-P1 library, i.e. zero async-attributable
// deltas. The risk this comment used to name - Iris and Sodium changing their submission
// schedule the moment GL_KHR_parallel_shader_compile is advertised - remains the one
// thing a recorded trace cannot cover, which is why the kill switch below stays.
inline constexpr Bool kAsyncShaderCompileDefault = true;
// MOBILEGL_ASYNC_SHADER_COMPILE forces the answer either way; unset keeps the built-in
// default above. Falsy is a complete kill switch: it reverts the threading *and*