diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a06b6a09..a5882c0a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -263,13 +263,6 @@ jobs: cmake --build "${BUILD_DIR}" --target MobileGL --parallel "$(nproc)" python3 scripts/ci/runtime_mode_proof.py build --build-dir "${BUILD_DIR}" \ --mode monolith --output "${BUILD_DIR}/runtime-mode.json" - python3 - "${BUILD_DIR}/runtime-mode.json" <<'PY' - import json, sys - rows = json.load(open(sys.argv[1]))['production_compilation'] - if not rows or any(row['definitions'].get('MOBILEGL_PIPE_PUSH') != '1' for row in rows): - sys.exit('::error::the push control was not compiled with MOBILEGL_PIPE_PUSH=1 everywhere') - print(f'push control: {len(rows)} production sources compiled with MOBILEGL_PIPE_PUSH=1, zero MG_Remote symbols') - PY - name: Prepare packaged test metadata run: python3 scripts/ci/prepare_test_runtime.py "${BUILD_DIR}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 375e0c66..0c940015 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,18 +31,16 @@ option(MOBILEGL_BUILD_DISAGGREGATED_INPROC "Compile the in-process (one-process, option(MOBILEGL_BUILD_SERVER_SPIKE "Build the P0 spike-A MobileGLServer delivery-chain executable (Android only)" OFF) option(MOBILEGL_BUILD_EXTMEM_PROBE "Package tools/spikes/extmem_probe as libMobileGLExtmemProbe.so for the trace APK's exec hook (P11 A3, Android only)" OFF) option(MOBILEGL_EXTMEM_PROBE_AS_SERVER "Spike only (P11 B2 step 1): also package the probe as libMobileGLServer.so, the real server as libMobileGLServerReal.so" OFF) -# The PipeInputs strangler (ARCHITECTURE.md 9.2). NOT AN OPTION SINCE P13 W3a: every build pushes, -# the pull build is retired (PLAN-P13 §6). The variable stays ON - and MOBILEGL_PIPE_PUSH=1 stays -# defined for the sources - only until W3b removes the `#if MOBILEGL_PIPE_PUSH` guards themselves; -# the order is what keeps a guard from going "green by skipping" (§4.2). A -DMOBILEGL_PIPE_PUSH=OFF -# (or the OFF that every pre-P13 build tree holds in its cache, the old default) is named and -# dropped rather than honoured: a warning, not an error, so an existing tree reconfigures. +# The PipeInputs strangler (ARCHITECTURE.md 9.2) is finished: since P13 every build pushes, and +# there is neither an option nor a macro for it (W3a removed the option, W3b the `#if` guards and +# the definition). A -DMOBILEGL_PIPE_PUSH=OFF (or the OFF that every pre-P13 build tree holds in its +# cache, the old default) is named and dropped rather than honoured: a warning, not an error, so an +# existing tree reconfigures. The RUNTIME MOBILEGL_PIPE_PUSH environment bitmask is unrelated. if (DEFINED CACHE{MOBILEGL_PIPE_PUSH} AND NOT "$CACHE{MOBILEGL_PIPE_PUSH}") message(WARNING "MobileGL: MOBILEGL_PIPE_PUSH=OFF asks for the pull build, which P13 retired; " "ignored - every build pushes now") endif() unset(MOBILEGL_PIPE_PUSH CACHE) -set(MOBILEGL_PIPE_PUSH ON) option(MOBILEGL_PIPE_VERIFY "Compile SnapshotFromGLContext() and the G4 per-verb shadow comparator; never shipped" OFF) # Track H's old-versus-new arm (ARCHITECTURE.md 9.6) - MOBILEGL_PIPE_LEGACY_MEMOS - retired with the # pull path in P13 W3b: the pre-handle memo arm is no longer compiled anywhere. Named and dropped, @@ -554,32 +552,30 @@ if (MOBILEGL_BUILD_DISAGGREGATED AND set(MOBILEGL_BUILD_DISAGGREGATED_INPROC OFF) endif() -if (MOBILEGL_PIPE_PUSH) - message(STATUS "MobileGL: PipeInputs push ON, appending the MGPipe fill sources") - list(APPEND SOURCE_FILES - MobileGL/MG_Backend/MGPipe/PipeInputs.cpp - MobileGL/MG_Impl/Pipe/PipeFill.cpp - # P2's contract: the chunk table and its subset hash, the in-process applier, and - # the client's {slot, gen} allocator. All three are push-only, which is how the - # pull build gains no symbol from P2 (G1) - a declaration emits nothing. - MobileGL/MG_Pipe/MGPipeRenderStateSpans.cpp - MobileGL/MG_Pipe/PipeApply.cpp - MobileGL/MG_Impl/Pipe/SlotAllocator.cpp - # P4a's contract: the reflection-archive serializer over ProgramArtifacts.h's - # VisitFields tables. Push-only for the same G1 reason as the three above - in - # monolith the archive never crosses (create_shader_state hands the two structs over - # by pointer beside the record), so the codec is live code only in the VERIFY lane, - # where the applier serialises, deserialises and field-compares before storing. - MobileGL/MG_State/GLState/ProgramState/ProgramArtifactsCodec.cpp - # P5's contract (integrator ruling R-17, package c1): the MONOLITH arm of the - # client->wire routing - the thirty-seven adapters that install gMGPipeScreen / - # gMGPipeContext over the MGPipeApply* entry points, and the reply mailbox the four - # acceptance rows answer through. Push-only for the same G1 reason as the five above: - # the two tables are inline variables that are zero in a pull build and nothing there - # can reach a thunk. - MobileGL/MG_Pipe/PipeRoute.cpp - ) -endif() +message(STATUS "MobileGL: PipeInputs push ON, appending the MGPipe fill sources") +list(APPEND SOURCE_FILES + MobileGL/MG_Backend/MGPipe/PipeInputs.cpp + MobileGL/MG_Impl/Pipe/PipeFill.cpp + # P2's contract: the chunk table and its subset hash, the in-process applier, and + # the client's {slot, gen} allocator. All three are push-only, which is how the + # pull build gains no symbol from P2 (G1) - a declaration emits nothing. + MobileGL/MG_Pipe/MGPipeRenderStateSpans.cpp + MobileGL/MG_Pipe/PipeApply.cpp + MobileGL/MG_Impl/Pipe/SlotAllocator.cpp + # P4a's contract: the reflection-archive serializer over ProgramArtifacts.h's + # VisitFields tables. Push-only for the same G1 reason as the three above - in + # monolith the archive never crosses (create_shader_state hands the two structs over + # by pointer beside the record), so the codec is live code only in the VERIFY lane, + # where the applier serialises, deserialises and field-compares before storing. + MobileGL/MG_State/GLState/ProgramState/ProgramArtifactsCodec.cpp + # P5's contract (integrator ruling R-17, package c1): the MONOLITH arm of the + # client->wire routing - the thirty-seven adapters that install gMGPipeScreen / + # gMGPipeContext over the MGPipeApply* entry points, and the reply mailbox the four + # acceptance rows answer through. Push-only for the same G1 reason as the five above: + # the two tables are inline variables that are zero in a pull build and nothing there + # can reach a thunk. + MobileGL/MG_Pipe/PipeRoute.cpp +) if (MOBILEGL_BUILD_DISAGGREGATED) message(STATUS "MobileGL: disaggregated transport ON, appending MG_Remote sources") @@ -746,9 +742,6 @@ if (MOBILEGL_BUILD_DISAGGREGATED) list(APPEND MOBILEGL_COMPILE_DEF -DMOBILEGL_BUILD_DISAGGREGATED=1) endif() -if (MOBILEGL_PIPE_PUSH) - list(APPEND MOBILEGL_COMPILE_DEF -DMOBILEGL_PIPE_PUSH=1) -endif() if (MOBILEGL_PIPE_VERIFY) list(APPEND MOBILEGL_COMPILE_DEF -DMOBILEGL_PIPE_VERIFY=1) endif() diff --git a/MobileGL/MG_IntegrationTest/CMakeLists.txt b/MobileGL/MG_IntegrationTest/CMakeLists.txt index 8a498f7b..08cd6c3e 100644 --- a/MobileGL/MG_IntegrationTest/CMakeLists.txt +++ b/MobileGL/MG_IntegrationTest/CMakeLists.txt @@ -407,10 +407,8 @@ set(MGL_ITEST_CAPABILITY_ENV "") # The lanes themselves are registered in BOTH builds even so. `ctest -L integration-gpu` has to # be name-for-name identical between the pull build and the push build (P2 gate G2), and a lane # that exists in only one of them breaks that comparison for every future package - a much worse -# outcome than four entries that skip. -if (MOBILEGL_PIPE_PUSH) - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_PUSH_BUILD=1") -endif() +# outcome than four entries that skip. P13 W3b: every build pushes, so the marker is unconditional. +list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_PUSH_BUILD=1") # THE THREE MARKERS BELOW ANSWER A QUESTION ABOUT THE SOURCE TREE, so each is only a true # statement about THIS LIBRARY while this build compiles the arm the source implements - and all @@ -508,198 +506,191 @@ function(mgl_itest_probe_for_two_symbols outVar directory symbolRegexA symbolReg endif() endfunction() -if (MOBILEGL_PIPE_PUSH) - # DirectGLES' Track H arm, probed by the subsystem bit it is gated on rather than by - # SlotTables.h existing: the bit is declared in the contract (MG_Pipe/MGPipe.h:77) and the - # backend has to name it to honour MOBILEGL_PIPE_PUSH's default mask, whatever files package C - # spreads the slot tables across. - mgl_itest_probe_for_symbol(MGL_ITEST_ESPRYT_SLOTS - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectGLES" "kMGPipeSubsystemEsprytSlots") - if (MGL_ITEST_ESPRYT_SLOTS) - message(STATUS "Integration tests: DirectGLES is keyed on {slot, gen} (${MGL_ITEST_ESPRYT_SLOTS})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_REKEY_DirectGLES=1") - else() - message(STATUS "Integration tests: no DirectGLES source names kMGPipeSubsystemEsprytSlots - " - "HandleRecycle.Handles will SKIP on it") - endif() - - # The CSO counters' EMITTER. The tracker package may implement the tracker and the cache - # header-only - today it does (MG_Impl/Pipe/{Tracker,CsoCache}.h, no Tracker.cpp) - so what is - # looked for is what the control actually reads: a source emitting the two counters. - mgl_itest_probe_for_symbol(MGL_ITEST_CSO_EMITTER - "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "RenderStateCso(Mints|Binds)") - if (MGL_ITEST_CSO_EMITTER) - message(STATUS "Integration tests: the CSO counters have an emitter (${MGL_ITEST_CSO_EMITTER})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_TRACKER_PRESENT=1") - else() - message(STATUS "Integration tests: no MG_Impl/Pipe source emits RenderStateCsoMints/Binds - " - "CsoContentAddressing will SKIP") - endif() - - # DirectVulkan's Track H arm, and the ABA knob's consumer. Both over the whole backend - # directory: the re-key is subsystem 4's bit wherever package D reads it, and the knob has a - # consumer if ANY DirectVulkan source reverts a guard on it - today two do, in two files. - mgl_itest_probe_for_symbol(MGL_ITEST_MAGMA_REKEY - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectVulkan" "kMGPipeSubsystemMagmaVertexInput") - if (MGL_ITEST_MAGMA_REKEY) - message(STATUS "Integration tests: DirectVulkan's vertex input is keyed on {slot, gen} " - "(${MGL_ITEST_MAGMA_REKEY})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_REKEY_DirectVulkan=1") - else() - message(STATUS "Integration tests: no DirectVulkan source names kMGPipeSubsystemMagmaVertexInput - " - "HandleRecycle.Handles will SKIP on it") - endif() - - # P3a's buffer question, and it is NOT the two above. Bits 5/6 re-keyed each backend's - # VERTEX-INPUT memos; a BUFFER only travels as a handle once the resource_* family does - # (P3a for DirectGLES, P7 for DirectVulkan), and until then a buffer's backend twin is - # still reached from the frontend BufferObject. HandleRecycle's buffer case therefore has - # a marker of its own: reading the P2 one would arm its Handles arm on a tree where - # nothing about a buffer is keyed on a handle. - # - # Probed by MGPipeResourceOps - the op table PipeApply.h declares and a backend registers - - # over each backend's whole directory, for the reason the block above gives: the owning - # package picks its own file layout, and a filename probe would answer "no" forever the - # moment it moved the code. - foreach(mglItestResourceBackend DirectGLES DirectVulkan) - mgl_itest_probe_for_symbol(MGL_ITEST_RESOURCE_OPS - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestResourceBackend}" "MGPipeResourceOps") - if (MGL_ITEST_RESOURCE_OPS) - message(STATUS "Integration tests: ${mglItestResourceBackend} registers a resource op table " - "(${MGL_ITEST_RESOURCE_OPS})") - list(APPEND MGL_ITEST_CAPABILITY_ENV - "MGITEST_HANDLE_REKEY_RESOURCES_${mglItestResourceBackend}=1") - else() - message(STATUS "Integration tests: no ${mglItestResourceBackend} source names " - "MGPipeResourceOps - HandleRecycle.Handles' buffer case will SKIP on it") - endif() - endforeach() - - # The client-side emitter of P3a's map-persistent-roundtrips counter, which is what - # StorageBufferRegrow, LargeArenaAdoption and ResourceSubsystemControl read. Same shape and - # same reason as the CSO emitter probe above: the counter is minted in MG_Impl/Pipe (package - # B), header-only today, so the question is "does any source there emit it", not "does a - # named file exist". Until it does, mpr= is structurally zero and an assertion about it - # would be a statement about nothing. - mgl_itest_probe_for_symbol(MGL_ITEST_RESOURCE_EMITTER - "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "MapPersistentRoundtrips") - if (MGL_ITEST_RESOURCE_EMITTER) - message(STATUS "Integration tests: map-persistent-roundtrips has an emitter " - "(${MGL_ITEST_RESOURCE_EMITTER})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_RESOURCE_EMITTER_PRESENT=1") - else() - message(STATUS "Integration tests: no MG_Impl/Pipe source emits MapPersistentRoundtrips - " - "StorageBufferRegrow's, LargeArenaAdoption's and ResourceSubsystemControl's " - "mpr entries will SKIP") - endif() - - # P4a's THIRD re-key question, per backend, and it is not either of the two above. Bits 5/6 - # re-keyed each backend's VERTEX-INPUT memos and bit 7/8 the BUFFER's; P4a re-keys six OBJECT - # classes - texture, renderbuffer, framebuffer, sampler CSO, sampler view, shader CSO - behind - # four new subsystem bits, and a backend has to NAME one of those constants to honour - # MOBILEGL_PIPE_PUSH's default mask. A P4a case that read either older marker would arm its - # Handles arm on a tree where nothing about a texture is keyed on a handle: green for a re-key - # that does not exist. Probed by the constants rather than by a file, for the reason the block - # above gives - packages D and E choose their own file layout. - foreach(mglItestObjectBackend DirectGLES DirectVulkan) - mgl_itest_probe_for_symbol(MGL_ITEST_OBJECT_REKEY - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestObjectBackend}" - "kMGPipeSubsystem(Framebuffer|TextureResources|Samplers|Programs)") - if (MGL_ITEST_OBJECT_REKEY) - message(STATUS "Integration tests: ${mglItestObjectBackend} is keyed on {slot, gen} for " - "P4a's object families (${MGL_ITEST_OBJECT_REKEY})") - list(APPEND MGL_ITEST_CAPABILITY_ENV - "MGITEST_HANDLE_REKEY_OBJECTS_${mglItestObjectBackend}=1") - else() - message(STATUS "Integration tests: no ${mglItestObjectBackend} source names " - "kMGPipeSubsystem{Framebuffer,TextureResources,Samplers,Programs} - " - "HandleRecycle's six P4a cases will SKIP their Handles arm on it") - endif() - - # ...and whether the ABA knob reaches those kinds THERE. A conjunction over the WHOLE - # backend directory, for the reason mgl_itest_probe_for_two_symbols states: reading the - # knob is not the same as steering P4a's keys with it, so the weaker single-regex evidence - # would turn six always-on entries into a permanent red - but requiring one FILE to carry - # both halves would let a backend satisfy the question and miss the probe, and the six - # controls would then keep asserting the correct pixels with nothing recording that the - # flip was forgotten (F-M5). - mgl_itest_probe_for_two_symbols(MGL_ITEST_OBJECT_ABA - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestObjectBackend}" - "PipeHandleAbaControl" - "kMGPipeSubsystem(Framebuffer|TextureResources|Samplers|Programs)") - if (MGL_ITEST_OBJECT_ABA) - message(STATUS "Integration tests: MOBILEGL_PIPE_HANDLE_ABA_CONTROL steers " - "${mglItestObjectBackend}'s P4a object keys (${MGL_ITEST_OBJECT_ABA})") - list(APPEND MGL_ITEST_CAPABILITY_ENV - "MGITEST_HANDLE_ABA_OBJECTS_${mglItestObjectBackend}=1") - else() - message(STATUS "Integration tests: MobileGL/MG_Backend/${mglItestObjectBackend} does not " - "both read Features.PipeHandleAbaControl and name a P4a subsystem bit " - "somewhere under it - HandleRecycle's six P4a cases will assert the " - "CORRECT pixels on the AbaControl arm and say that it is not a control " - "for them yet") - endif() - endforeach() - - # The client-side emitter of P4a's four suppressor-visible emission counters, which is what - # ObjectSubsystemControl reads. Same shape and same reason as the CSO and map-persistent - # emitter probes above: the emitters are minted in MG_Impl/Pipe (packages B and C), header-only - # by design (D-P), so the question is "does any source there emit it", not "does a named file - # exist". Until one does, every counter in the emit[] bracket is structurally zero in BOTH arms - # of the A/B and an assertion about their difference would be a statement about nothing. - mgl_itest_probe_for_symbol(MGL_ITEST_OBJECT_EMITTER - "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "FramebufferEmissions") - if (MGL_ITEST_OBJECT_EMITTER) - message(STATUS "Integration tests: P4a's object emissions have an emitter " - "(${MGL_ITEST_OBJECT_EMITTER})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_OBJECT_EMITTER_PRESENT=1") - else() - message(STATUS "Integration tests: no MG_Impl/Pipe source emits FramebufferEmissions - " - "ObjectSubsystemControl's emission case will SKIP") - endif() - - # ...and the CLIENT half of the texture-upload shape, separately, because it is a different - # question with a different owner's file behind it (review F-m7). ctu= is emitted by PipeStats - # in EVERY push build whether or not anything increments it, so "the counter read zero" and - # "no client emitter exists" are the same number and TextureUploadShape cannot tell them apart - # from the summary line alone. An emitter that STOPPED emitting reads exactly like no emitter - # at all in that field, and the two-sided assertion the scenario exists for would pass while - # comparing nothing. This probe is what separates them. - # - # THAT EMITTER HAS LANDED (P3b/P4b wave 2-D corrects this comment's tense): - # MG_Impl/Pipe/TextureEmit.h's EmitOneLevel increments - # CallClass::ClientTextureUploadEmissions on every piece it emits, so the probe hits and the - # else() arm below is unreachable on this tree. It is KEPT rather than deleted because it is - # what makes the arming decision falsifiable in both directions - a probe that cannot report - # "absent" cannot be shown to be looking for the right symbol. - mgl_itest_probe_for_symbol(MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER - "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "ClientTextureUploadEmissions") - if (MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER) - message(STATUS "Integration tests: the client texture-upload counter has an emitter " - "(${MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER}) - TextureUploadShape's " - "two-sided assertion is live") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_CLIENT_TEXTURE_UPLOAD_EMITTER_PRESENT=1") - else() - message(STATUS "Integration tests: no MG_Impl/Pipe source emits " - "ClientTextureUploadEmissions - TextureUploadShape records the SERVER shape " - "only and asserts that ctu= is zero") - endif() - - mgl_itest_probe_for_symbol(MGL_ITEST_MAGMA_ABA - "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectVulkan" "PipeHandleAbaControl") - if (MGL_ITEST_MAGMA_ABA) - message(STATUS "Integration tests: MOBILEGL_PIPE_HANDLE_ABA_CONTROL has a consumer " - "(${MGL_ITEST_MAGMA_ABA})") - list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_ABA_IMPLEMENTED=1") - else() - message(STATUS "Integration tests: no DirectVulkan source names PipeHandleAbaControl - " - "HandleRecycle.AbaControl will SKIP") - endif() +# DirectGLES' Track H arm, probed by the subsystem bit it is gated on rather than by +# SlotTables.h existing: the bit is declared in the contract (MG_Pipe/MGPipe.h:77) and the +# backend has to name it to honour MOBILEGL_PIPE_PUSH's default mask, whatever files package C +# spreads the slot tables across. +mgl_itest_probe_for_symbol(MGL_ITEST_ESPRYT_SLOTS + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectGLES" "kMGPipeSubsystemEsprytSlots") +if (MGL_ITEST_ESPRYT_SLOTS) + message(STATUS "Integration tests: DirectGLES is keyed on {slot, gen} (${MGL_ITEST_ESPRYT_SLOTS})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_REKEY_DirectGLES=1") else() - message(STATUS "Integration tests: pull build - HandleRecycle.{Handles,AbaControl}, " - "CsoContentAddressing, ResourceSubsystemControl, ObjectSubsystemControl and " - "TextureUploadShape stay registered (G2) and SKIP: every arm they assert is " - "compiled only under MOBILEGL_PIPE_PUSH") + message(STATUS "Integration tests: no DirectGLES source names kMGPipeSubsystemEsprytSlots - " + "HandleRecycle.Handles will SKIP on it") +endif() + +# The CSO counters' EMITTER. The tracker package may implement the tracker and the cache +# header-only - today it does (MG_Impl/Pipe/{Tracker,CsoCache}.h, no Tracker.cpp) - so what is +# looked for is what the control actually reads: a source emitting the two counters. +mgl_itest_probe_for_symbol(MGL_ITEST_CSO_EMITTER + "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "RenderStateCso(Mints|Binds)") +if (MGL_ITEST_CSO_EMITTER) + message(STATUS "Integration tests: the CSO counters have an emitter (${MGL_ITEST_CSO_EMITTER})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_TRACKER_PRESENT=1") +else() + message(STATUS "Integration tests: no MG_Impl/Pipe source emits RenderStateCsoMints/Binds - " + "CsoContentAddressing will SKIP") +endif() + +# DirectVulkan's Track H arm, and the ABA knob's consumer. Both over the whole backend +# directory: the re-key is subsystem 4's bit wherever package D reads it, and the knob has a +# consumer if ANY DirectVulkan source reverts a guard on it - today two do, in two files. +mgl_itest_probe_for_symbol(MGL_ITEST_MAGMA_REKEY + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectVulkan" "kMGPipeSubsystemMagmaVertexInput") +if (MGL_ITEST_MAGMA_REKEY) + message(STATUS "Integration tests: DirectVulkan's vertex input is keyed on {slot, gen} " + "(${MGL_ITEST_MAGMA_REKEY})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_REKEY_DirectVulkan=1") +else() + message(STATUS "Integration tests: no DirectVulkan source names kMGPipeSubsystemMagmaVertexInput - " + "HandleRecycle.Handles will SKIP on it") +endif() + +# P3a's buffer question, and it is NOT the two above. Bits 5/6 re-keyed each backend's +# VERTEX-INPUT memos; a BUFFER only travels as a handle once the resource_* family does +# (P3a for DirectGLES, P7 for DirectVulkan), and until then a buffer's backend twin is +# still reached from the frontend BufferObject. HandleRecycle's buffer case therefore has +# a marker of its own: reading the P2 one would arm its Handles arm on a tree where +# nothing about a buffer is keyed on a handle. +# +# Probed by MGPipeResourceOps - the op table PipeApply.h declares and a backend registers - +# over each backend's whole directory, for the reason the block above gives: the owning +# package picks its own file layout, and a filename probe would answer "no" forever the +# moment it moved the code. +foreach(mglItestResourceBackend DirectGLES DirectVulkan) + mgl_itest_probe_for_symbol(MGL_ITEST_RESOURCE_OPS + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestResourceBackend}" "MGPipeResourceOps") + if (MGL_ITEST_RESOURCE_OPS) + message(STATUS "Integration tests: ${mglItestResourceBackend} registers a resource op table " + "(${MGL_ITEST_RESOURCE_OPS})") + list(APPEND MGL_ITEST_CAPABILITY_ENV + "MGITEST_HANDLE_REKEY_RESOURCES_${mglItestResourceBackend}=1") + else() + message(STATUS "Integration tests: no ${mglItestResourceBackend} source names " + "MGPipeResourceOps - HandleRecycle.Handles' buffer case will SKIP on it") + endif() +endforeach() + +# The client-side emitter of P3a's map-persistent-roundtrips counter, which is what +# StorageBufferRegrow, LargeArenaAdoption and ResourceSubsystemControl read. Same shape and +# same reason as the CSO emitter probe above: the counter is minted in MG_Impl/Pipe (package +# B), header-only today, so the question is "does any source there emit it", not "does a +# named file exist". Until it does, mpr= is structurally zero and an assertion about it +# would be a statement about nothing. +mgl_itest_probe_for_symbol(MGL_ITEST_RESOURCE_EMITTER + "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "MapPersistentRoundtrips") +if (MGL_ITEST_RESOURCE_EMITTER) + message(STATUS "Integration tests: map-persistent-roundtrips has an emitter " + "(${MGL_ITEST_RESOURCE_EMITTER})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_RESOURCE_EMITTER_PRESENT=1") +else() + message(STATUS "Integration tests: no MG_Impl/Pipe source emits MapPersistentRoundtrips - " + "StorageBufferRegrow's, LargeArenaAdoption's and ResourceSubsystemControl's " + "mpr entries will SKIP") +endif() + +# P4a's THIRD re-key question, per backend, and it is not either of the two above. Bits 5/6 +# re-keyed each backend's VERTEX-INPUT memos and bit 7/8 the BUFFER's; P4a re-keys six OBJECT +# classes - texture, renderbuffer, framebuffer, sampler CSO, sampler view, shader CSO - behind +# four new subsystem bits, and a backend has to NAME one of those constants to honour +# MOBILEGL_PIPE_PUSH's default mask. A P4a case that read either older marker would arm its +# Handles arm on a tree where nothing about a texture is keyed on a handle: green for a re-key +# that does not exist. Probed by the constants rather than by a file, for the reason the block +# above gives - packages D and E choose their own file layout. +foreach(mglItestObjectBackend DirectGLES DirectVulkan) + mgl_itest_probe_for_symbol(MGL_ITEST_OBJECT_REKEY + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestObjectBackend}" + "kMGPipeSubsystem(Framebuffer|TextureResources|Samplers|Programs)") + if (MGL_ITEST_OBJECT_REKEY) + message(STATUS "Integration tests: ${mglItestObjectBackend} is keyed on {slot, gen} for " + "P4a's object families (${MGL_ITEST_OBJECT_REKEY})") + list(APPEND MGL_ITEST_CAPABILITY_ENV + "MGITEST_HANDLE_REKEY_OBJECTS_${mglItestObjectBackend}=1") + else() + message(STATUS "Integration tests: no ${mglItestObjectBackend} source names " + "kMGPipeSubsystem{Framebuffer,TextureResources,Samplers,Programs} - " + "HandleRecycle's six P4a cases will SKIP their Handles arm on it") + endif() + + # ...and whether the ABA knob reaches those kinds THERE. A conjunction over the WHOLE + # backend directory, for the reason mgl_itest_probe_for_two_symbols states: reading the + # knob is not the same as steering P4a's keys with it, so the weaker single-regex evidence + # would turn six always-on entries into a permanent red - but requiring one FILE to carry + # both halves would let a backend satisfy the question and miss the probe, and the six + # controls would then keep asserting the correct pixels with nothing recording that the + # flip was forgotten (F-M5). + mgl_itest_probe_for_two_symbols(MGL_ITEST_OBJECT_ABA + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/${mglItestObjectBackend}" + "PipeHandleAbaControl" + "kMGPipeSubsystem(Framebuffer|TextureResources|Samplers|Programs)") + if (MGL_ITEST_OBJECT_ABA) + message(STATUS "Integration tests: MOBILEGL_PIPE_HANDLE_ABA_CONTROL steers " + "${mglItestObjectBackend}'s P4a object keys (${MGL_ITEST_OBJECT_ABA})") + list(APPEND MGL_ITEST_CAPABILITY_ENV + "MGITEST_HANDLE_ABA_OBJECTS_${mglItestObjectBackend}=1") + else() + message(STATUS "Integration tests: MobileGL/MG_Backend/${mglItestObjectBackend} does not " + "both read Features.PipeHandleAbaControl and name a P4a subsystem bit " + "somewhere under it - HandleRecycle's six P4a cases will assert the " + "CORRECT pixels on the AbaControl arm and say that it is not a control " + "for them yet") + endif() +endforeach() + +# The client-side emitter of P4a's four suppressor-visible emission counters, which is what +# ObjectSubsystemControl reads. Same shape and same reason as the CSO and map-persistent +# emitter probes above: the emitters are minted in MG_Impl/Pipe (packages B and C), header-only +# by design (D-P), so the question is "does any source there emit it", not "does a named file +# exist". Until one does, every counter in the emit[] bracket is structurally zero in BOTH arms +# of the A/B and an assertion about their difference would be a statement about nothing. +mgl_itest_probe_for_symbol(MGL_ITEST_OBJECT_EMITTER + "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "FramebufferEmissions") +if (MGL_ITEST_OBJECT_EMITTER) + message(STATUS "Integration tests: P4a's object emissions have an emitter " + "(${MGL_ITEST_OBJECT_EMITTER})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_OBJECT_EMITTER_PRESENT=1") +else() + message(STATUS "Integration tests: no MG_Impl/Pipe source emits FramebufferEmissions - " + "ObjectSubsystemControl's emission case will SKIP") +endif() + +# ...and the CLIENT half of the texture-upload shape, separately, because it is a different +# question with a different owner's file behind it (review F-m7). ctu= is emitted by PipeStats +# in EVERY push build whether or not anything increments it, so "the counter read zero" and +# "no client emitter exists" are the same number and TextureUploadShape cannot tell them apart +# from the summary line alone. An emitter that STOPPED emitting reads exactly like no emitter +# at all in that field, and the two-sided assertion the scenario exists for would pass while +# comparing nothing. This probe is what separates them. +# +# THAT EMITTER HAS LANDED (P3b/P4b wave 2-D corrects this comment's tense): +# MG_Impl/Pipe/TextureEmit.h's EmitOneLevel increments +# CallClass::ClientTextureUploadEmissions on every piece it emits, so the probe hits and the +# else() arm below is unreachable on this tree. It is KEPT rather than deleted because it is +# what makes the arming decision falsifiable in both directions - a probe that cannot report +# "absent" cannot be shown to be looking for the right symbol. +mgl_itest_probe_for_symbol(MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER + "${MGL_ITEST_ROOT}/MobileGL/MG_Impl/Pipe" "ClientTextureUploadEmissions") +if (MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER) + message(STATUS "Integration tests: the client texture-upload counter has an emitter " + "(${MGL_ITEST_CLIENT_TEXTURE_UPLOAD_EMITTER}) - TextureUploadShape's " + "two-sided assertion is live") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_PIPE_CLIENT_TEXTURE_UPLOAD_EMITTER_PRESENT=1") +else() + message(STATUS "Integration tests: no MG_Impl/Pipe source emits " + "ClientTextureUploadEmissions - TextureUploadShape records the SERVER shape " + "only and asserts that ctu= is zero") +endif() + +mgl_itest_probe_for_symbol(MGL_ITEST_MAGMA_ABA + "${MGL_ITEST_ROOT}/MobileGL/MG_Backend/DirectVulkan" "PipeHandleAbaControl") +if (MGL_ITEST_MAGMA_ABA) + message(STATUS "Integration tests: MOBILEGL_PIPE_HANDLE_ABA_CONTROL has a consumer " + "(${MGL_ITEST_MAGMA_ABA})") + list(APPEND MGL_ITEST_CAPABILITY_ENV "MGITEST_HANDLE_ABA_IMPLEMENTED=1") +else() + message(STATUS "Integration tests: no DirectVulkan source names PipeHandleAbaControl - " + "HandleRecycle.AbaControl will SKIP") endif() mgl_itest_join_environment(MGL_ITEST_GLES_ENVIRONMENT @@ -1243,13 +1234,12 @@ gtest_discover_tests(MobileGLIntegrationTest # OBJECT handles it is now also about stayed switched off - a lane that still passes and no longer # measures the key that ships. Each phase's constant survives as the NEXT phase's A/B control, which # is what ResourceSubsystemControl's Off lane uses 0x7f for and ObjectSubsystemControl's uses 0x1ff. -if (MOBILEGL_PIPE_PUSH) - set(MGL_ITEST_HANDLES_ARM_KNOBS "MOBILEGL_PIPE_LEGACY_MEMOS=0" "MOBILEGL_PIPE_PUSH=0x1fff") - set(MGL_ITEST_ABA_ARM_KNOBS "MOBILEGL_PIPE_HANDLE_ABA_CONTROL=1") -else() - set(MGL_ITEST_HANDLES_ARM_KNOBS "") - set(MGL_ITEST_ABA_ARM_KNOBS "") -endif() +# P13 W3b (ID-P13-3): the pre-handle arm is no longer compiled, so the Handles arm needs neither +# MOBILEGL_PIPE_LEGACY_MEMOS=0 nor a mask that switches anything off: it runs the default mask. +# The Legacy and AbaControl lanes (MOBILEGL_PIPE_PUSH=0, the pre-handle arm) went with that arm; +# AbaControlHandles - the ABA control against the handle arm that ships - stays. +set(MGL_ITEST_HANDLES_ARM_KNOBS "") +set(MGL_ITEST_ABA_ARM_KNOBS "MOBILEGL_PIPE_HANDLE_ABA_CONTROL=1") mgl_itest_join_environment(MGL_ITEST_GLES_HANDLE_HANDLES_ENVIRONMENT "MOBILEGL_TRANSPORT=monolith" @@ -1259,19 +1249,6 @@ mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_HANDLES_ENVIRONMENT "MOBILEGL_TRANSPORT=monolith" "MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=handles" ${MGL_ITEST_HANDLES_ARM_KNOBS} ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) -mgl_itest_join_environment(MGL_ITEST_GLES_HANDLE_LEGACY_ENVIRONMENT - "MOBILEGL_TRANSPORT=monolith" - "MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_HANDLE_ARM=legacy" "MOBILEGL_PIPE_PUSH=0" - ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV}) -mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_LEGACY_ENVIRONMENT - "MOBILEGL_TRANSPORT=monolith" - "MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=legacy" "MOBILEGL_PIPE_PUSH=0" - ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) -mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_ABA_ENVIRONMENT - "MOBILEGL_TRANSPORT=monolith" - "MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=aba" "MOBILEGL_PIPE_PUSH=0" - ${MGL_ITEST_ABA_ARM_KNOBS} - ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_ABA_HANDLES_ENVIRONMENT "MOBILEGL_TRANSPORT=monolith" "MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=aba" @@ -1296,33 +1273,6 @@ gtest_discover_tests(MobileGLIntegrationTest TIMEOUT ${MGL_ITEST_TIMEOUT} ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_HANDLES_ENVIRONMENT}" ) -gtest_discover_tests(MobileGLIntegrationTest - TEST_PREFIX "DirectGLES.HandleRecycle.Legacy." - TEST_FILTER "HandleRecycleScenario.*" - DISCOVERY_TIMEOUT 30 - PROPERTIES - LABELS "integration-gpu\;integration-monolith-control" - TIMEOUT ${MGL_ITEST_TIMEOUT} - ENVIRONMENT "${MGL_ITEST_GLES_HANDLE_LEGACY_ENVIRONMENT}" -) -gtest_discover_tests(MobileGLIntegrationTest - TEST_PREFIX "DirectVulkan.HandleRecycle.Legacy." - TEST_FILTER "HandleRecycleScenario.*" - DISCOVERY_TIMEOUT 30 - PROPERTIES - LABELS "integration-gpu\;integration-monolith-control" - TIMEOUT ${MGL_ITEST_TIMEOUT} - ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_LEGACY_ENVIRONMENT}" -) -gtest_discover_tests(MobileGLIntegrationTest - TEST_PREFIX "DirectVulkan.HandleRecycle.AbaControl." - TEST_FILTER "HandleRecycleScenario.*" - DISCOVERY_TIMEOUT 30 - PROPERTIES - LABELS "integration-gpu\;integration-monolith-control" - TIMEOUT ${MGL_ITEST_TIMEOUT} - ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_ABA_ENVIRONMENT}" -) gtest_discover_tests(MobileGLIntegrationTest TEST_PREFIX "DirectVulkan.HandleRecycle.AbaControlHandles." TEST_FILTER "HandleRecycleScenario.*" diff --git a/MobileGL/MG_Pipe/PipeInputsSwitch.h b/MobileGL/MG_Pipe/PipeInputsSwitch.h deleted file mode 100644 index 2abd0552..00000000 --- a/MobileGL/MG_Pipe/PipeInputsSwitch.h +++ /dev/null @@ -1,21 +0,0 @@ -// MobileGL - MobileGL/MG_Pipe/PipeInputsSwitch.h -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header - -#pragma once -#ifndef MOBILEGL_MG_PIPE_INPUTS_SWITCH_H // belt and braces: reachable as and <..> (CMakeLists.txt:531,535) -#define MOBILEGL_MG_PIPE_INPUTS_SWITCH_H -// The strangler switch (ARCHITECTURE.md 9.2). Every backend read of frontend state is spelled -// MGB_CTX->Accessor(...). Pull arm: the live GLContext, so the pull build is the tree before P1 -// token for token. Push arm: the PipeInputs block the frontend fills at every verb boundary. -// The pull arm is the ONLY place under MobileGL/ outside MG_State and MG_Impl that may spell -// pGLContext; purity gate C greps MG_Backend/ for that token. -#include -#define MGB_CTX (&::MobileGL::MG_Pipe::gPipeInputs) -#define MGB_CTX_LIVE (::MobileGL::MG_Pipe::gPipeInputs.IsLive()) -#define MGB_CTX_IDENTITY (::MobileGL::MG_Pipe::gPipeInputs.ContextIdentity()) -#endif