From 4373964443cc90c2f45f0829375ac8f00036299e Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 29 Sep 2026 04:07:35 -0400 Subject: [PATCH] [Test] (P10 B): AsyncCompileScenario (AsyncOn/AsyncOff/OptimisticShaderStatus), XfbPrimitiveQueryScenario and PrimitivesGeneratedNoXfbScenario on the split arms of both backends - Espryt Split/Spawn/Tcp, Magma Split/Spawn/Tcp gated, PrimGenReroute split+spawn only --- MobileGL/MG_IntegrationTest/CMakeLists.txt | 139 +++++++++++++++++++++ scripts/ci/spawn_lane_parity.py | 15 ++- 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_IntegrationTest/CMakeLists.txt b/MobileGL/MG_IntegrationTest/CMakeLists.txt index bc691738..39353e8e 100644 --- a/MobileGL/MG_IntegrationTest/CMakeLists.txt +++ b/MobileGL/MG_IntegrationTest/CMakeLists.txt @@ -2500,6 +2500,62 @@ if (MOBILEGL_BUILD_DISAGGREGATED) math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1") endforeach() + # ---- P10 B: AsyncCompileScenario ON THE SPLIT ARMS, IN ITS THREE PINNED CONFIGURATIONS ---- + # + # ITS OWN BLOCK, for the ForcedDs block's reason: every case needs a whole-process compiler + # configuration (MOBILEGL_ASYNC_SHADER_COMPILE, MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS) and + # the registration macro hands every arm the shared environment. The three monolith entries + # near the top of this file - AsyncOn. (the whole scenario), AsyncOff. (the one case that + # has anything to say with compilation inline) and OptimisticShaderStatus. (the Iris shape) + # - are mirrored per arm, with one filter change: AsyncOn. leaves out the Iris case, which + # skips without MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS and runs in its own entry, so every + # entry here runs its case. The AMBIENT configuration is not registered here, for the + # monolith block's own reason: it runs whatever the shipped default is, and the day that + # flips it would stop covering the asynchronous half with nothing red. + # + # WHAT THE SPLIT ARM ADDS: the artifacts a worker built are shipped as program archives and + # linked and drawn by the SERVER's backend, so a worker-built archive the server mis-binds is + # a wrong quadrant here and nowhere in the monolith entries. + # + # THE SWITCH IS THE CLIENT'S ON ALL THREE ARMS, THE TCP ONE INCLUDED. The pool, its threads, + # glMaxShaderCompilerThreadsKHR and GL_MAX_SHADER_COMPILER_THREADS_KHR are frontend state, + # and the advertised GL_KHR_parallel_shader_compile is re-derived on the client from the same + # switch (CapsMirror.cpp, ReconcileClientCompileExtensions). So unlike an MGITEST_MAGMA_FORCE_* + # knob, the tcp fixture server not seeing the variable is exactly what that arm tests. Red + # before that fix: AsyncOff.ExtensionStringMatchesTheConfiguration on the Tcp arm, both + # backends - the string came from the default (async-on) fixture server. + foreach(mglItestAsyncArm IN LISTS MGL_ITEST_MAGMA_ARMS) + mgl_itest_magma_arm_shape(${mglItestAsyncArm}) + string(TOUPPER "${mglItestAsyncArm}" mglItestAsyncArmUpper) + foreach(mglItestAsyncShape AsyncOn AsyncOff OptimisticShaderStatus) + if(mglItestAsyncShape STREQUAL "AsyncOn") + set(mglItestAsyncFilter + "AsyncCompileScenario.*-AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly") + set(mglItestAsyncKnobs "MOBILEGL_ASYNC_SHADER_COMPILE=1") + elseif(mglItestAsyncShape STREQUAL "AsyncOff") + set(mglItestAsyncFilter "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration") + set(mglItestAsyncKnobs "MOBILEGL_ASYNC_SHADER_COMPILE=0") + else() + set(mglItestAsyncFilter "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly") + set(mglItestAsyncKnobs + "MOBILEGL_ASYNC_SHADER_COMPILE=1\;MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1") + endif() + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectGLES.${mglItestAsyncArm}.${mglItestAsyncShape}." + TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}" + TEST_FILTER "${mglItestAsyncFilter}" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-gpu\;integration-${mglItestArmLower}" + TIMEOUT ${MGL_ITEST_TIMEOUT} + ENVIRONMENT "${MGL_ITEST_GLES_${mglItestAsyncArmUpper}_ENVIRONMENT}\;${mglItestAsyncKnobs}" + ${mglItestArmProperties} + ) + list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}") + math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1") + endforeach() + endforeach() + # ---- P5e fix1: THE PUSH-MONOLITH ARM, INSIDE THE GATED SET (ID-107) ---------------------- # @@ -2759,6 +2815,24 @@ if (MOBILEGL_BUILD_DISAGGREGATED) mgl_itest_register_split_arms("TessellationXfbCaptureScenario.*" "") mgl_itest_register_split_arms("XfbCaptureBufferReuseScenario.*" "") + # ---- P10 B: THE TWO XFB QUERY TARGETS ON ONE SPAN --------------------------------------- + # + # XfbPrimitiveQueryScenario asks GL_PRIMITIVES_GENERATED and GL_TRANSFORM_FEEDBACK_PRIMITIVES_ + # WRITTEN about one vertex-only capture, once with room for every point and once overflowing + # (4 generated, 3 written), and reads the captured records back. Under a transport both + # answers are query replies from the server and the records a readback of the server's + # capture, so a WRITTEN that crossed as the GENERATED count, or a result read before the + # span's end record was applied, is a wrong number here. The Magma arms are the + # `DirectVulkan..XfbQuery.` block after the Remint block. + # + # PrimitivesGeneratedNoXfbScenario IS NOT REGISTERED ON THESE ARMS, by name: every case in it + # skips in SetUp on DirectGLES ("the stream-query defect and its reroute are DirectVulkan's"), + # because ES has no GENERATED counter for a draw with no capture span and Espryt's CPU + # accounting is a different mechanism. Three arms of guaranteed skips would be a green that + # ran nothing. Its Magma arms are the `PrimGen.` / `PrimGenReroute.` entries in the same + # block as the XfbQuery. ones. + mgl_itest_register_split_arms("XfbPrimitiveQueryScenario.*" "") + # ---- P5e package vi (MG_Remote/CONTRACT-P5E.md ยง5.1, ID-82 / ruling 2) -------------------- # # Client-memory vertices and indices now cross as owned ordinary buffers. @@ -3702,6 +3776,71 @@ if (MOBILEGL_BUILD_DISAGGREGATED) endforeach() endif() +# P10 B: ASYNC COMPILATION, THE XFB QUERY PAIR AND GL_PRIMITIVES_GENERATED ON MAGMA, all three +# arms, GATED, in the band flavour (role-split state, strict errors, run-ahead). The DirectGLES +# half of the first two is registered beside the other Espryt arms; the third is Magma's alone. +# One registration per arm and shape, and every entry gets a private log through +# MGL_SPLIT_ARM_TEST_LISTS (no name there matches a lane marker SplitLogPaths arms). +# +# AsyncOn. / AsyncOff. / OptimisticShaderStatus. AsyncCompileScenario, the monolith entries' +# three configurations (AsyncOn. without the Iris case, which has its own entry), for the +# reason the Espryt block states - including why the tcp arm keeps all three: the switch is +# the client's, and so is the extension since this package. +# XfbQuery. XfbPrimitiveQueryScenario, both cases. +# PrimGen. PrimitivesGeneratedNoXfbScenario under the bring-up probe's Auto verdict, minus the +# arming case, which skips unless the reroute is pinned (a guaranteed skip is not coverage). +# PrimGenReroute. The same scenario with MOBILEGL_MAGMA_PRIMGEN_QUERY_REROUTE=1, arming case +# included. SPLIT AND SPAWN ONLY: the renderer reads the knob on the SERVER, and the tcp +# arm's server is the lane fixture, which no per-entry property reaches - a tcp copy would +# run the Auto verdict under a name claiming the pin (spawn_lane_parity.py, +# MAGMA_SERVER_ENV_KNOB_NO_TCP). One entry per case, as ctest runs every discovered case: +# the arming line is LATCHED once per process, so a process that ran an earlier rerouted +# case first reads nothing new (measured, running the scenario as one process). +if (MOBILEGL_BUILD_DISAGGREGATED) + foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS) + mgl_itest_magma_arm_shape(${mglItestArm}) + mgl_itest_join_environment(mglItestMagmaP10bEnvironment + ${MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV} ${mglItestArmTransportEnv}) + set(mglItestP10bShapes AsyncOn AsyncOff OptimisticShaderStatus XfbQuery PrimGen) + if(NOT mglItestArm STREQUAL "Tcp") + list(APPEND mglItestP10bShapes PrimGenReroute) + endif() + foreach(mglItestP10bShape IN LISTS mglItestP10bShapes) + set(mglItestP10bKnobs "") + if(mglItestP10bShape STREQUAL "AsyncOn") + set(mglItestP10bFilter + "AsyncCompileScenario.*-AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly") + set(mglItestP10bKnobs "\;MOBILEGL_ASYNC_SHADER_COMPILE=1") + elseif(mglItestP10bShape STREQUAL "AsyncOff") + set(mglItestP10bFilter "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration") + set(mglItestP10bKnobs "\;MOBILEGL_ASYNC_SHADER_COMPILE=0") + elseif(mglItestP10bShape STREQUAL "OptimisticShaderStatus") + set(mglItestP10bFilter "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly") + set(mglItestP10bKnobs + "\;MOBILEGL_ASYNC_SHADER_COMPILE=1\;MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1") + elseif(mglItestP10bShape STREQUAL "XfbQuery") + set(mglItestP10bFilter "XfbPrimitiveQueryScenario.*") + elseif(mglItestP10bShape STREQUAL "PrimGen") + set(mglItestP10bFilter + "PrimitivesGeneratedNoXfbScenario.*-PrimitivesGeneratedNoXfbScenario.TheRerouteIsActuallyArmedWhenTheEnvironmentPinsItOn") + else() + set(mglItestP10bFilter "PrimitivesGeneratedNoXfbScenario.*") + set(mglItestP10bKnobs "\;MOBILEGL_MAGMA_PRIMGEN_QUERY_REROUTE=1") + endif() + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectVulkan.${mglItestArm}.${mglItestP10bShape}." + TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}" + TEST_FILTER "${mglItestP10bFilter}" + DISCOVERY_TIMEOUT 30 + PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT} + ${mglItestArmProperties} + ENVIRONMENT "${mglItestMagmaP10bEnvironment}${mglItestP10bKnobs}") + list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}") + math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1") + endforeach() + endforeach() +endif() + # Magma application buffers: public GL pixels/bytes, with the two role blocks and # strict field checks forced on. Existing public scenarios supply offset, mutation, # persistent-map, growth and indirect coverage; no copied backend implementation. diff --git a/scripts/ci/spawn_lane_parity.py b/scripts/ci/spawn_lane_parity.py index 801b08b9..22447aaa 100644 --- a/scripts/ci/spawn_lane_parity.py +++ b/scripts/ci/spawn_lane_parity.py @@ -97,6 +97,18 @@ MAGMA_INPROC_ONLY = ("MagmaRunAheadScenario.", "MagmaWireCacheScenario.") # unit-private placeholder for an invalid image unit instead of a null descriptor - the # knob-free `.ImageUnitWindow.` copies of the same two cases keep their tcp entries. Two cases, so two # tails (one case each), as for `.Reclaim.`. +# P10 B: the `.PrimGenReroute.` entries set MOBILEGL_MAGMA_PRIMGEN_QUERY_REROUTE=1, which the +# SERVER's VulkanRenderer reads to pin the GL_PRIMITIVES_GENERATED reroute on - the knob-free +# `.PrimGen.` copies (the bring-up probe's Auto verdict) keep their tcp entries. Eight cases, eight +# tails. +PRIMGEN_REROUTE_CASES = ("CountsADrawMadeWithNoCaptureSpan", + "CountsUnderRasterizerDiscardWithNoCaptureSpan", + "CountsATessellatedPatchWithNoCaptureSpan", + "ASpanMixingActiveAndInactiveDrawsAccumulatesBoth", + "APausedSpanCountsACpuPricedDrawExactlyOnce", + "APausedSpanCountsATessellatedPatchExactlyOnce", + "APausedSpanCountsAnInstancedDrawExactlyOnce", + "TheRerouteIsActuallyArmedWhenTheEnvironmentPinsItOn") MAGMA_SERVER_ENV_KNOB_NO_TCP = (".ShaderMip1.", ".ShaderMip2.", ".DepthMip.", ".DefaultBlitShape1.", ".MsResolve1.", ".StaleSerial.", ".MsFlip1.", ".MsResolveBug.", ".MsFlipBug.", ".MsResolveElide.", @@ -106,7 +118,8 @@ MAGMA_SERVER_ENV_KNOB_NO_TCP = (".ShaderMip1.", ".ShaderMip2.", ".DepthMip.", ".Reclaim.MagmaWireReclaimScenario.RespecifyAndDrawEachStoreInOneFrameStaysWithinTheDeferredBudget", ".Reclaim.MagmaWireReclaimScenario.ManySmallRespecifyAndDrawRoundsStayUnderTheStoreCountCeiling", ".Reclaim.MagmaWireReclaimScenario.ADrawAfterTheEarlyReclaimFollowsTheNewStoreNotTheMemoizedHandle", - ".Reclaim.MagmaWireReclaimScenario.DescriptorSetsRewindInsideOneLongFrameAfterTheirSubmitRetires") + ".Reclaim.MagmaWireReclaimScenario.DescriptorSetsRewindInsideOneLongFrameAfterTheirSubmitRetires") + tuple( + f".PrimGenReroute.PrimitivesGeneratedNoXfbScenario.{case}" for case in PRIMGEN_REROUTE_CASES) def lane_names(build_dir, label):