Files
MobileGL/MobileGL/MG_IntegrationTest/CMakeLists.txt
T

4835 lines
308 KiB
CMake

cmake_minimum_required(VERSION 3.24)
# MobileGL headless GPU integration tests.
#
# These are not unit tests: each scenario brings up a real EGL context on a
# pbuffer, renders real frames through a real backend and asserts on
# glReadPixels output. They need a GPU, so the module is OFF by default
# (MOBILEGL_BUILD_INTEGRATION_TEST) and every scenario skips cleanly - never
# fails, never hangs - on a machine without one. "Cleanly" is not a hope: the
# harness runs the whole bring-up in a forked child first, because MobileGL
# ABORTS rather than returning an error on an unusable platform (HeadlessGL.cpp).
#
# A clean skip is also indistinguishable from a pass, so set
# MOBILEGL_ITEST_REQUIRE_GPU wherever the machine is supposed to have a GPU.
#
# Backend selection is latched at initialization from MOBILEGL_BACKEND_TYPE, so
# one process is one backend: the same binary is registered twice, once per
# backend, under the `integration-gpu` label.
message(STATUS "Generating build files for MobileGL Integration Test...")
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(MGL_ITEST_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..)
# Desktop links the static implementation directly. Android runs the same
# executable from adb shell and links the shipping shared library instead.
if (ANDROID)
set(MGL_ITEST_MOBILEGL_TARGET MobileGL)
elseif (TARGET MobileGL_s)
set(MGL_ITEST_MOBILEGL_TARGET MobileGL_s)
else()
message(STATUS "No MobileGL library target is available; skipping the integration test module")
return()
endif()
# MG_Test already pulls googletest in when MOBILEGL_BUILD_TEST is ON. Stand on
# our own feet when it is not, so this module can be built by itself.
if (NOT TARGET GTest::gtest)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.17.0
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()
add_executable(MobileGLIntegrationTest
Main.cpp
Harness/HeadlessGL.cpp
Harness/BackendCapsPeek.cpp
Harness/PipeSlotPeek.cpp
Harness/PipeApplyPeek.cpp
Harness/P4aSeamPeek.cpp
Harness/P4aFinalFixPeek.cpp
Harness/PersistentMapPeek.cpp
Harness/SplitRuntimePeek.cpp
# ---- P3b/P4b wave 2-D package D2 (own block; D1 edits this file elsewhere) --------------
# The client texture emitter's own counters, for TextureViewAliasScenario's half of the
# owner-keyed emission cursor gate: a drain that ran and emitted nothing is invisible in
# pixels and is exactly the two-cursor regression's signature.
Harness/TextureEmitPeek.cpp
Scenarios/OrientationScenario.cpp
Scenarios/CrossFrameBufferScenario.cpp
Scenarios/ResidentIndexScenario.cpp
Scenarios/MultiDrawScenario.cpp
Scenarios/IndexedDrawFamilyScenario.cpp
Scenarios/SyncWireScenario.cpp
Scenarios/DrawParametersScenario.cpp
Scenarios/AsyncCompileScenario.cpp
Scenarios/XfbAfterClipDistanceScenario.cpp
Scenarios/UnwrittenPositionOutputScenario.cpp
Scenarios/SampleMaskScopeScenario.cpp
Scenarios/SampledSetStalenessScenario.cpp
Scenarios/ThreeChannelAttachmentScenario.cpp
Scenarios/SnormAttachmentScenario.cpp
Scenarios/MonolithAttachmentClearScenario.cpp
Scenarios/PipelineFailureScenario.cpp
Scenarios/AdvertisedLimitsScenario.cpp
Scenarios/PixelStoreSweepScenario.cpp
# P7 gate 5 (g5-readback): readbacks larger than one reply slot. Ordinary GL cases, so the
# monolith arms run them too - that is the parity half of the split registrations below.
Scenarios/BandedReadbackScenario.cpp
# P9 (W1): reads into a pixel pack buffer answered by nothing. Ordinary GL cases too, plus
# one wire case that skips where there is no wire.
Scenarios/PackBufferReadbackScenario.cpp
# P10 (A): fence polls answered from the server's reports.
Scenarios/FencePollScenario.cpp
Scenarios/PrimitiveRestartScenario.cpp
Scenarios/FragCoordOriginScenario.cpp
Scenarios/ClientVertexArrayScenario.cpp
Scenarios/ClearThenReadPixelsScenario.cpp
Scenarios/SampleVariablesScenario.cpp
Scenarios/DepthStencilReadbackScenario.cpp
Scenarios/DepthStencilReadbackMatrixScenario.cpp
Scenarios/DepthStencilReadbackAttachmentShapeScenario.cpp
Scenarios/ClipDistanceScenario.cpp
Scenarios/ViewportArrayScenario.cpp
Scenarios/SsboArrayLengthScenario.cpp
Scenarios/DoublePrecisionScenario.cpp
Scenarios/UniformInitializerScenario.cpp
Scenarios/SwizzleAccessRoutineScenario.cpp
Scenarios/IterationRPFirstReductionScenario.cpp
Scenarios/IterationRPProgram203Scenario.cpp
Scenarios/IterationRPScratchFixScenario.cpp
Scenarios/ProgramPipelineScenario.cpp
Scenarios/ImageLoadStoreSsoScenario.cpp
Scenarios/ImageTargetKindScenario.cpp
Scenarios/ImageFormatQualifierScenario.cpp
Scenarios/TextureRemintPullScenario.cpp
Scenarios/NonCoreImageFormatScenario.cpp
Scenarios/ImageSizeAfterRespecScenario.cpp
Scenarios/EmptyTextureLevelScenario.cpp
Scenarios/ImageBindableRemintScenario.cpp
Scenarios/PartialUploadOverGpuContentScenario.cpp
Scenarios/SsboDeclarationFormScenario.cpp
Scenarios/Glsl420DeclarationScenario.cpp
Scenarios/IoBlockNameCollisionScenario.cpp
Scenarios/UnlocatedIoBlockScenario.cpp
Scenarios/TessellationDrawModeScenario.cpp
Scenarios/GeometryDrawModeScenario.cpp
Scenarios/PostLinkAttachScenario.cpp
Scenarios/FormatlessImageBakeScenario.cpp
Scenarios/FragmentOutputArrayIndexScenario.cpp
Scenarios/BufferTextureScenario.cpp
Scenarios/VertexAttribBindingScenario.cpp
Scenarios/XfbCaptureBufferReuseScenario.cpp
Scenarios/XfbPrimitiveQueryScenario.cpp
Scenarios/PrimitivesGeneratedNoXfbScenario.cpp
Scenarios/XfbRepeatedCaptureScenario.cpp
Scenarios/TessellationXfbCaptureScenario.cpp
Scenarios/PointSizeDemotionScenario.cpp
Scenarios/VertexArrayEnableDisableScenario.cpp
Scenarios/CopyImageLevelRangeScenario.cpp
Scenarios/CopyImageLayeredScenario.cpp
Scenarios/CopyImagePacked16Scenario.cpp
Scenarios/TextureViewScenario.cpp
# P3b/P4b wave 2-D package D2: the verification half of the owner-keyed emission cursor.
Scenarios/TextureViewAliasScenario.cpp
Scenarios/PackedWordReadbackScenario.cpp
Scenarios/LayeredAttachmentBarrierScenario.cpp
Scenarios/LayeredAttachmentShapeScenario.cpp
Scenarios/LayeredTextureReadbackScenario.cpp
Scenarios/AtomicCounterScenario.cpp
Scenarios/LargeArenaAdoptionScenario.cpp
Scenarios/SsboArrayDynamicIndexScenario.cpp
Scenarios/StorageBufferRegrowScenario.cpp
Scenarios/SpirvShaderBinaryScenario.cpp
Scenarios/RelinkStageSetScenario.cpp
Scenarios/GuiBatchScenario.cpp
Scenarios/UnboundImageDescriptorScenario.cpp
# P7 gate 5: an image unit naming a (level, layer) its texture lacks (GL 4.6 core 8.26).
Scenarios/InvalidImageUnitScenario.cpp
Scenarios/IntegerBorderColorScenario.cpp
Scenarios/ClearTexImageUndefinedLevelZeroScenario.cpp
Scenarios/RenderbufferBlendFormatScenario.cpp
Scenarios/DualSourceBlendScenario.cpp
Scenarios/PipeVerifyArmingScenario.cpp
Scenarios/PoisonOmissionScenario.cpp
Scenarios/HandleRecycleScenario.cpp
Scenarios/CsoContentAddressingScenario.cpp
Scenarios/ResourceSubsystemControlScenario.cpp
Scenarios/TextureParamsWithoutASamplerViewScenario.cpp
Scenarios/TextureUploadShapeScenario.cpp
Scenarios/ObjectSubsystemControlScenario.cpp
Scenarios/P4aSeamAuditScenario.cpp
Scenarios/P4aFinalFixScenario.cpp
# P5's two new scenarios, targets B and C of the reduced path (BRIEF-P5 4). Both are
# ORDINARY GL scenarios that run in every lane; the DirectGLES.Split. entries further down
# run the same cases with MOBILEGL_TRANSPORT=inproc.
Scenarios/TriangleScenario.cpp
Scenarios/PersistentCoherentMapScenario.cpp
Scenarios/DefaultFramebufferAcrossSwapScenario.cpp
)
target_include_directories(MobileGLIntegrationTest PRIVATE
${MGL_ITEST_ROOT}/include
${MGL_ITEST_ROOT}/MobileGL
)
# gtest, not gtest_main: Main.cpp installs the harness banner itself.
target_link_libraries(MobileGLIntegrationTest PRIVATE
GTest::gtest
${MGL_ITEST_MOBILEGL_TARGET}
)
if (ANDROID)
find_library(MGL_ITEST_ANDROID_LIBRARY android REQUIRED)
find_library(MGL_ITEST_LOG_LIBRARY log REQUIRED)
find_library(MGL_ITEST_MEDIANDK_LIBRARY mediandk REQUIRED)
target_link_libraries(MobileGLIntegrationTest PRIVATE
${MGL_ITEST_ANDROID_LIBRARY}
${MGL_ITEST_LOG_LIBRARY}
${MGL_ITEST_MEDIANDK_LIBRARY}
)
endif()
if (MSVC)
# Same reason as MG_Test/Backend/DirectVulkan: the GLES headers declare gl*
# as dllimport on Windows, so the in-library GL entry-point definitions only
# resolve if the whole static library is part of the link.
target_link_options(MobileGLIntegrationTest PRIVATE /WHOLEARCHIVE:MobileGL_s)
endif()
target_compile_definitions(MobileGLIntegrationTest PRIVATE -DNOMINMAX)
if (ANDROID)
return()
endif()
# --- ctest wiring --------------------------------------------------------
# A bare libEGL on a glvnd box resolves to whatever vendor comes first, which is
# usually Mesa/llvmpipe - a software rasteriser silently replacing the GPU under
# a GPU test. Pin the vendor/ICD json the same way MG_Benchmark's
# run_driver_bench.sh does.
#
# Leaving these empty is not a neutral default, it is the failure mode: an
# unpinned libEGL lands on llvmpipe and the suite goes green having tested a
# software rasteriser. So they are DETECTED here rather than defaulted to empty,
# and an empty result is a loud warning.
#
# mgl_itest_find_driver_json(<outVar> <description> <glob> [<glob>...])
# Picks the first json a real hardware vendor owns, in preference order, and
# never picks a software rasteriser (llvmpipe / lavapipe / swrast) - landing on
# one of those silently is the exact accident this pinning exists to prevent.
function(mgl_itest_find_driver_json outVar)
set(candidates "")
foreach(pattern IN LISTS ARGN)
file(GLOB matches "${pattern}")
list(APPEND candidates ${matches})
endforeach()
list(SORT candidates)
# Vendors ship an i686 json beside the x86_64 one and it sorts first. Pinning
# the wrong word size is worse than not pinning at all - the loader finds no
# driver and the whole suite skips - so drop the mismatched ones outright.
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
list(FILTER candidates EXCLUDE REGEX "i686|i386")
else()
list(FILTER candidates EXCLUDE REGEX "x86_64|aarch64")
endif()
set(software "")
foreach(vendor IN ITEMS nvidia amdgpu amd radeon intel_hasvk intel broadcom freedreno panfrost)
foreach(candidate IN LISTS candidates)
get_filename_component(leaf "${candidate}" NAME)
string(TOLOWER "${leaf}" leaf)
if (leaf MATCHES "${vendor}")
set(${outVar} "${candidate}" PARENT_SCOPE)
return()
endif()
endforeach()
endforeach()
# Nothing recognised as hardware. Report the first non-software entry if there
# is one; otherwise report nothing, so the warning below fires.
foreach(candidate IN LISTS candidates)
get_filename_component(leaf "${candidate}" NAME)
string(TOLOWER "${leaf}" leaf)
if (NOT leaf MATCHES "lvp|llvmpipe|lavapipe|swrast|softpipe")
set(${outVar} "${candidate}" PARENT_SCOPE)
return()
endif()
set(software "${candidate}")
endforeach()
set(${outVar} "" PARENT_SCOPE)
endfunction()
set(MGL_ITEST_DETECTED_EGL_VENDOR "")
set(MGL_ITEST_DETECTED_VK_ICD "")
if (UNIX AND NOT APPLE AND NOT ANDROID)
mgl_itest_find_driver_json(MGL_ITEST_DETECTED_EGL_VENDOR
"/usr/share/glvnd/egl_vendor.d/*.json"
"/etc/glvnd/egl_vendor.d/*.json")
mgl_itest_find_driver_json(MGL_ITEST_DETECTED_VK_ICD
"/usr/share/vulkan/icd.d/*.json"
"/etc/vulkan/icd.d/*.json")
endif()
set(MOBILEGL_ITEST_EGL_VENDOR "${MGL_ITEST_DETECTED_EGL_VENDOR}" CACHE FILEPATH
"glvnd EGL vendor json to pin for the integration tests (empty: leave the loader alone)")
set(MOBILEGL_ITEST_VK_ICD "${MGL_ITEST_DETECTED_VK_ICD}" CACHE FILEPATH
"Vulkan ICD json to pin for the DirectVulkan integration tests (empty: leave the loader alone)")
if (MOBILEGL_ITEST_EGL_VENDOR)
message(STATUS "Integration tests: pinning EGL vendor ${MOBILEGL_ITEST_EGL_VENDOR}")
else()
message(WARNING
"Integration tests: no EGL vendor json found or configured (MOBILEGL_ITEST_EGL_VENDOR is empty). "
"An unpinned libEGL on a glvnd system resolves to whichever vendor comes first, which is usually "
"Mesa/llvmpipe - the scenarios would then go green against a software rasteriser instead of the GPU. "
"Set -DMOBILEGL_ITEST_EGL_VENDOR=/usr/share/glvnd/egl_vendor.d/<vendor>.json.")
endif()
if (MOBILEGL_ITEST_VK_ICD)
message(STATUS "Integration tests: pinning Vulkan ICD ${MOBILEGL_ITEST_VK_ICD}")
else()
message(WARNING
"Integration tests: no Vulkan ICD json found or configured (MOBILEGL_ITEST_VK_ICD is empty). "
"DirectVulkan would then load whichever ICD the loader enumerates first, quite possibly lavapipe. "
"Set -DMOBILEGL_ITEST_VK_ICD=/usr/share/vulkan/icd.d/<vendor>.json.")
endif()
# Turns "no usable GPU" from a clean skip into a failure - see ScenarioFixture.h.
# Without it the integration-gpu label is unfalsifiable: a run that skipped every
# scenario and a run that passed every scenario are the same green in ctest.
option(MOBILEGL_ITEST_REQUIRE_GPU
"Fail (rather than skip) the integration scenarios when the headless harness is unusable" OFF)
# No EGL_PLATFORM knob here on purpose. The harness pins EGL_PLATFORM=surfaceless
# itself before its first EGL call (HeadlessGL.cpp, EnsureHeadlessPlatform) so a
# developer's machine and a CI runner take the SAME path whether or not a window
# system happens to be running. This used to inject "x11", which is how the lane
# came up green on a workstation with WSLg and died on a runner with no X server.
#
# A build-system knob would not just be redundant, it would be a trap: `set(...
# CACHE ...)` does not rewrite an existing cache, so every build directory
# configured before this change would keep injecting EGL_PLATFORM=x11 and go on
# binding to a window system - silently, and only on the machines that have one.
# Someone reproducing a platform-specific bug sets EGL_PLATFORM in their own
# environment, which the harness still honours.
set(MGL_ITEST_COMMON_ENV "")
if (MOBILEGL_ITEST_EGL_VENDOR)
list(APPEND MGL_ITEST_COMMON_ENV "__EGL_VENDOR_LIBRARY_FILENAMES=${MOBILEGL_ITEST_EGL_VENDOR}")
endif()
unset(MOBILEGL_ITEST_EGL_PLATFORM CACHE) # see above: an old cache must not resurrect x11
if (MOBILEGL_ITEST_REQUIRE_GPU)
list(APPEND MGL_ITEST_COMMON_ENV "MOBILEGL_ITEST_REQUIRE_GPU=1")
endif()
set(MGL_ITEST_VULKAN_ENV ${MGL_ITEST_COMMON_ENV})
if (MOBILEGL_ITEST_VK_ICD)
list(APPEND MGL_ITEST_VULKAN_ENV "VK_ICD_FILENAMES=${MOBILEGL_ITEST_VK_ICD}")
# The three iterationRP repairs are tri-state quirks that default to device
# auto-detection, and lavapipe is not on any auto list - so on lavapipe the
# iterationRP scenarios run unrepaired and Program 203 misses its golden
# output. CI's integration-gpu job exports these three by hand; pinning them
# to the ICD instead means a local `ctest -L integration-gpu` measures the
# same thing the gate does, with no environment to remember.
if (MOBILEGL_ITEST_VK_ICD MATCHES "lvp_icd|lavapipe")
message(STATUS "Integration tests: lavapipe ICD - forcing the iterationRP repairs on")
list(APPEND MGL_ITEST_VULKAN_ENV
"MOBILEGL_MAGMA_FIX_ITERATIONRP_SUBGROUP_SCRATCH=1"
"MOBILEGL_MAGMA_DERIVE_NUM_SUBGROUPS=1"
"MOBILEGL_MAGMA_ITERATIONRP_FIX_BARRIER=1")
endif()
endif()
# The ENVIRONMENT test property is itself a `;`-list, and gtest_discover_tests
# forwards PROPERTIES as a flat list - so a plain `;`-joined value arrives as
# four separate arguments and everything after the first is silently read as
# another property name. Escaping the separators keeps the whole thing one list
# element until set_tests_properties expands it back. Without this only
# MOBILEGL_BACKEND_TYPE reaches the test and the vendor/ICD pinning is lost.
function(mgl_itest_join_environment outVar)
set(joined "")
foreach(entry IN LISTS ARGN)
if (joined)
string(APPEND joined "\\;${entry}")
else()
set(joined "${entry}")
endif()
endforeach()
set(${outVar} "${joined}" PARENT_SCOPE)
endfunction()
# --- what THIS TREE implements, answered by the build rather than by a person ----------
#
# Two P2 entries assert something that only EXISTS once another P2 package has landed:
# HandleRecycleScenario's Handles arm needs a backend keyed on {slot, gen} (packages C and D),
# its AbaControl arm needs a consumer for MOBILEGL_PIPE_HANDLE_ABA_CONTROL (package D), and
# CsoContentAddressingScenario needs the client-side tracker that mints CSOs at all (package B).
# The gates package is written and merged FIRST, against the P2 contract commit, precisely so
# that the AbaControl red is on the record before either backend is touched - so for a while
# those entries have nothing to assert.
#
# The honest report for that is a SKIP naming what is missing, never a deleted registration and
# never a green that means "the thing I test does not exist yet". What decides the skip is
# THIS block, so that nobody has to remember to remove a hand-written guard:
#
# * two of the three answers are pure EXISTENCE checks, through file(GLOB CONFIGURE_DEPENDS).
# Ninja re-evaluates such a glob before every build and reconfigures only when the RESULT
# changes, so these cost nothing until the file appears - and then they arm themselves.
# * the third has to read a file's CONTENTS, because package D re-keys inside an existing
# source rather than adding one. VertexInputStateFactory.cpp is the one file both of D's
# answers live in (ComputeHash's buffer key is what the re-key changes AND what the ABA
# knob reverts), it is small, and it is watched by name - so an edit to it reconfigures and
# an edit anywhere else in the backend does not.
#
# Every verdict is printed at configure time: a marker that silently answered "no" for a tree
# that does implement the thing would turn a real gate into a permanent skip.
set(MGL_ITEST_CAPABILITY_ENV "")
# Whether the library under test compiled the push arm. Passed in rather than inferred, because
# the two CSO counters and the cso[] bracket of the stats line are #if MOBILEGL_PIPE_PUSH: in a
# pull build there is no CSO to mint and no channel to read, so the control has nothing to say -
# and "nothing to say" must be a SKIP that names the reason, not an assertion failure about a
# missing bracket.
#
# 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()
# 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
# three arms are `#if MOBILEGL_PIPE_PUSH`. A pull build has no {slot, gen} key (the slot tables
# and the re-keyed memos are push-only) and no Features.PipeHandleAbaControl at all (Config.h
# declares the field inside `#if MOBILEGL_PIPE_PUSH` and ConfigLoader parses it in the same arm).
# A source-only probe would therefore arm the PULL build's lanes the moment packages C and D
# land: the AbaControl lane would go hard red on a gate G2 requires green (the guards it means to
# defeat are still in force, so the scenario's "expect the stale pixels" assertion fails), and the
# Handles lane would report green against a library that contains no re-key at all - the
# "test that cannot fail" this scenario exists to avoid.
#
# So the whole block sits under the same `if (MOBILEGL_PIPE_PUSH)` as MGITEST_PIPE_PUSH_BUILD, and
# HandleRecycleScenario re-checks that marker before either arm asserts, so a hand-forced
# environment cannot arm an arm this build does not have either.
#
# ALL FOUR MARKERS ARE CONTENT PROBES, AND NONE OF THEM NAMES A FILE. A probe for a filename asks
# the wrong question: the owning package chooses its own file layout, so the moment it moves the
# code the probe answers "no" forever and the arm skips with a reason that has become false - a
# test quietly measuring nothing, which is the one outcome this whole scenario exists to prevent.
# The CSO probe was rewritten for exactly that reason once already; the magma probe still read one
# hard-coded .cpp, and package D already keeps one of its two Features.PipeHandleAbaControl
# consumers in a different file of the same directory (Renderer/VulkanRenderer.cpp), so it was one
# refactor away from a permanent AbaControl skip. So all four now ask "does any source in the
# directory the owning package owns name this symbol?", which is the thing each arm actually needs.
#
# Staleness cannot creep in from either side: the GLOB is CONFIGURE_DEPENDS (a file added or
# removed re-runs it) and every file it finds is appended to CMAKE_CONFIGURE_DEPENDS (an edit to
# one re-runs it).
function(mgl_itest_probe_for_symbol outVar directory symbolRegex)
file(GLOB_RECURSE mglItestProbeSources CONFIGURE_DEPENDS
"${directory}/*.h" "${directory}/*.hpp" "${directory}/*.cpp" "${directory}/*.c")
set(mglItestProbeHit "")
foreach(mglItestProbeSource IN LISTS mglItestProbeSources)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${mglItestProbeSource}")
file(STRINGS "${mglItestProbeSource}" mglItestProbeLines REGEX "${symbolRegex}")
if (mglItestProbeLines AND NOT mglItestProbeHit)
set(mglItestProbeHit "${mglItestProbeSource}")
endif()
endforeach()
set(${outVar} "${mglItestProbeHit}" PARENT_SCOPE)
endfunction()
# The same probe, over a CONJUNCTION: BOTH regexes matched ANYWHERE UNDER the directory, not
# necessarily in the same file. outVar is set to "<file matching A> + <file matching B>" when both
# were found and to the empty string otherwise.
#
# P4a needs it for exactly one question and the question cannot be asked any other way. "Does
# MOBILEGL_PIPE_HANDLE_ABA_CONTROL defeat the identity of P4a's OBJECT kinds on this backend?" is
# not answered by "some source reads Features.PipeHandleAbaControl" - MagmaPipeArms.h does, and its
# consumers are Magma's VERTEX-INPUT keys, so a single-regex probe would arm the six P4a ABA
# controls on a backend where the knob cannot reach a texture, a framebuffer, a sampler, a view or a
# program, and every one of them would assert a corruption nothing on the tree can produce - a hard
# red on an always-on integration-gpu lane. Nor is it answered by "some source names a P4a subsystem
# bit", which will become true for a backend that honours the mask long before anyone wires the
# knob. What the arm needs is BOTH FACTS TO BE TRUE OF THE BACKEND.
#
# DIRECTORY-WIDE RATHER THAN PER FILE, and that is review finding F-M5 rather than a preference.
# Requiring one file to carry both makes the arming depend on the FILE LAYOUT a later package
# chooses: a backend that wires the knob in Managers.cpp while its P4a subsystem constants live in
# SlotTables.h satisfies the question and fails the probe, the six controls keep printing wired=0
# and asserting the correct pixels, and NOTHING fails, warns or records that the expected flip did
# not happen - the one failure mode a control whose flip is in the future has. The false-positive
# this trades against is a backend that reads the knob somewhere and names a P4a bit somewhere else
# without connecting them; that costs a red lane an engineer must look at, which is the direction
# that gets noticed. Both spellings of the answer are printed, so the configure log says which file
# supplied which half.
#
# Same staleness guarantees as the single-regex probe: CONFIGURE_DEPENDS on the glob, and every file
# it finds appended to CMAKE_CONFIGURE_DEPENDS.
function(mgl_itest_probe_for_two_symbols outVar directory symbolRegexA symbolRegexB)
file(GLOB_RECURSE mglItestProbeSources CONFIGURE_DEPENDS
"${directory}/*.h" "${directory}/*.hpp" "${directory}/*.cpp" "${directory}/*.c")
set(mglItestProbeHitA "")
set(mglItestProbeHitB "")
foreach(mglItestProbeSource IN LISTS mglItestProbeSources)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${mglItestProbeSource}")
if (NOT mglItestProbeHitA)
file(STRINGS "${mglItestProbeSource}" mglItestProbeLinesA REGEX "${symbolRegexA}")
if (mglItestProbeLinesA)
set(mglItestProbeHitA "${mglItestProbeSource}")
endif()
endif()
if (NOT mglItestProbeHitB)
file(STRINGS "${mglItestProbeSource}" mglItestProbeLinesB REGEX "${symbolRegexB}")
if (mglItestProbeLinesB)
set(mglItestProbeHitB "${mglItestProbeSource}")
endif()
endif()
endforeach()
if (mglItestProbeHitA AND mglItestProbeHitB)
set(${outVar} "${mglItestProbeHitA} + ${mglItestProbeHitB}" PARENT_SCOPE)
else()
set(${outVar} "" PARENT_SCOPE)
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()
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")
endif()
mgl_itest_join_environment(MGL_ITEST_GLES_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_FORCED_DS_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION=1" ${MGL_ITEST_COMMON_ENV})
# The shader-compiler configurations AsyncCompileScenario needs, and the one
# ViewportArrayScenario's negative control needs.
#
# These used to be poked into MG_Config::Features from inside the test bodies. They
# cannot be any more - on Android this module links the SHIPPING libMobileGL.so, which
# exports nothing internal - and they should not have been anyway: half of what each of
# them decides is latched before the first GL call (the compile pool and its threads;
# the advertised extension list, which a backend builds once from the configuration in
# force at its first use), so an in-process write could only ever have moved the other
# half. Every one of them is a whole-process property, and a whole-process property is
# spelled with an environment variable and a ctest entry of its own.
#
# Note the shape of every list here: it APPENDS to MGL_ITEST_COMMON_ENV /
# MGL_ITEST_VULKAN_ENV rather than standing alone. A ctest ENVIRONMENT property REPLACES
# the job environment rather than adding to it, so an entry that lists only its mode
# variable would silently lose the EGL vendor and Vulkan ICD pinning and run against
# whatever the loader found first.
mgl_itest_join_environment(MGL_ITEST_GLES_ASYNC_ON_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_ASYNC_OFF_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=0" ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_ON_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1" ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_ASYNC_OFF_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=0" ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_OPTIMISTIC_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ASYNC_SHADER_COMPILE=1"
"MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1" ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_OPTIMISTIC_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ASYNC_SHADER_COMPILE=1"
"MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS=1" ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_NO_VIEWPORT_EMULATION_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ESPRYT_FORCE_VIEWPORT_ARRAY_EMULATION=0" ${MGL_ITEST_COMMON_ENV})
# MOBILEGL_LOG_FILE_PATH alongside the pin, because the arming assertion needs somewhere to
# read the library's own report from. The strip's arming signal is a latched MGLOG_I and there
# is no other way for a test process to learn that it fired - MG_Config is not reachable from
# this module on Android, where it links the shipping library. The path is per-lane so nothing
# else appends to it, and the case only trusts the bytes written after it started.
mgl_itest_join_environment(MGL_ITEST_GLES_UNLOCATED_IO_BLOCKS_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ESPRYT_UNLOCATED_IO_BLOCKS=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/unlocated-io-blocks.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_WIDENED_PACKED16_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_ESPRYT_WIDEN_PACKED16_STORAGE=1" ${MGL_ITEST_COMMON_ENV})
# Same shape as the UnlocatedIoBlocks entry: the log path is where the reroute's latched
# MGLOG_I lands, and the arming case only trusts the bytes written after it started.
mgl_itest_join_environment(MGL_ITEST_VULKAN_PRIMGEN_REROUTE_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_MAGMA_PRIMGEN_QUERY_REROUTE=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/primgen-query-reroute.log"
${MGL_ITEST_VULKAN_ENV})
# The point-size demotion pinned on, per backend, with a per-lane log file for the arming
# assertion - the same MOBILEGL_LOG_FILE_PATH reasoning as the UnlocatedIoBlocks lane above.
# Two lanes because the demotion runs in the SHARED phase-B chain and each backend then
# consumes it differently (Espryt respells the driver-side capture request, Magma binds the
# SPIR-V Xfb decorations to the carrier).
mgl_itest_join_environment(MGL_ITEST_GLES_POINT_SIZE_DEMOTION_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_POINT_SIZE_DEMOTION=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/point-size-demotion-gles.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_POINT_SIZE_DEMOTION_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_POINT_SIZE_DEMOTION=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/point-size-demotion-vulkan.log"
${MGL_ITEST_VULKAN_ENV})
# TIMEOUT on every entry: a GPU test that wedges must fail the run, not hang it.
set(MGL_ITEST_TIMEOUT 120)
include(GoogleTest)
# Discovery runs `--gtest_list_tests`, which does not construct the harness and
# so needs no GPU. One registration per backend; TEST_PREFIX keeps the two sets
# of ctest names apart.
# The original ambient names remain present, but mechanism oracles must not
# inherit an inproc environment: they deliberately toggle process-local push
# masks, pointer-key ABA, direct persistent adoption or synchronous stats slots.
# Keep ordinary pixel/byte cases (including the other arena/regrow cases) on the
# caller's transport. A separate label makes every exception inspectable.
set(MGL_ITEST_MONOLITH_MECHANISM_FILTER
"HandleRecycleScenario.*:CsoContentAddressingScenario.*:ResourceSubsystemControlScenario.*:ObjectSubsystemControlScenario.*:PipeVerifyArmingScenario.*:PoisonOmissionScenario.*:StorageBufferRegrowScenario.NStorageDefinitionsCostNMapPersistentRoundtripsNotOnePerDraw:LargeArenaAdoptionScenario.AnAdoptionCostsExactlyOneMapPersistentRoundtrip")
# P3b/P4b wave 2-D package D2: TextureViewAliasScenario joins this list rather than the ambient
# one for the same reason TextureViewScenario is in it - every case it carries constructs a
# glTextureView, which DirectGLES withholds unless MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1
# (ConfigLoader.cpp:213). In the ambient entry it would green-skip on every run and the gate
# would be a name in a list.
set(MGL_ITEST_GLES_VIEW_FILTER
"TextureViewScenario.*:TextureViewAliasScenario.*:F1WireScenario.ComputeImageStoreThroughViewPreservesOtherRootLayer:F1WireScenario.TextureViewClearTargetsItsRootMipAndLayer:F1WireScenario.GenerateMipmapThroughViewKeepsOwnerLevelsAndLayersOutsideItsWindow:InvalidImageUnitScenario.ALevelPastATextureViewsWindowReadsZero")
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES."
TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:${MGL_ITEST_GLES_VIEW_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan."
TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_ENVIRONMENT}"
)
foreach(backend DirectGLES DirectVulkan)
if (backend STREQUAL "DirectGLES")
set(mechanism_environment "${MGL_ITEST_GLES_ENVIRONMENT}")
else()
set(mechanism_environment "${MGL_ITEST_VULKAN_ENVIRONMENT}")
endif()
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${backend}."
TEST_FILTER "${MGL_ITEST_MONOLITH_MECHANISM_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${mechanism_environment}\;MOBILEGL_TRANSPORT=monolith")
endforeach()
# This is Espryt's existing feature opt-in, independent of transport. Exercise
# the actual view implementation instead of inheriting its default-off skip.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES."
TEST_FILTER "${MGL_ITEST_GLES_VIEW_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS integration-gpu TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ENVIRONMENT}\;MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1")
# A third registration, of ONE scenario, with asynchronous shader compilation
# pinned on. Not a second code path in the renderer: a second ALLOCATION pattern.
# The async pipeline's job objects change which of the freed blocks the capture
# phase is handed, and that is what decides whether the destroyed-VAO address is
# reached at all - on the ablated (pre-fix) tree async=1 reproduced 3 runs out of
# 3 where the ambient default reproduced 2 of 3. Pinning it here means the
# high-signal configuration runs whatever the shipped default becomes, instead of
# the suite quietly weakening the day that default flips. It must be process-wide
# (the ENVIRONMENT property), not an in-process scope: the compile pool and its
# threads are stood up at initialization, and their allocations are half the
# point. DirectVulkan only - the memo this pins is DirectVulkan's.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.AsyncCompile."
TEST_FILTER "XfbAfterClipDistanceScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_ENVIRONMENT}"
)
# A fourth registration, of the depth/stencil readback scenarios, with the ES
# shader-sampling emulation forced on. Not paranoia - without it these scenarios are
# UNFALSIFIABLE on the machines this suite runs on: OpenGL ES has no depth or stencil
# readback in core, but Mesa accepts the reads anyway, so on llvmpipe every one of them
# goes green through a native path that the Adreno device does not have. Deleting the
# entire emulation left all of them passing. With the flag the native spellings are off
# the table and only the path the device actually takes remains. DirectGLES only - the
# emulation is DirectGLES's.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ForcedDepthStencilEmulation."
TEST_FILTER "DepthStencilReadback*Scenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_FORCED_DS_ENVIRONMENT}"
)
# UnlocatedIoBlockScenario with the interface-block location strip PINNED ON, for the same
# reason the depth/stencil entry above pins its emulation: without it this scenario is
# UNFALSIFIABLE on the machines this suite runs on. llvmpipe carries a located interface block
# correctly, so the driver POST that arms the strip on Mali answers "healthy" here and the
# emulation never runs - the ambient registration would be exercising the un-stripped path
# twice and calling it coverage. With the variable set, the blocks really are emitted with no
# location and the assertion is about the spelling the device gets.
# RESOURCE_LOCK, on this lane and on the three below it, and it is a bug fix rather than a
# precaution. Each of these lanes gives a WHOLE SCENARIO one MOBILEGL_LOG_FILE_PATH, and one case
# in each reads that log back to prove the pinned emulation actually armed. The library opens the
# log fopen(path, "w"), so every process in the lane TRUNCATES it - and under `ctest -j` a sibling
# case of the same lane can truncate it while the arming case is reading, which reads back as "the
# log carries no arming line" and fails a healthy lane. Measured on this tree: three runs of the
# full integration-gpu label at -j 8 produced 4 failures, 0 and 2, always one of these arming
# cases, never the same set twice.
#
# The rule stated above the verify block - a case that reads the log needs a lane whose filter
# selects it alone - would fix it by re-filtering, but that would RENAME the arming entries, and
# an existing ctest name may never disappear (gate G14). A ctest RESOURCE_LOCK named after the log
# is the same guarantee without touching a name: ctest never runs two entries holding the same lock
# at once, so the only processes that can truncate a lane's log are ones nobody is reading it for.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.UnlocatedIoBlocks."
TEST_FILTER "UnlocatedIoBlockScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK unlocated-io-blocks.log
ENVIRONMENT "${MGL_ITEST_GLES_UNLOCATED_IO_BLOCKS_ENVIRONMENT}"
)
# P4a final review C-2: the dirty-then-delete case, with the allocator SCRIBBLING every freed
# block. The defect this pins was a client emitter resolving a dead-but-not-recycled texture
# handle to the freed ITextureObject* and calling a virtual on it from the next verb's drain;
# whether that reads the object's ghost or faults depends on what the allocator did with the
# block, so the ambient registrations above run the case as the application would see it and
# these two run it with MALLOC_PERTURB_ set, where a resolved-but-dead pointer faults rather
# than passes. Both backends: the death path is backend-neutral by ruling (ID-8).
mgl_itest_join_environment(MGL_ITEST_GLES_MALLOC_PERTURB_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MALLOC_PERTURB_=165" ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_MALLOC_PERTURB_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MALLOC_PERTURB_=165" ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.MallocPerturb."
TEST_FILTER "P4aFinalFixScenario.ADirtyTextureDeletedBeforeAnyVerbIsWalkedByTheNextDrain"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_MALLOC_PERTURB_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.MallocPerturb."
TEST_FILTER "P4aFinalFixScenario.ADirtyTextureDeletedBeforeAnyVerbIsWalkedByTheNextDrain"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_MALLOC_PERTURB_ENVIRONMENT}"
)
# AsyncCompileScenario, with asynchronous compilation PINNED ON per backend.
#
# Not a duplicate of what the two ambient registrations already run: they run whatever
# MobileGL's built-in default happens to be, and the day that default flips they would
# stop covering the asynchronous path without anything going red. These entries are the
# ones that keep the asynchronous half tested no matter what ships. They are also the
# only place ExtensionStringMatchesTheConfiguration can assert that the extension IS
# advertised - the case derives its expectation from this variable and nothing else, and
# skips where it is unset, precisely so that it is not asserting the implementation
# against itself.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.AsyncOn."
TEST_FILTER "AsyncCompileScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ASYNC_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.AsyncOn."
TEST_FILTER "AsyncCompileScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_ON_ENVIRONMENT}"
)
# The other side of the same switch: asynchronous compilation OFF, so
# GL_KHR_parallel_shader_compile must be WITHDRAWN from both spellings of the extension
# list and GL_MAX_SHADER_COMPILER_THREADS_KHR must read 0. Only that one case is
# registered here because it is the only one that has anything to say in this
# configuration - the other four exist to observe worker-built artifacts, and there are
# none - so registering the whole scenario would buy four guaranteed skips per backend.
# Together with the AsyncOn. entries above, one ctest run still covers both flag states,
# which is what the in-process forcing used to be for.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.AsyncOff."
TEST_FILTER "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ASYNC_OFF_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.AsyncOff."
TEST_FILTER "AsyncCompileScenario.ExtensionStringMatchesTheConfiguration"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_ASYNC_OFF_ENVIRONMENT}"
)
# The optimistic-status quirk's end-to-end shape. Its own entries and not part of the
# AsyncOn. ones because the quirk is not neutral for the rest of the scenario: with it in
# force glGetShaderiv(GL_COMPILE_STATUS) deliberately answers without joining, which is
# exactly what CompletionStatusPollingThenForcedJoin asserts must NOT happen. Off by
# default and never advertised, so - unlike asynchronous compilation, which announces
# itself through the extension string - the variable is the only thing that can tell the
# case it is in force.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.OptimisticShaderStatus."
TEST_FILTER "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OPTIMISTIC_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.OptimisticShaderStatus."
TEST_FILTER "AsyncCompileScenario.IrisShapedTwoPhaseBatchRendersCorrectly"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_OPTIMISTIC_ENVIRONMENT}"
)
# The negative control for the DirectGLES gl_ViewportIndex emulation, in a process that
# has it switched off. One case, because it is the only one the switch may touch: with
# the emulation off the three positive cases in the same fixture describe behaviour the
# backend does not have, so a whole-scenario registration would be three guaranteed reds.
# DirectGLES only - the flag steers nothing on DirectVulkan, which routes natively.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.NoViewportArrayEmulation."
TEST_FILTER "ViewportArrayScenario.WithoutTheEmulationEveryIndexCollapsesOntoViewportZero"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_NO_VIEWPORT_EMULATION_ENVIRONMENT}"
)
# PrimitivesGeneratedNoXfbScenario again, with the GL_PRIMITIVES_GENERATED statistics
# reroute PINNED ON. The ambient DirectVulkan registration runs the same cases under the
# bring-up probe's Auto verdict, so between the two entries both accounting paths answer
# the same GL questions and must produce the same numbers - the "two pools must agree"
# gate this machine can hold that the affected device cannot. The pinned entry is also
# the only one whose arming case runs: it asserts the renderer's latched MGLOG_I, so a
# silently-disarmed reroute (an inverted override mapping, a lost gate) fails here
# instead of leaving every equality case vacuously green. DirectVulkan only - the flag
# steers nothing on DirectGLES.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.PrimGenReroute."
TEST_FILTER "PrimitivesGeneratedNoXfbScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK primgen-query-reroute.log
ENVIRONMENT "${MGL_ITEST_VULKAN_PRIMGEN_REROUTE_ENVIRONMENT}"
)
# The packed16 copy scenarios again, with the 8-bit storage widening PINNED ON. The ambient
# registrations above cover the narrow storage - on every CI driver the widening's POST
# probe finds no field-order mirror, so Auto keeps the native 16-bit path - which means the
# storage every AFFECTED device will actually run would otherwise execute nowhere at all:
# no CI driver has the Mali bug that arms it. This lane is what proves the widened storage
# is client-invisible (same packed words in and out on every leg the 18 failing CTS bodies
# used, the renderbuffer one included). DirectGLES only - the flag steers nothing on
# DirectVulkan, which has always stored these formats widened.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.WidenedPacked16."
TEST_FILTER "CopyImagePacked16Scenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_WIDENED_PACKED16_ENVIRONMENT}"
)
# PointSizeDemotionScenario with the demotion PINNED ON, per backend, for the reason every
# pinned lane above exists: llvmpipe and lavapipe both HOST gl_PointSize in tessellation and
# geometry stages, so the ambient registrations run these captures through the built-in and
# the demotion - the path every affected Mali device actually takes - would execute nowhere.
# The ambient runs stay the negative control: same scenario, same CPU-computed bytes, native
# path. Both backends, because the demotion is shared phase-B work with two different
# consumers (the ESSL capture respelling vs the SPIR-V Xfb carrier binding).
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.PointSizeDemotion."
TEST_FILTER "PointSizeDemotionScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK point-size-demotion-gles.log
ENVIRONMENT "${MGL_ITEST_GLES_POINT_SIZE_DEMOTION_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.PointSizeDemotion."
TEST_FILTER "PointSizeDemotionScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK point-size-demotion-vulkan.log
ENVIRONMENT "${MGL_ITEST_VULKAN_POINT_SIZE_DEMOTION_ENVIRONMENT}"
)
# --- the third CI mode: MOBILEGL_PIPE_VERIFY -----------------------------------
#
# ARCHITECTURE.md 13.2-(2) asks for a THIRD build mode next to pull and push: two state models in
# one address space, compared field by field at every verb boundary and again at every accessor
# read, 5-10x slower and never shipped. These entries are that mode's lane. They exist only when
# the library was configured with -DMOBILEGL_PIPE_VERIFY=ON, which is deliberate and is half of
# what makes the lane falsifiable: `ctest -L integration-verify --no-tests=error` in a build that
# forgot the option matches NO tests and fails, instead of reporting a green run of nothing.
#
# The other half is PipeVerifyArmingScenario.Armed, which asserts the library's own arming line -
# because MOBILEGL_PIPE_VERIFY=1 in the environment of a library that never compiled the
# comparator in is a silent no-op that looks exactly like a clean pass.
#
# Three things about the ENVIRONMENT properties below, each of which has already gone wrong once
# in this file:
# * every list APPENDS ${MGL_ITEST_COMMON_ENV} / ${MGL_ITEST_VULKAN_ENV}. A ctest ENVIRONMENT
# entry overrides the job environment for the names it lists, so an entry that named only its
# own knobs would lose the EGL vendor and Vulkan ICD pinning and run against whichever driver
# the loader found first.
# * the ambient Verify. entries name NEITHER MOBILEGL_PIPE_VERIFY_CORRUPT NOR
# MOBILEGL_PIPE_POISON_OMIT. That is what lets CI's two always-on negative-control steps
# export those knobs in the JOB environment and have them reach the test processes; a
# property entry of the same name would silently win and the controls would prove nothing.
# * MOBILEGL_LOG_FILE_PATH is per lane, and "per lane" is the exact limit of what it proves. It
# is the only channel a test process has for reading the library's own report (MG_Config is not
# reachable from this module), but the log is opened fopen(path, "w"), so every process in a
# lane TRUNCATES it: after an ambient lane of 400-odd entries the file holds the LAST process
# and nothing else. Reading it is therefore only sound in a filtered, one-entry lane - which is
# why the arming case has a lane and a log of its own below, and why neither this file nor CI
# may read the ambient logs as evidence about the entries that ran before the last one. The
# ambient path is kept for post-mortems (and to keep library chatter out of ctest's capture).
# --- G8: the handle ABA, three always-on arms -----------------------------------------
#
# ALWAYS ON, in every build mode, which is deliberate: the Legacy arm asserts today's
# lifetimeId + weak_ptr guards and is meaningful in a pull build, and `ctest -R HandleRecycle`
# has to name the same entries whichever build directory it is pointed at (P2 brief G8 runs it
# against build-verify; D.3 part 1 runs it again as part of the interface-purity gate).
#
# One lane per arm, and each lane names MGITEST_HANDLE_ARM: the arm is not a property of the
# test body, it is the (MOBILEGL_PIPE_PUSH, MOBILEGL_PIPE_LEGACY_MEMOS, MOBILEGL_PIPE_HANDLE_ABA_CONTROL)
# triple the process was launched with, and the scenario skips in the ambient entries because
# none of that is configured there.
#
# Every list APPENDS the common/Vulkan environment for the reason spelled out above the verify
# block: a ctest ENVIRONMENT property REPLACES the job environment for the names it lists, so an
# entry naming only its own knobs would lose the EGL vendor and Vulkan ICD pinning.
#
# The AbaControl arm is DirectVulkan only. The knob defeats the object-identity half of
# DirectVulkan's vertex-input memo keys (VertexInputStateFactory::ComputeHash, its per-VAO memo
# table, and LookupVaoDrawMemo); it steers nothing on DirectGLES, and a lane that configured it
# there would be a permanent skip claiming to be a control.
#
# SO THE BUFFER ABA's CORRUPTION EVIDENCE IS MAGMA-ONLY, AND THAT IS RECORDED RATHER THAN LEFT
# AS AN ABSENCE (gates m10, closed here as a statement rather than as a lane). P3a re-keys the
# BUFFER on DirectGLES - resource_* now dispatches by handle - so the obvious next move is a
# DirectGLES `.AbaControl` lane over ABufferAtARecycledAddressDoesNotInheritItsPredecessorsContents.
# It is not a registration-only change and it is therefore not made here: the knob has exactly
# one consumer in the tree (MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h's
# MagmaPipeAbaControlDefeatsIdentity, which is what the MGL_ITEST_MAGMA_ABA probe above looks
# for), so a DirectGLES lane would run with the knob inert, fail to reproduce the corruption it
# asserts, and go RED in an always-on integration-gpu lane - the exact failure mode the header
# of HandleRecycleScenario.cpp records this file already having had once.
#
# What that costs, stated so the next reader does not have to re-derive it: on DirectGLES the
# buffer case's Handles arm proves the re-key does NOT alias, and nothing proves the reproducer
# could still see an aliasing that was reintroduced there. The positive control for that is a
# Features.PipeHandleAbaControl consumer over Espryt's resource slot table - one `if` in
# GetOrCreate / FindByHandle, the way MagmaPipeClaimSlotMemos is Magma's - and it belongs with
# whoever next touches that table, not with a lane registration.
#
# It gets TWO lanes, because there are two arms and the control has to reach the one P2 SHIPS.
# `AbaControl` is D18's lane verbatim (MOBILEGL_PIPE_PUSH=0, the pre-handle arm) and defeats the
# lifetime-id/address guards; `AbaControlHandles` runs the handle arm (MOBILEGL_PIPE_LEGACY_MEMOS=0,
# the default push mask) and defeats the object identity that SELECTS THE SLOT - the key the handle
# arm ships. With only the first lane the control says nothing at all about the re-key: the handle
# arm is not executed under MOBILEGL_PIPE_PUSH=0, so every guard it would have to defeat is in
# another branch.
#
# NEITHER lane exercises the GENERATION half of {slot, gen}, and no lane of this shape can. Magma's
# mint has no death notification and returns a slot only through its age sweep (256/1024 boundaries,
# MagmaPipeArms.h), so the five frame boundaries this scenario issues always hand the replacement a
# brand-new slot at Gen 1; a real reuse needs >= 1024 idle boundaries, which puts the two draws in
# different frames - where the only pixel-visible memo declines by design. The generation is covered
# by the unit suite MG_Test/Pipe/MagmaPipeIdentityTest.cpp instead, which drives a real
# retire -> reuse; MagmaPipeAbaControlDefeatsIdentity carries the measurement.
#
# The two PUSH-ONLY knobs of those arms are set only in a push build, and the lane NAMES are
# unaffected by that (an ENVIRONMENT property is not part of a test's name, so G2 still sees the
# same list in both builds). MOBILEGL_PIPE_LEGACY_MEMOS=0 says "never enter the legacy arm"; in a
# pull build the legacy arm is the ONLY arm and every Track-H subsystem bit is clear, which is
# precisely D14's startup Fatal{PipeLegacyMemosDisabled} condition - so a lane that set it there
# would abort the process before the scenario could report its skip. MOBILEGL_PIPE_HANDLE_ABA_CONTROL
# has no field to parse into in a pull build at all (Config.h declares it under #if MOBILEGL_PIPE_PUSH).
# A lane that needs an arm pins EVERY knob that selects it. A ctest ENVIRONMENT property overrides
# only the variables it names; the rest leak in from the job. The five-part gate's all-pull control
# arm runs `MOBILEGL_PIPE_PUSH=0 ctest -L integration-gpu` over the whole label, and without the
# explicit bitmask below that leaked PUSH=0 turned this lane's LEGACY_MEMOS=0 into D14's armless
# combination: the bring-up aborted, on purpose, and the lane went red for a reason that was never
# about handles. The mask is the PHASE default, not a hand-picked bit, so the lane keeps measuring
# the shape that ships: it was kMGPipeSubsystemsMigratedAtP2 (0x7f), then
# kMGPipeSubsystemsMigratedAtP3a (0x1ff), and is now kMGPipeSubsystemsMigratedAtP4a (0x1fff,
# MG_Pipe/MGPipe.h), which adds bits 9-12 - framebuffer, texture resources, samplers and programs.
# Pinning it at 0x1ff after P4a would leave the Handles arm asserting the P3a shape while the six
# 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()
mgl_itest_join_environment(MGL_ITEST_GLES_HANDLE_HANDLES_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_HANDLE_ARM=handles" ${MGL_ITEST_HANDLES_ARM_KNOBS}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
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"
${MGL_ITEST_HANDLES_ARM_KNOBS} ${MGL_ITEST_ABA_ARM_KNOBS}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.HandleRecycle.Handles."
TEST_FILTER "HandleRecycleScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_HANDLE_HANDLES_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.HandleRecycle.Handles."
TEST_FILTER "HandleRecycleScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
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.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_ABA_HANDLES_ENVIRONMENT}"
)
# --- G12: the CSO content-addressing negative control ---------------------------------
#
# PUSH BUILDS ONLY, and that is the honest scope rather than a convenience: the two counters the
# control reads (CallClass::RenderStateCsoMints / RenderStateCsoBinds) and the `cso[...]` bracket
# of the summary line are both `#if MOBILEGL_PIPE_PUSH` (PipeStats.h, PipeStats.cpp), so in a pull
# build there is no channel to read and an entry here would be a permanent skip.
#
# Each arm gets a LOG PATH OF ITS OWN. The library opens its log fopen(path, "w") - every process
# in a lane truncates it - and these two cases READ that log, so a shared path would have them
# reading a neighbour's bring-up under `ctest -j 4`. Same rule as the arming lane below.
#
# MOBILEGL_PIPE_STATS_PERIOD=1 makes one summary line per eglSwapBuffers, which is what lets the
# workload be bracketed by two swaps and read back as a window covering exactly itself.
#
# Registered in EVERY build, including the pull build where there is no CSO at all, so that
# `ctest -L integration-gpu` stays name-for-name identical between pull and push (gate G2). In a
# pull build MGITEST_PIPE_PUSH_BUILD is absent and both cases skip saying so.
#
# THE MASK IS THE PHASE DEFAULT AND THE CONTROL IS BIT 63, and the two must not be confused. The
# only thing these four lanes are an A/B about is `no CSO content addressing` (bit 63,
# kMGPipeBehaviourNoCsoContentAddressing), which is what separates the On lane from the Off lane.
# Every
# other bit is the build's shipping mask, so it moves with the phase: 0x7f
# (kMGPipeSubsystemsMigratedAtP2), then 0x1ff (kMGPipeSubsystemsMigratedAtP3a), now 0x1fff
# (kMGPipeSubsystemsMigratedAtP4a) for the same reason MGL_ITEST_HANDLES_ARM_KNOBS above moved. Left
# pinned at 0x1ff after P4a these lanes would keep passing while running on a configuration nothing
# ships - bits 9-12 (framebuffer, texture resources, samplers, programs) cleared - which is the
# "still green, no longer measuring the shape that ships" failure the Handles-arm comment above
# rejects. NOTE THAT THE OFF LANE'S MASK MOVED TOO, from 0x80000000000001ff to
# 0x8000000000001fff: the mask moves with the phase, the control is bit 63, and the two must not be
# confused. The counters they read (csom / csob) are render-state and
# are steered by neither bit, so raising the mask is behaviour-preserving for what they assert;
# what it buys is that a CSO regression that only shows up with the P3a subsystems on can reach
# them. (contract-review-v1.md item 11, closed here for all three lane families.)
mgl_itest_join_environment(MGL_ITEST_GLES_CSO_ON_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_CSO_LANE=content-addressed"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/cso-content-addressed-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_CSO_OFF_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_CSO_LANE=no-content-addressing"
"MOBILEGL_PIPE_PUSH=0x8000000000001fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/cso-no-content-addressing-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_CSO_ON_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_CSO_LANE=content-addressed"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/cso-content-addressed-DirectVulkan.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_CSO_OFF_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_CSO_LANE=no-content-addressing"
"MOBILEGL_PIPE_PUSH=0x8000000000001fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/cso-no-content-addressing-DirectVulkan.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.CsoContentAddressing.On."
TEST_FILTER "CsoContentAddressingScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_CSO_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.CsoContentAddressing.Off."
TEST_FILTER "CsoContentAddressingScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_CSO_OFF_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.CsoContentAddressing.On."
TEST_FILTER "CsoContentAddressingScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_CSO_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.CsoContentAddressing.Off."
TEST_FILTER "CsoContentAddressingScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_CSO_OFF_ENVIRONMENT}"
)
# --- G12: the P3a subsystem A/B, and G10's map-persistent-roundtrips lanes ------------
#
# THE MASKS ARE PHASE CONSTANTS, not hand-picked bits: 0x1fff is
# kMGPipeSubsystemsMigratedAtP4a (the push build's default as of P4a) and 0x7f is
# kMGPipeSubsystemsMigratedAtP2, which is that default with bits 7 (resources), 8 (vertex input)
# and 9-12 (P4a's four object families) cleared. MGPipe.h keeps each phase's constant alive as the
# next phase's A/B control for this reason, and a lane that spelled its own bit pattern would stop
# being the shape that ships the first time the default moved. THE ON LANE MOVED TO 0x1fff WITH THE
# PHASE and the OFF LANE'S 0x7f DID NOT: this A/B is about bit 7, and pinning its On arm at 0x1ff
# after P4a would measure the resource emitter on a configuration nothing ships. P4a's own A/B -
# 0x1fff against 0x1ff - is ObjectSubsystemControl's, further down.
#
# DirectGLES only. P3a migrates Espryt's buffer and VAO paths; Magma's buffer path is P7 and
# registers no MGPipeResourceOps, so a DirectVulkan arm would be measuring the client emitter
# against a backend nobody asked to change.
#
# Each reading entry gets a LOG PATH OF ITS OWN, and its ctest entry selects ONE case: the library
# opens the log fopen(path, "w") - every process in a lane truncates it - and these cases READ it.
# Two readers in one lane race under `ctest -j`, and the failure looks exactly like "the counter
# was never emitted". Same rule as the CSO lanes above and the verify arming lane below.
#
# MOBILEGL_PIPE_STATS_PERIOD=1 makes one summary line per eglSwapBuffers, which is what lets a
# workload be bracketed by two swaps and read back as a window covering exactly itself.
#
# Registered in EVERY build, including the pull build where none of the counters exists, so that
# `ctest -L integration-gpu` stays name-for-name identical between pull and push (gate G2). In a
# pull build MGITEST_PIPE_PUSH_BUILD is absent and every one of these cases skips saying so; a
# MOBILEGL_PIPE_PUSH value in the environment of a pull library steers nothing (Config.h declares
# the field inside the push guard), exactly as the HandleRecycle Legacy lanes already rely on.
mgl_itest_join_environment(MGL_ITEST_GLES_RESOURCE_SUBSYSTEM_ON_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_RESOURCE_SUBSYSTEM_LANE=on"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/resource-subsystem-on-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_RESOURCE_SUBSYSTEM_OFF_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_RESOURCE_SUBSYSTEM_LANE=off"
"MOBILEGL_PIPE_PUSH=0x7f" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/resource-subsystem-off-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ResourceSubsystemControl.On."
TEST_FILTER "ResourceSubsystemControlScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_RESOURCE_SUBSYSTEM_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ResourceSubsystemControl.Off."
TEST_FILTER "ResourceSubsystemControlScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_RESOURCE_SUBSYSTEM_OFF_ENVIRONMENT}"
)
# G10's two counting entries, one per scenario that has a claim about the counter:
# StorageBufferRegrow asserts N definitions cost N round trips (never one per draw), and
# LargeArenaAdoption asserts one adoption costs exactly one. Each names a single case in its
# TEST_FILTER, for the private-log reason above.
mgl_itest_join_environment(MGL_ITEST_GLES_MPR_REGROW_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_MPR_LANE=storage-buffer-regrow"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/mpr-storage-buffer-regrow-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_MPR_ARENA_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_MPR_LANE=large-arena-adoption"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/mpr-large-arena-adoption-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.MapPersistentRoundtrips."
TEST_FILTER "StorageBufferRegrowScenario.NStorageDefinitionsCostNMapPersistentRoundtripsNotOnePerDraw"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_MPR_REGROW_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.MapPersistentRoundtrips."
TEST_FILTER "LargeArenaAdoptionScenario.AnAdoptionCostsExactlyOneMapPersistentRoundtrip"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_MPR_ARENA_ENVIRONMENT}"
)
# LargeArenaAdoption's three behavioural cases under BOTH arms of the same A/B. This file is where
# an adopted store's whole life is exercised - the NULL-data definition that adopts it, an
# in-flight SubData, a readback and a GPU write - so if the handle path and the legacy
# BufferBackendOps path disagree about any of it, one of these two lanes goes red and names which.
# No log path: none of these three cases reads one, and giving them one would only add a file for
# four processes to truncate. The fourth case skips in both lanes for exactly that reason, saying
# so.
#
# P11 A2: both lanes pin monolith, so both DECLARE the adopted arm (MGITEST_PERSISTENT_MAP_ARM) and
# LargeArenaAdoptionScenario.TheArenaLandsInTheTierItsLaneDeclares asserts the 24 MiB arena really
# adopted on the handle arm (Ops_H_MapPersistentTracked) and on the legacy one. Red once with
# MOBILEGL_DISABLE_LARGE_BUFFER_ADOPTION=1 in the job environment (CONTRACT-P11 §2).
mgl_itest_join_environment(MGL_ITEST_GLES_ARENA_SUBSYSTEM_ON_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith" "MGITEST_PERSISTENT_MAP_ARM=adopted"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_PUSH=0x1fff"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_ARENA_SUBSYSTEM_OFF_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith" "MGITEST_PERSISTENT_MAP_ARM=adopted"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_PUSH=0x7f"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# ... and Magma's monolith half: the legacy AcquirePersistentMap (the wire resource table is
# registered only off monolith, VkBufferManager.cpp RegisterWireResourceOps).
mgl_itest_join_environment(MGL_ITEST_VULKAN_ARENA_ARM_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith" "MGITEST_PERSISTENT_MAP_ARM=adopted"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ResourceSubsystemOn."
TEST_FILTER "LargeArenaAdoptionScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ARENA_SUBSYSTEM_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ResourceSubsystemOff."
TEST_FILTER "LargeArenaAdoptionScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_ARENA_SUBSYSTEM_OFF_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.ArenaArm."
TEST_FILTER "LargeArenaAdoptionScenario.TheArenaLandsInTheTierItsLaneDeclares"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_ARENA_ARM_ENVIRONMENT}"
)
# --- G12: the P4a subsystem A/B, and its dependency refusal ---------------------------
#
# THE MASKS ARE THE TWO PHASE CONSTANTS, exactly as the P3a block above: 0x1fff is
# kMGPipeSubsystemsMigratedAtP4a (the push build's default) and 0x1ff is
# kMGPipeSubsystemsMigratedAtP3a, which is that default with bits 9 (framebuffer), 10 (texture
# resources), 11 (samplers) and 12 (programs) cleared. THIS is the phase's "new 0x1ff off-lane": the
# constant P3a shipped survives as P4a's A/B control, and a lane that spelled its own bit pattern
# would stop being the shape that ships the first time the default moved.
#
# THE THIRD AND FOURTH LANES ARE THE DEPENDENCY REFUSALS (D-K2) and they are the entries in this
# family that are not vacuous before the emitters land, because both are decisions made from the
# bitmask alone. A half-honoured mask is invisible in the pixels by construction, which is why each
# needs an entry rather than a code comment.
#
# 0x9ff sets the sampler subsystem (bit 11) WITHOUT the texture resource subsystem (bit 10) that
# every MGPBoundView::Texture and MGPImageView::Res depends on.
# 0x5ff sets the texture resource subsystem (bit 10) WITHOUT the sampler subsystem (bit 11):
# D-K2's fourth row (ID-15). MGPTextureParams::BuiltinSampler is a SamplerCso handle and
# only bit 11 mints sampler CSOs, so bit 10 alone would emit a null there and the applier's
# Fatal is the next thing that happens. The brief called this pair harmless; P4a as built
# says otherwise, and the refusal belongs in the texture family's arm resolver.
#
# In both, the bring-up must log ONE error naming both bits and run the legacy arm.
#
# ONE CASE PER LANE, through TEST_FILTER, and it is a constraint rather than a preference: each case
# READS the library's log and the log is a per-LANE resource (the library opens it fopen(path, "w"),
# so every process in a lane truncates it). Two entries in one lane race under `ctest -j` with a
# failure indistinguishable from "the counter was never emitted". Same rule as the CSO lanes, the
# map-persistent lanes and the verify arming lane.
#
# THE FIRST FOUR LANES ARE DirectGLES ONLY. P4a migrates Espryt's framebuffer, texture, sampler
# and program paths; Magma's are P7 and register nothing here, so a DirectVulkan lane that measured
# the emit[] bracket would be measuring the client emitters against a backend nobody asked to
# change.
#
# THE FIFTH AND SIXTH LANES INVERT THAT, and the inversion is the point (c0f, ID-39/ID-40). "Magma
# registers no consumer" stopped being a reason to have no lane the moment it became a THING THE
# CLIENT MUST CHECK: P4a's families were wired without P3a's "a backend registered
# MGPipeResourceOps" conjunct, so on Magma the client emitted, the applier ACCEPTED, the client
# cleared its dirty flags on that acceptance and Magma's legacy path found nothing to upload - 66
# DirectVulkan cases red, every one of them texture-upload shaped, every one of them green at
# 0x1ff. The fix's belt (the applier refusing and counting RefusedNoConsumer) is invisible in
# pixels and invisible in the emit[] bracket, so it needs its own entry, and it needs it on the
# backend WITHOUT the consumer. The DirectGLES twin is the control that keeps the assertion from
# being vacuously true of a tree where nothing emits anywhere.
#
# Both run at the PHASE DEFAULT (0x1fff) rather than a hand-picked mask, for the reason the whole
# block gives: the shape that ships is the shape worth measuring.
#
# Registered in EVERY build, including the pull build where none of the counters exists, so that
# `ctest -L integration-gpu` stays name-for-name identical between pull and push (gate G2). In a
# pull build MGITEST_PIPE_PUSH_BUILD is absent and every one of these cases skips saying so.
mgl_itest_join_environment(MGL_ITEST_GLES_OBJECT_SUBSYSTEM_ON_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_OBJECT_SUBSYSTEM_LANE=on"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-on-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_OBJECT_SUBSYSTEM_OFF_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_OBJECT_SUBSYSTEM_LANE=off"
"MOBILEGL_PIPE_PUSH=0x1ff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-off-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_OBJECT_SUBSYSTEM_REFUSED_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_OBJECT_SUBSYSTEM_LANE=refused"
"MOBILEGL_PIPE_PUSH=0x9ff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-refused-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_OBJECT_SUBSYSTEM_REFUSED_TEXTURE_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_OBJECT_SUBSYSTEM_LANE=refused-texture"
"MOBILEGL_PIPE_PUSH=0x5ff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-refused-texture-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_OBJECT_SUBSYSTEM_CONSUMER_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_OBJECT_SUBSYSTEM_LANE=consumer"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-consumer-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_OBJECT_SUBSYSTEM_NO_CONSUMER_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_OBJECT_SUBSYSTEM_LANE=no-consumer"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/object-subsystem-no-consumer-DirectVulkan.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ObjectSubsystemControl.On."
TEST_FILTER "ObjectSubsystemControlScenario.ClearingTheP4aBitsStopsTheEmissionsAndNotThePixels"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OBJECT_SUBSYSTEM_ON_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ObjectSubsystemControl.Off."
TEST_FILTER "ObjectSubsystemControlScenario.ClearingTheP4aBitsStopsTheEmissionsAndNotThePixels"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OBJECT_SUBSYSTEM_OFF_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ObjectSubsystemControl.Refused."
TEST_FILTER "ObjectSubsystemControlScenario.ASamplerBitWithoutTheTextureBitIsRefusedAndNamed"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OBJECT_SUBSYSTEM_REFUSED_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ObjectSubsystemControl.RefusedTexture."
TEST_FILTER "ObjectSubsystemControlScenario.ATextureBitWithoutTheSamplerBitIsRefusedAndNamed"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OBJECT_SUBSYSTEM_REFUSED_TEXTURE_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.ObjectSubsystemControl.Consumer."
TEST_FILTER "ObjectSubsystemControlScenario.TheAppliersNoConsumerBeltNeverFiresBehindTheClientsGate"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_OBJECT_SUBSYSTEM_CONSUMER_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.ObjectSubsystemControl.NoConsumer."
TEST_FILTER "ObjectSubsystemControlScenario.TheAppliersNoConsumerBeltNeverFiresBehindTheClientsGate"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_OBJECT_SUBSYSTEM_NO_CONSUMER_ENVIRONMENT}"
)
# --- The texture upload shape: A GATE as of P3b/P4b R-11 (D-D4) -----------------------
#
# SSIM is blind to the box-versus-rect upload shape and the Mali cliff it hides is ~+6 ms/frame, so
# the shape needs a number - two numbers, in fact, the server's tex[emit= box= rect= jobs=] and the
# client's emit[ctu=], which agreeing is the whole reason both are published (D-L).
#
# P4a RECORDED those numbers rather than gating them, because the per-storage-owner emission cursor
# with view/owner index remapping - what actually decides the shape for a texture uploaded through a
# VIEW - was the next phase's and gating an unfinished shape pins a non-answer. THAT WORK LANDED
# (MG_Impl/Pipe/TextureEmit.h's owner-keyed drain list; TextureObjectView::ToOwner*), so this lane's
# RecordProperty block is now EXPECT_EQ against a gold row measured on this cursor, and the workload
# carries a third texture written through a glTextureView so the remap is inside the counted window.
#
# MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 IS THEREFORE MANDATORY HERE, not decorative: without it the
# case SKIPS rather than dropping the third texture, because a conditional workload behind a fixed
# gold row is a gate that passes by shrinking.
#
# THE MALI FRAME-TIME DELTA D-D4 asks for beside the gold is NOT SCHEDULABLE in this phase - one
# Redmi, an Adreno, no Mali part - and is recorded as a declared deviation in the scenario header
# and in docs/Disaggregated/MEASUREMENTS.md rather than modelled.
#
# Its own log path and its own single-case filter, for the per-lane-log reason above.
mgl_itest_join_environment(MGL_ITEST_GLES_TEXTURE_UPLOAD_SHAPE_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_TEXTURE_UPLOAD_SHAPE_LANE=1"
"MOBILEGL_PIPE_PUSH=0x1fff" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/texture-upload-shape-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.TextureUploadShape."
TEST_FILTER "TextureUploadShapeScenario.TheEmittedUploadShapeIsRecordedAndTheTwoSidesAgree"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK texture-upload-shape-DirectGLES.log
ENVIRONMENT "${MGL_ITEST_GLES_TEXTURE_UPLOAD_SHAPE_ENVIRONMENT}"
)
# --- G9: the mandatory red-before scenario -------------------------------------------
#
# TextureParamsWithoutASamplerViewScenario needs NO lane of its own, and that is deliberate rather
# than an omission. It reads no counter and no log - its observable is a sampled colour - and its
# claim is about the SHIPPING configuration, so the two ambient registrations at the top of this
# file (which run at the build's default mask) are exactly the arms it wants. A lane here would pin
# a mask and make the entry stop describing what ships the next time the default moved. The
# DirectVulkan ambient entries skip in the scenario's SetUp, naming the backend: the gap it is about
# is Espryt's SyncAttachmentObject / SyncNeccessaryTextures pair and P4a touches no DirectVulkan
# source but MagmaPipeArms.h (D-Q).
#
# D-E3 expects its second case, AReadAttachmentOnlyTexturesDepthStencilModeReachesTheDriver, to be
# RED until package esprytobj lands. MEASURED ON THE CONTRACT COMMIT IT IS GREEN, and the scenario's
# header carries the mechanism: a texture parameter's only public-GL observable is a sample, and the
# sample repairs the state it was meant to catch (the unit sync list re-syncs whenever the params
# version moved). Nothing about any of that is expressed in this file - a registration that
# "expected" a red would be a gate that could never go green - and the ruling on the missing
# artefact is the integrator's, recorded in the gates result document.
if (MOBILEGL_PIPE_VERIFY)
# 900s, not the ambient 120: the comparator re-reads every field of the fill mask at the verb
# boundary and again at every accessor read, which the design budgets at 5-10x.
set(MGL_ITEST_VERIFY_TIMEOUT 900)
mgl_itest_join_environment(MGL_ITEST_GLES_VERIFY_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-DirectGLES.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_VERIFY_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-DirectVulkan.log"
${MGL_ITEST_VULKAN_ENV})
# The arming assertion's own lane, one case per backend, with a log path nothing else writes to.
#
# PipeVerifyArmingScenario.Armed reads the library's log, and the log is a per-LANE resource: it
# is opened fopen(path, "w"), so every process in a lane truncates it. In the ambient Verify.
# lane that is 400-odd processes on one path, run `-j 4` in CI, and a whole-file read there
# races a neighbour's bring-up. Every other log-reading scenario in this file (UnlocatedIoBlocks,
# the primgen reroute, the point-size demotion) is registered exactly like this for the same
# reason. MGITEST_PIPE_ARMING_LANE is a harness marker - the library never reads it - and it is
# what makes the case skip in the ambient lane instead of racing there.
mgl_itest_join_environment(MGL_ITEST_GLES_VERIFY_ARMING_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_VERIFY=1" "MGITEST_PIPE_ARMING_LANE=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-arming-DirectGLES.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_VERIFY_ARMING_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_PIPE_VERIFY=1" "MGITEST_PIPE_ARMING_LANE=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-arming-DirectVulkan.log"
${MGL_ITEST_VULKAN_ENV})
# Negative control A (G4). MOBILEGL_PIPE_VERIFY_FATAL=0 so the process SURVIVES its own
# divergence and the case can read the report back out of the log; the CI step that exports
# the same corruption against the ambient lane, where FATAL keeps its default of 1, asserts
# the other half - that a divergence aborts and reds the entry.
mgl_itest_join_environment(MGL_ITEST_GLES_VERIFY_CORRUPT_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_PIPE_VERIFY_CORRUPT=GetRenderStateParameters" "MOBILEGL_PIPE_VERIFY_FATAL=0"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-corrupt-DirectGLES.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_VERIFY_CORRUPT_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_PIPE_VERIFY_CORRUPT=GetRenderStateParameters" "MOBILEGL_PIPE_VERIFY_FATAL=0"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-corrupt-DirectVulkan.log"
${MGL_ITEST_VULKAN_ENV})
# Negative control B (G5). The omission skips the STAMP of one field for one verb while still
# copying its value, which is indistinguishable from a fill row nobody wrote; the scenario
# forks, so the resulting std::abort() is a datum in waitpid() rather than a dead lane.
mgl_itest_join_environment(MGL_ITEST_GLES_POISON_OMIT_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_PIPE_POISON_OMIT=GenerateMipmap:GetActiveTextureUnit"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-poison-omit-DirectGLES.log"
${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_POISON_OMIT_ENVIRONMENT
"MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_PIPE_VERIFY=1"
"MOBILEGL_PIPE_POISON_OMIT=GenerateMipmap:GetActiveTextureUnit"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-poison-omit-DirectVulkan.log"
${MGL_ITEST_VULKAN_ENV})
# The whole suite again, per backend, with the comparator armed. Same scenarios, same
# assertions, but every backend read of frontend state is now checked against a snapshot taken
# from the live context at the verb boundary - which is what "the 742 integration entries
# prove push equals pull" means. Labelled integration-gpu as well so a verify build's
# `ctest -L integration-gpu` still describes the whole registration set.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Verify."
TEST_FILTER "-${MGL_ITEST_GLES_VIEW_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Verify."
TEST_FILTER "${MGL_ITEST_GLES_VIEW_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_ENVIRONMENT}\;MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1")
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Verify."
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_VERIFY_ENVIRONMENT}"
)
# The arming assertion, one entry per backend. This is the entry that fails a lane whose library
# never armed: it runs the same library and the same MOBILEGL_PIPE_VERIFY=1 as the ambient
# entries above, but unlike them it cannot be green against a library with no comparator
# compiled in. Its log is its own, so `-j 4` cannot make it flake.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.VerifyArming."
TEST_FILTER "PipeVerifyArmingScenario.Armed"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_ARMING_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.VerifyArming."
TEST_FILTER "PipeVerifyArmingScenario.Armed"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_VERIFY_ARMING_ENVIRONMENT}"
)
# One case each: the knobs are process-wide, so a corrupted or poisoned process cannot also be
# running the ambient assertions. These four entries are the ones that assert the RED - they
# pass when the comparator and the poison report, and go red when either stops.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.VerifyCorrupted."
TEST_FILTER "PipeVerifyArmingScenario.CorruptedFieldIsReported"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_CORRUPT_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.VerifyCorrupted."
TEST_FILTER "PipeVerifyArmingScenario.CorruptedFieldIsReported"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_VERIFY_CORRUPT_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.PoisonOmitted."
TEST_FILTER "PoisonOmissionScenario.OmittedFieldAbortsOnThatVerb"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_POISON_OMIT_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.PoisonOmitted."
TEST_FILTER "PoisonOmissionScenario.OmittedFieldAbortsOnThatVerb"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-verify\;integration-monolith-control"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_POISON_OMIT_ENVIRONMENT}"
)
endif()
# --- P5: the DirectGLES.Split. lanes and the persistent-map ARM lanes ------------------------
#
# THE PRIVATE SECOND LABEL IS WHAT MAKES THE LANE FALSIFIABLE, and it is the verify block above
# copied verbatim for the same argument: `ctest -L integration-split --no-tests=error` in a build
# that forgot -DMOBILEGL_BUILD_DISAGGREGATED=ON matches NOTHING and FAILS, instead of reporting a
# green run of zero entries. Keeping `integration-gpu` as well is why "a split build's
# `ctest -L integration-gpu` still describes the whole registration set" stays true.
#
# REGISTERED INSIDE `if (MOBILEGL_BUILD_DISAGGREGATED)`, and that is what keeps gate G2 (pull and
# push name-for-name identical) untouched: neither of those two builds sets the option, so the
# Split family is absent from BOTH of them rather than present in one. The two SCENARIO FILES the
# lanes point at are added to the source list unconditionally, so their cases DO appear in the
# ambient DirectGLES./DirectVulkan. registrations of every build - they are ordinary GL scenarios
# and their monolith behaviour is the baseline the split arm is compared against.
#
# WHAT ARMS THE SPLIT LANES, AND WHY IT IS NOT A PROBE OVER SOURCE TEXT.
#
# Until a real client session exists, MOBILEGL_TRANSPORT=inproc is parsed (CONTRACT-P5 5) and then
# nothing consumes it, so a Split entry would go green having run monolith end to end - the exact
# failure the lane exists to prevent. The first version of this file answered "has the client
# landed" with a CMake conjunction over c0's stub files: the c1 symbols present AND no
# `Fatal.Unimplemented` surviving. REVIEW FINDING M-1 FALSIFIED IT BY PERFORMING IT - a
# `sed -i 's/Fatal{Unimplemented/Fatal{NotYetImplemented/'` over c0's six stubs, with every entry
# point still aborting and ImplementedVerbCount() still 0, armed all eleven lanes and EIGHT WENT
# GREEN. A single comment line carrying the marker did the opposite and would keep them dark
# forever (M-2), and two stub files outside the two probed directories allowed a partial arm (M-3).
#
# A statement about source text can always be falsified by editing source text, and the people
# most likely to edit it are the ones landing the packages the probe watches for. So the arming
# condition moved into the PROCESS: Harness/SplitRuntimePeek.cpp reads MG_Config::Transport,
# ClientSession::Active() and ImplementedVerbCount() - three values c0 shipped and documented,
# none of which a message edit can move - and every Split case skips, naming the first one that is
# not true. All this file has to decide now is whether that peek can be COMPILED, which is exactly
# "did this build compile MG_Remote", which is exactly the build option.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_compile_definitions(MobileGLIntegrationTest PRIVATE -DMGITEST_SPLIT_RUNTIME_PEEK=1)
message(STATUS "Integration tests: the DirectGLES.Split. lanes arm from the RUNNING PROCESS - "
"MG_Config::Transport, ClientSession::Active() and ImplementedVerbCount() - and "
"skip naming the first of those that is not true")
endif()
# Q-3, made a build fact rather than documentation. ConfigLoader logs the resolved transport at
# INFO, and that line is what run_trace_case.cmake reads back as proof a retrace really went
# split. At WARN or above it is compiled out and every split retrace reds for a reason that is not
# a defect; at DEBUG, ConfigLoader's unconditional env dump prints a confusable KEY=VALUE line in
# a PULL build too (review M-5, also fixed on the reading side). The integration lanes themselves
# no longer depend on the log level at all - they read the variable - so this is a WARNING.
if (MOBILEGL_BUILD_DISAGGREGATED AND DEFINED MOBILEGL_LOG_ACTIVE_LEVEL
AND NOT MOBILEGL_LOG_ACTIVE_LEVEL STREQUAL "MOBILEGL_LOG_LEVEL_INFO"
AND NOT MOBILEGL_LOG_ACTIVE_LEVEL STREQUAL "MOBILEGL_LOG_LEVEL_DEBUG")
message(WARNING "Integration tests: MOBILEGL_LOG_ACTIVE_LEVEL=${MOBILEGL_LOG_ACTIVE_LEVEL} in a "
"disaggregated build. ConfigLoader's transport line is MGLOG_I, so the "
"trace-replay split arm's transport-resolution assertion cannot see it and every "
"split retrace will red. Use MOBILEGL_LOG_LEVEL_INFO.")
endif()
# Package b1's client-side persistent-map tracker, which is what Harness/PersistentMapPeek.cpp
# asks the membership question of (b1-v1.md 4.1 item 2). TWO halves, and both are needed:
# MOBILEGL_BUILD_DISAGGREGATED because a build that never compiled MG_Remote cannot LINK the call,
# and the content probe because b1 may not have landed it yet. __has_include in the peek would
# answer yes in a pull build - the header is in the source tree of every build - and turn a
# healthy pull build into a link error, which is why this decision is made here.
if (MOBILEGL_BUILD_DISAGGREGATED)
mgl_itest_probe_for_symbol(MGL_ITEST_PERSISTENT_MAP_TRACKER
"${MGL_ITEST_ROOT}/MobileGL/MG_Remote/Client" "IsLivePersistentMap")
if (MGL_ITEST_PERSISTENT_MAP_TRACKER)
message(STATUS "Integration tests: package b1's persistent-map tracker is present "
"(${MGL_ITEST_PERSISTENT_MAP_TRACKER}) - PersistentCoherentMapScenario's "
"membership assertion is live")
target_compile_definitions(MobileGLIntegrationTest PRIVATE -DMGITEST_PERSISTENT_MAP_TRACKER=1)
else()
message(STATUS "Integration tests: no source under MobileGL/MG_Remote/Client names "
"IsLivePersistentMap - package b1's tracker has not landed, so "
"PersistentCoherentMapScenario's membership assertion SKIPS")
endif()
endif()
# ARCHITECTURE.md:543 - every new ctest ENVIRONMENT and add_trace_replay_test's SPLIT branch
# carries MOBILEGL_IPC_SERVER_PATH, because the dladdr fallback cannot find the server from a
# binary that links MobileGL_s statically. P5 is inproc-only and nothing reads the value yet; it
# is carried now so that an unparsed variable and a parsed-and-ignored one stop being
# indistinguishable the day P6 consumes it. A generator expression is deliberately NOT used here:
# a $<TARGET_FILE_DIR:...> inside a gtest_discover_tests PROPERTIES value is written into the
# generated ctest include file verbatim and never expanded.
set(MGL_ITEST_SPLIT_SERVER_PATH "${CMAKE_BINARY_DIR}/libMobileGLServer.so")
# P3b/P4b wave 2-D package D2: MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 IS ON THE SHARED GLES
# SPLIT/SPAWN/TCP LISTS, not on a private entry, and that is the deliberate reading of the plan
# row. The knob is Espryt's FEATURE opt-in (ConfigLoader.cpp:213), independent of transport: it
# advertises GL_ARB_texture_view and nothing else. Without it TextureViewAliasScenario - and
# TextureViewScenario, if it is ever registered here - green-skips in all three arms and the
# gate is a name in a list. The monolith DirectGLES lane has carried it on its own view entry
# since P4a for exactly this reason; the split arms had no equivalent.
#
# It is NOT added to MGL_ITEST_VULKAN_{SPLIT,SPAWN,TCP}_ENVIRONMENT below: the variable is read
# only by ConfigLoader's Espryt feature block, so on DirectVulkan it would be a parsed-and-
# ignored name, and tier 2's informational Magma replay of these registrations wants the two
# backends' arms to differ only where the product differs.
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# The two counting lanes, one per transport, and they are a PAIR: exit gate E3(c) asks that the
# split arm's `mpr` equal the monolith arm's, and one test process can only ever see its own. So
# both lanes run the same workload and assert the same constant, and the equality holds by
# construction with each half able to fail on its own.
#
# Each gets a LOG PATH OF ITS OWN and a TEST_FILTER that selects ONE case, for the reason
# PipeStatsWindow.h gives: the library opens its log fopen(path, "w"), so every process in a lane
# truncates it, and two readers in one lane race under `ctest -j`. RESOURCE_LOCK on top of that,
# for the reason the UnlocatedIoBlocks lane gives - measured on this tree, three runs of the full
# integration-gpu label at -j 8 produced 4, 0 and 2 spurious failures of the log-reading cases
# without it.
#
# The monolith lane declares NO arm: which arm AcquireMemoryRange takes for a sub-16-MiB
# PERSISTENT|WRITE|COHERENT map is a property of the driver and the build, so the case RECORDS it
# there and skips the assertion. Only the split lane - where R-6 pins the adopt tier at T2 -
# declares one.
# MOBILEGL_TRANSPORT=monolith IS NAMED HERE ON PURPOSE, and it is review finding N-6. This entry
# is the MONOLITH half of a pair; without the property a job-level or gate-level
# `MOBILEGL_TRANSPORT=inproc` export reaches it (observed: its own log then carried
# `Config: MOBILEGL_TRANSPORT=inproc`) and, in the inproc arm of the three-arm A/B, BOTH halves of
# the pair were inproc. Nothing failed - each half asserts the same constant - but the pair was
# not the pair its name describes. A ctest ENVIRONMENT property overrides the job environment,
# which is the one case where that is what you want.
mgl_itest_join_environment(MGL_ITEST_GLES_PMAP_ARM_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_PMAP_LANE=1" "MOBILEGL_TRANSPORT=monolith"
"MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/persistent-map-arm-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.PersistentMapArm."
TEST_FILTER "PersistentCoherentMapScenario.TheMapLandsInTheArmItsLaneDeclares"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK persistent-map-arm-DirectGLES.log
ENVIRONMENT "${MGL_ITEST_GLES_PMAP_ARM_ENVIRONMENT}"
)
if (MOBILEGL_BUILD_DISAGGREGATED)
# One block per scenario, following the DirectGLES.MapPersistentRoundtrips. precedent: a
# `:`-separated multi-pattern TEST_FILTER is not used anywhere in this file, so its escaping
# through gtest_discover_tests' flat PROPERTIES forwarding is unproven, and three blocks cost
# nothing.
#
# ClearThenReadPixelsScenario is target A of the reduced path and already existed; Triangle is
# target B and PersistentCoherentMap is target C, both new in P5.
# ---- P6 `t6`: THE SPAWN ARM, beside the inproc one and never instead of it --------------
#
# EXIT GATES 9.2 AND 9.3: `integration-spawn`'s case-name set must be IDENTICAL to
# `integration-split`'s, and it must be green at the same count.
#
# THAT IDENTITY IS MADE STRUCTURAL RATHER THAN MAINTAINED. Registering the spawn arm as a
# second copy of each block would make the two sets agree today and drift the first time
# somebody adds a scenario to one of them - and a spawn lane covering LESS than the split
# lane goes green while proving less, with nothing to say so. One macro emits both arms from
# one filter, so a case added to either is added to both or to neither.
#
# ONE ENVIRONMENT DIFFERENCE, AND IT IS THE SUBJECT OF THE LANE. MOBILEGL_TRANSPORT=spawn
# makes the test process the CLIENT and has it launch a server from MOBILEGL_IPC_SERVER_PATH
# - the same path the inproc arm already carries, because under inproc the library reads it
# and decides it does not need one.
# D2: the texture-view opt-in, for the reason stated over the SPLIT list above. Under spawn
# the variable has to reach BOTH processes; it does, because the server is spawned from this
# process's environment.
mgl_itest_join_environment(MGL_ITEST_GLES_SPAWN_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# A single supervisor serves one session at a time. Fixture teardown also reaps a
# child left behind by a failed client; the resource lock serializes this lane.
set(MOBILEGL_ITEST_TCP_ENDPOINT "tcp://127.0.0.1:40613" CACHE STRING "Loopback TCP integration endpoint")
set(MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT "" CACHE STRING "Optional device TCP integration endpoint")
set(MOBILEGL_ITEST_TCP_DEVICE_TOKEN "" CACHE STRING "Token for the device TCP integration endpoint")
find_package(Python3 REQUIRED COMPONENTS Interpreter)
set(MGL_TCP_FIXTURE "${CMAKE_SOURCE_DIR}/scripts/ci/tcp_server_fixture.py")
set(MGL_TCP_STATE "${CMAKE_CURRENT_BINARY_DIR}/tcp-server.json")
add_test(NAME TcpServer.Start COMMAND "${Python3_EXECUTABLE}" "${MGL_TCP_FIXTURE}"
start --server "${MGL_ITEST_SPLIT_SERVER_PATH}" --endpoint "${MOBILEGL_ITEST_TCP_ENDPOINT}"
--state "${MGL_TCP_STATE}")
add_test(NAME TcpServer.Stop COMMAND "${Python3_EXECUTABLE}" "${MGL_TCP_FIXTURE}"
stop --state "${MGL_TCP_STATE}")
# P3b/P4b wave 2-D package D2: THE TCP LANE'S SERVER IS PRE-STARTED BY THIS FIXTURE, not
# spawned from a client that already carries the lane environment, so a FEATURE opt-in has to
# be set here as well as on MGL_ITEST_GLES_TCP_ENVIRONMENT. tcp_server_fixture.py builds the
# supervisor's environment from os.environ (:60) and strips only the transport keys (:63-65),
# so a ctest ENVIRONMENT property on this entry reaches the server process.
#
# Measured, not assumed: without it every TextureViewAliasScenario case SKIPPED in the Tcp
# arm with "GL_ARB_texture_view not advertised" while the identical Split and Spawn arms ran
# - because under inproc and spawn the server inherits the client's environment and under tcp
# it does not. A feature knob that reaches two of three arms is the worst of the three states:
# the lane is green and tests nothing.
set_tests_properties(TcpServer.Start PROPERTIES FIXTURES_SETUP mobilegl-tcp TIMEOUT 20
ENVIRONMENT "MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1")
set_tests_properties(TcpServer.Stop PROPERTIES FIXTURES_CLEANUP mobilegl-tcp TIMEOUT 20)
add_test(NAME TcpLane.AccountingControls COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/ci/tcp_lane_tools_test.py")
set_tests_properties(TcpLane.AccountingControls PROPERTIES LABELS unit TIMEOUT 20)
# P7 wave 0. scripts/ci/tcp_supervisor_smoke.py has been in the tree since P6.5 asserting the
# supervisor's Busy / token / wire-version / build-policy controls, and was referenced by
# NOTHING - no ctest entry, no workflow step - so nobody could have said whether those four
# controls were green. It also now carries Ph slice (1)'s negative control: a session child
# killed with SIGABRT must be NAMED in the supervisor log by pid and signal, and the next
# Hello must still be welcomed. It starts its own supervisor on its own free port, so it
# needs no fixture, but it takes the lane's resource lock because a second supervisor's
# session child would answer the other's peers with Busy and make both lanes flaky.
# It needs flatc, which is deliberately not in the build graph (gen_protocol.py's header):
# with none found the script exits 77 and this entry reports SKIP rather than passing on a
# test that did not run.
add_test(NAME TcpLane.SupervisorProtocolControls COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/ci/tcp_supervisor_smoke.py"
--server "${MGL_ITEST_SPLIT_SERVER_PATH}"
--out "${CMAKE_CURRENT_BINARY_DIR}/tcp-supervisor-smoke")
set_tests_properties(TcpLane.SupervisorProtocolControls PROPERTIES
LABELS integration-tcp TIMEOUT 180 SKIP_RETURN_CODE 77
RESOURCE_LOCK mobilegl-tcp)
# Ph fuzz arm 3 (PH-6, ID-P7-2): A PEER THAT STOPS DRAINING SEG_EVENT, on both data planes.
# MG_Test/Wire/EventForfeitPeerTest.cpp starts its own `--serve` supervisor (an abstract unix
# endpoint for the shm plane, a free loopback port for the stream plane) with a NON-default
# MOBILEGL_IPC_EVENT_WAIT_MS, and asserts the whole arm: the server forfeits the reverse
# channel by name against that knob, counts the drop, ends the session with exit 0 inside the
# knob rather than the old 30 s Fatal, and the SAME supervisor welcomes the next connection.
# Each entry also runs the kill-the-peer case (knob 8000, over ServerLoop's 5000 ms join: the
# server must say PeerGone at once and exit 0), and the shm entry the LaunchServer case (the
# knob must cross ServerSpawn.cpp's scrub). The gtest filters are per plane. The names are not
# `DirectGLES.<Arm>.<Scenario>` on purpose: spawn_lane_parity.py compares the scenario arms and
# this is a supervisor control, one per lane, like the entry above. It needs no fixture (its
# supervisor is its own), and the CI lane names both entries to junit_tally.py
# --require-entry-passed so a missing build or a skip is red by name. The Tcp entry still takes
# the lane's resource lock, as the entry above does: every integration-tcp entry must, or
# spawn_lane_parity.py and junit_tally.py --discovery refuse the registration.
if (TARGET EventForfeitPeerTest)
# A plain list, not mgl_itest_join_environment's escaped one: that form is for values that
# travel through gtest_discover_tests' PROPERTIES, and these two entries are add_test's.
set(MGL_ITEST_EVENT_FORFEIT_ENVIRONMENT
"MOBILEGL_TEST_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" ${MGL_ITEST_COMMON_ENV})
add_test(NAME SpawnLane.EventForfeitPeer COMMAND $<TARGET_FILE:EventForfeitPeerTest>
--gtest_filter=EventForfeitPeer.Shm*)
set_tests_properties(SpawnLane.EventForfeitPeer PROPERTIES
LABELS integration-spawn TIMEOUT 120
ENVIRONMENT "${MGL_ITEST_EVENT_FORFEIT_ENVIRONMENT}")
add_test(NAME TcpLane.EventForfeitPeer COMMAND $<TARGET_FILE:EventForfeitPeerTest>
--gtest_filter=EventForfeitPeer.Stream*)
set_tests_properties(TcpLane.EventForfeitPeer PROPERTIES
LABELS integration-tcp TIMEOUT 120 RESOURCE_LOCK mobilegl-tcp
ENVIRONMENT "${MGL_ITEST_EVENT_FORFEIT_ENVIRONMENT}")
endif()
# P7 F2: Ph fuzz arm 1 (PLAN-PH-P34B-P7.md §1.1, "gate: fuzz arm 1 malformed control
# frames"). Five malformed control frames - bad identifier, truncated length prefix, oversize
# length, garbage flatbuffer, wrong union type - sent to a live supervisor as a FIRST frame
# (answered by name with no child forked, PH-7 (5)) and inside an established session (the
# session ends with a named line and is not counted as a fault), with a well-formed client
# welcomed after each phase. Same shape as TcpLane.SupervisorProtocolControls: its own supervisor on its own
# port, the lane's resource lock, flatc or SKIP (77) - and CI requires it PASSED by name.
add_test(NAME TcpLane.ControlFrameFuzz COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/ci/ph_fuzz_control_frames.py"
--server "${MGL_ITEST_SPLIT_SERVER_PATH}"
--out "${CMAKE_CURRENT_BINARY_DIR}/tcp-control-frame-fuzz")
set_tests_properties(TcpLane.ControlFrameFuzz PROPERTIES
LABELS integration-tcp TIMEOUT 180 SKIP_RETURN_CODE 77
RESOURCE_LOCK mobilegl-tcp)
# D2: the texture-view opt-in on both TCP lists too, so the three shared GLES split arms
# carry one configuration. See the note over MGL_ITEST_GLES_SPLIT_ENVIRONMENT.
#
# THE TWO TCP LISTS ARE THE CLIENT'S HALF ONLY, and the two arms differ in whether that is
# enough. The loopback Tcp arm's server is started by the TcpServer.Start fixture below,
# which this package also gives the knob - so both halves have it. The TcpDevice arm's
# server is a supervisor already running ON A DEVICE, started outside this build by whoever
# set MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT; nothing here can reach its environment. If that
# supervisor was started without MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 it will withhold
# GL_ARB_texture_view and every texture-view case in the TcpDevice arm will GREEN-SKIP,
# exactly as the loopback arm did before the fixture entry got the knob. The arm is
# unconfigured in this repo (the endpoint defaults empty, so the arm is not created at all),
# so this is a note for whoever configures it rather than a defect today.
mgl_itest_join_environment(MGL_ITEST_GLES_TCP_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_SPLIT_LANE=1" "MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_GLES_TCPDEVICE_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1"
"MOBILEGL_IPC_TOKEN=${MOBILEGL_ITEST_TCP_DEVICE_TOKEN}"
"MGITEST_SPLIT_LANE=1" "MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# ---- P7 package L: THE SAME THREE ARMS FOR MAGMA ----------------------------------------
#
# The three lists above are the DirectGLES half of a dimension that had only one value. P7
# exit gate 1 asks for integration AND trace green "under Magma push and split", and until
# this package the shared labels `integration-split` / `-spawn` / `-tcp` held ZERO
# DirectVulkan entries: every arm of mgl_itest_register_split_arms hardcoded
# MOBILEGL_BACKEND_TYPE=DirectGLES and MGL_ITEST_MAGMA_WIRE_ENVIRONMENT hardcoded
# MOBILEGL_TRANSPORT=inproc, so the gate was not merely unmet, it was UNMEASURABLE.
#
# THE ONE DIFFERENCE FROM THE GLES TRIO IS ${MGL_ITEST_VULKAN_ENV}, AND IT IS NOT COSMETIC.
# That list carries VK_ICD_FILENAMES and, on lavapipe, the three iterationRP repairs the
# monolith `DirectVulkan.` arm has been pinned to since they were added (see its definition
# near the top of this file). A DirectVulkan lane that appended ${MGL_ITEST_COMMON_ENV}
# instead would run against whatever ICD the loader found first, which is exactly how a lane
# measures a different driver from the one the gate it mirrors measures.
#
# MOBILEGL_ITEST_REQUIRE_GPU=1 IS PINNED, as the existing Magma lanes pin it: on a host with
# no usable Vulkan every one of these entries would otherwise SKIP, and a lane that skipped
# everything and a lane that passed everything are the same green in ctest.
mgl_itest_join_environment(MGL_ITEST_VULKAN_SPLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_SPAWN_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_TCP_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_SPLIT_LANE=1" "MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
# THE TRANSPORT DIMENSION ON ITS OWN, for the Magma lanes further down this file that already
# have an environment of their OWN FLAVOUR (strict + dual-block state, run-ahead credits,
# cache pinning) and need only the transport half re-stated per arm. Kept beside the joined
# lists above so there is ONE place that says what "the spawn arm" and "the tcp arm" mean.
set(MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
set(MGL_ITEST_SPAWN_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
set(MGL_ITEST_TCP_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_TCP_LANE=1")
# ---- P7 package L: ONE SHAPE FOR EVERY MAGMA LANE'S THREE ARMS --------------------------
#
# The gated Magma tier is six hand-laid blocks (Fm, Buffers, RunAhead, Caches, NamedBlit,
# P5fRsp) because each carries a flavour of its own. What they share is the ARM: the same
# three transports, the same tcp fixture, the same label and log-name arithmetic. This macro
# is that shared half, so a seventh block gets its arms right by calling one line.
#
# Sets, for the arm it is given:
# mglItestArmLower split | spawn | tcp
# mglItestArmLogTag "" on the inproc arm, "-spawn"/"-tcp" on the others - THE
# INPROC ARM'S PRIVATE LOG PATHS DO NOT MOVE. magma_cache_checks
# and magma_runahead_checks name entries and re-derive their logs
# from discovery, and P6.5's device evidence cites these paths.
# mglItestArmProperties the tcp fixture + resource lock; empty otherwise
# mglItestArmTransportEnv the arm's transport pins, to append to the lane's flavour
# mglItestMagmaLabels "integration-magma-<arm>" plus one label per WORD in ARGN
#
# THE SUB-LABEL SPELLING IS ASYMMETRIC ON PURPOSE. On the inproc arm a word keeps its
# historical name (`integration-magma-buffers`); on the others the ARM comes first
# (`integration-magma-spawn-buffers`). `ctest -L` is a regex, so the obvious
# `integration-magma-buffers-spawn` would be SELECTED by the CI step that runs
# `-L integration-magma-buffers` and require_greens its twenty-one inproc entries by name -
# the lane would red on "required green entries differ" the day this package landed.
macro(mgl_itest_magma_arm_shape mglItestArm)
string(TOLOWER "${mglItestArm}" mglItestArmLower)
set(mglItestArmProperties)
set(mglItestArmLogTag "")
set(mglItestArmTransportEnv ${MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV})
if("${mglItestArm}" STREQUAL "Spawn")
set(mglItestArmTransportEnv ${MGL_ITEST_SPAWN_ARM_TRANSPORT_ENV})
set(mglItestArmLogTag "-spawn")
elseif("${mglItestArm}" STREQUAL "Tcp")
set(mglItestArmTransportEnv ${MGL_ITEST_TCP_ARM_TRANSPORT_ENV})
set(mglItestArmLogTag "-tcp")
set(mglItestArmProperties FIXTURES_REQUIRED mobilegl-tcp RESOURCE_LOCK mobilegl-tcp)
endif()
set(mglItestMagmaLabels "integration-magma-${mglItestArmLower}")
foreach(mglItestWord IN ITEMS ${ARGN})
if("${mglItestArm}" STREQUAL "Split")
set(mglItestMagmaLabels "${mglItestMagmaLabels}\\;integration-magma-${mglItestWord}")
else()
set(mglItestMagmaLabels
"${mglItestMagmaLabels}\\;integration-magma-${mglItestArmLower}-${mglItestWord}")
endif()
endforeach()
endmacro()
set(MGL_ITEST_MAGMA_ARMS Split Spawn Tcp)
# scenarioFilter, a PREFIX TAIL (empty for most; "F1." and "Ct." for the two per-slot loops,
# which name their sub-lane in the test name), then zero or more EXTRA LABEL STEMS. A stem is
# suffixed with the arm's own name (`integration-clientarrays` becomes `-split` on one arm and
# `-spawn` on the other), so a lane-scoped label cannot accidentally name both lanes at once.
# A UNIQUE LIST VARIABLE PER CALL, and the names collected for SplitLogPaths to walk.
#
# gtest_discover_tests' TEST_LIST is not a configure-time value: the generated include file
# sets it when CTEST runs. So one shared variable would hold only the LAST block's entries -
# measured, and it is why the first version of this macro silently unhooked every private log
# path but one. The counter gives each call its own name; the names are what get walked.
set(MGL_SPLIT_ARM_TESTS "")
set(MGL_SPLIT_ARM_TEST_LISTS "")
set(MGL_SPLIT_ARM_INDEX 0)
set(MGL_SPLIT_ARM_CALLS "")
# ---- P7 package L: THE BACKEND IS NOW A PARAMETER, AND THE TWO TIERS IT REGISTERS -------
#
# TIER 1, GATED. DirectGLES keeps every label it had - `integration-gpu`,
# `integration-{split,spawn,tcp,tcp-device}` and the caller's extra stems - so the sets CI
# gates on and the names G14 ratchets are byte-for-byte what they were. Magma's own gated
# tier is `integration-magma-{split,spawn,tcp}`, laid out by hand further down this file
# because each of those lanes carries a FLAVOUR (strict + dual-block state, run-ahead
# credits, cache pinning) that no shared filter can express.
#
# TIER 2, INFORMATIONAL, AND THAT IS THE POINT. DirectVulkan through THIS macro registers
# `integration-magma-all-{split,spawn,tcp}`: every scenario the split arms run, on Magma, on
# all three transports. It is deliberately in NO CI gating step. P7's exit gate 1 needs a
# lane that can be RED - the first run's red list IS the work list wave 2 clusters A/B/C
# divide up - and a red list is worthless if the only way to record it is to break the
# build's green. When a cluster retires its share, its cases move from this tier into the
# gated one, and CI stays honest at every step in between.
#
# THE LABEL SPELLINGS ARE CHOSEN AGAINST `ctest -L`'s REGEX MATCH (ID-131's rule, which this
# file has paid for twice). `-L integration-magma-spawn` must NOT select this tier, so the
# tier's word goes in the MIDDLE - `integration-magma-all-spawn` does not contain
# `integration-magma-spawn` as a substring, while the obvious `integration-magma-spawn-all`
# does and would have quietly pulled ~100 expected-red entries into the gated lane. Checked
# in both directions for all six spellings.
#
# NO `integration-gpu` ON THE MAGMA ARMS, deliberately: that label is a hard CI gate and the
# existing Magma split entries do not carry it either. NO EXTRA LABEL STEMS either - a stem
# like `integration-clientarrays` would produce `integration-clientarrays-spawn`, which is
# the label the DirectGLES spawn arm already owns, and one `ctest -L` would then run two
# backends under one name.
#
# NO TcpDevice ARM ON MAGMA: the device endpoint is one phone, run serially, and doubling
# its matrix before the host lane is even green buys nothing. Stated rather than implied.
macro(mgl_itest_register_split_arms_for_backend mglItestBackend scenarioFilter prefixTail)
# QUOTED DEREFERENCE, NOT A BARE NAME: a macro parameter is a textual substitution and
# not a variable, so `if(mglItestBackend STREQUAL ...)` would compare the literal string
# "mglItestBackend" and take the else branch on every call.
if("${mglItestBackend}" STREQUAL "DirectGLES")
set(mglItestEnvStem GLES)
set(mglItestLaneStem "integration")
set(mglItestSharedLabels "integration-gpu\\;")
set(mglItestArms Split Spawn Tcp)
if(MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT)
list(APPEND mglItestArms TcpDevice)
endif()
else()
set(mglItestEnvStem VULKAN)
set(mglItestLaneStem "integration-magma-all")
set(mglItestSharedLabels "")
set(mglItestArms Split Spawn Tcp)
endif()
foreach(mglItestArm IN LISTS mglItestArms)
string(TOLOWER "${mglItestArm}" mglItestArmLower)
string(TOUPPER "${mglItestArm}" mglItestArmUpper)
set(mglItestArmProperties)
if(mglItestArm STREQUAL "Tcp")
set(mglItestArmProperties FIXTURES_REQUIRED mobilegl-tcp RESOURCE_LOCK mobilegl-tcp)
elseif(mglItestArm STREQUAL "TcpDevice")
set(mglItestArmLower tcp-device)
set(mglItestArmProperties RESOURCE_LOCK mobilegl-tcp-device)
endif()
set(mglItestArmLabels "${mglItestSharedLabels}${mglItestLaneStem}-${mglItestArmLower}")
foreach(mglItestExtra IN ITEMS ${ARGN})
set(mglItestArmLabels "${mglItestArmLabels}\\;${mglItestExtra}-${mglItestArmLower}")
endforeach()
# ONE ACCUMULATED LIST FOR BOTH ARMS, and it is not bookkeeping: SplitLogPaths gives
# every entry a PRIVATE MOBILEGL_LOG_FILE_PATH, and SplitLogPaths.PrivateAndDistinct
# reds if one is missing or shared. The per-block TEST_LIST variables this macro
# replaced were what fed it - dropping them silently unhooked the whole mechanism,
# which that gate caught. Accumulating here means a block added later is covered
# without anyone remembering to add its variable to the list.
#
# IT MATTERS MORE ON THE SPAWN ARM: there TWO PROCESSES append to the path, so two
# entries sharing one file is not merely ambiguous, it interleaves two sessions.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestBackend}.${mglItestArm}.${prefixTail}"
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
TEST_FILTER "${scenarioFilter}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${mglItestArmLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_${mglItestEnvStem}_${mglItestArmUpper}_ENVIRONMENT}"
${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()
endmacro()
# THE NAME EVERY EXISTING CALL SITE USES, unchanged in signature so that this package adds a
# dimension without touching one registration. It also RECORDS its call, which is what makes
# tier 2 structural rather than maintained: the informational Magma tier at the end of this
# file replays the recorded list, so a scenario added to the split arms tomorrow joins the
# Magma census the same day and nobody has to remember a second edit. `-` stands for an empty
# prefix tail, because a CMake list cannot tell "one empty element" from "no elements".
macro(mgl_itest_register_split_arms scenarioFilter prefixTail)
if("${prefixTail}" STREQUAL "")
set(mglItestRecordedTail "-")
else()
set(mglItestRecordedTail "${prefixTail}")
endif()
list(APPEND MGL_SPLIT_ARM_CALLS "${scenarioFilter}|${mglItestRecordedTail}")
mgl_itest_register_split_arms_for_backend(DirectGLES "${scenarioFilter}" "${prefixTail}"
${ARGN})
endmacro()
mgl_itest_register_split_arms("ClearThenReadPixelsScenario.*" "")
mgl_itest_register_split_arms("TriangleScenario.*" "")
mgl_itest_register_split_arms("PersistentCoherentMapScenario.*" "")
# P11 A2 (MG_Remote/CONTRACT-P11.md §2): the >= 16 MiB arena on all three arms. Its tier case
# is declared emulated per entry by SplitLogPaths (T2: every acquisition declines); the mpr and
# adopt-tier-refusal cases skip here for want of their lane markers. The Magma arms are the
# gated `Arena.` block beside `Pbo.` / `Fence.` below, plus the Buffers lane.
mgl_itest_register_split_arms("LargeArenaAdoptionScenario.*" "")
# P11 A1 (CONTRACT-P11 §1): the tcp arm with MOBILEGL_IPC_ADOPT_TIER=0. A stream refuses the
# tier by name at the client's handshake and runs T2, so the whole scenario is green here and
# AStreamSessionRefusesTheAdoptTierOnceByName reads exactly one refusal line. TCP ONLY by
# construction: over shared segments (split, spawn) the same knob dies at the handshake, which
# is the unit gate RemoteClientControls.AdoptTier*OverSharedSegments*. The `.AdoptTier0.` tail is
# what keeps these names out of spawn_lane_parity.py's case set (see MAGMA_TCP_ONLY there).
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Tcp.AdoptTier0."
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
TEST_FILTER "LargeArenaAdoptionScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-tcp"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_TCP_ENVIRONMENT}\;MOBILEGL_IPC_ADOPT_TIER=0\;MGITEST_ADOPT_TIER_REFUSAL=T0"
FIXTURES_REQUIRED mobilegl-tcp RESOURCE_LOCK mobilegl-tcp
)
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")
# ---- P3b/P4b espryt D1 slice 1: THE ORPHANED XFB CAPTURE TARGET -------------------------
#
# The two cases whose whole subject is the split arm. A scattered capture is a
# read-modify-write of the destination's pre-capture bytes, and under a transport those bytes
# are the SERVER's staged shadow - so a buffer the application orphaned
# (glBufferData(size, NULL)) and only partly uploaded is the one shape where the shadow
# legitimately cannot answer for the whole range. The scatter used to read that as "discard
# this target": silently for a wholly orphaned store, and as
# Fatal{StageSnapshotTooNarrow, "xfb_scatter_pre_capture"} for a partly uploaded one.
#
# ---- P3b/P4b espryt D1 slice 2: THE WHOLE XFB FAMILY, once the writeback is sliced -------
#
# Slice 1 registered only OrphanedCaptureTarget* here, because the rest of these two files
# could not survive a transport: both writeback producers posted the WHOLE bound range as one
# SEG_EVENT record, and a record above half the ring (128 KiB at the 256 KiB default) is
# refused outright, which the server answers with Fatal{EventRingOverflow}. With the event
# sliced, the two scenarios go on in full - including the megabyte-range pair whose whole
# subject is that slicing, and XfbRepeatedCaptureScenario's gl_NextBuffer compacted-target
# shape, which is the first thing outside the census to exercise the archive-served stride
# and varyings (ProgramArchive->Link's xfb fields) on the server.
mgl_itest_register_split_arms("XfbAfterClipDistanceScenario.*" "Xfb.")
mgl_itest_register_split_arms("XfbRepeatedCaptureScenario.*" "Xfb.")
# ---- P3b/P4b espryt D1 slice 4: THE READBACK FAMILY ON THE SPLIT ARMS -------------------
#
# The 回读 half of the plan's "回读 / pack state" row. The PACK half is done - server reads
# with neutral pack state, the client scatters (ID-49, EmitTables.cpp) - and the READBACK half
# had no split coverage at all, so every claim about it was a reading of the code rather than
# a run of it. Arming the lanes is the first half of the work and the census is the second:
# what reds here IS the remaining worklist, and each red is either D1's to fix or excluded BY
# NAME with the Fatal quoted, the way the d1 draw block excludes
# MultiDrawScenario.ClientSideIndicesBatchMatchesUnrolledDraws.
mgl_itest_register_split_arms("PixelStoreSweepScenario.*" "")
mgl_itest_register_split_arms("PackedWordReadbackScenario.*" "")
mgl_itest_register_split_arms("LayeredTextureReadbackScenario.*" "")
# FramebufferChurnScenario shares PixelStoreSweepScenario.cpp and is the other half of its
# story - ~3300 texture+framebuffer pairs per case, the shape that walked an Adreno driver to
# 1.2 GB of leaked objects and then answered every readback with someone else's pixels. Under
# a transport every one of those pairs is also a create/destroy record round trip, so this is
# the only entry in the readback block that says anything about the OBJECT lifetime half.
mgl_itest_register_split_arms("FramebufferChurnScenario.*" "")
# P7 gate 5 (g5-readback): a glReadPixels larger than one SEG_REPLY slot is banded by the
# client instead of Fatal{ReplyTooLarge}. Exactly 2 MiB (the CTS renderbuffers_storage shape),
# 2 MiB + one row, more than the whole 16 MiB segment, a non-neutral pack state, a pack
# buffer, depth and packed depth/stencil, and glGetTexImage's windowed twin. The Magma arms of
# the same cases are the `Band.` block after the Fm lane below.
mgl_itest_register_split_arms("BandedReadbackScenario.*" "")
# P9 (W1, MG_Remote/CONTRACT-P9.md §1): the pack-buffer readback crosses as
# read_pixels_to_buffer / get_texture_image_to_buffer and is answered by nothing. Six parity
# cases (every pack parameter, the map reader, a byte swap, a layered glGetTexImage, an upload
# FROM the buffer the read filled, a later write over part of it) and the wire case (no
# reply-slot record, one mark per read). The Magma arms are the `Pbo.` block after the Band
# block below.
mgl_itest_register_split_arms("PackBufferReadbackScenario.*" "")
# P10 (A, MG_Remote/CONTRACT-P10.md §1): fence polls answered from kEventFenceSignaled - the
# idiom's poll loops end (with and without the flush bit), a signaled fence's polls cross
# nothing, and an idle server still reports a fence that finishes. The Magma arms are the
# `Fence.` block beside the `Pbo.` block below.
mgl_itest_register_split_arms("FencePollScenario.*" "")
# DepthStencilReadbackMatrixScenario GETS ITS OWN BLOCK, because it needs a variable the
# registration macro cannot carry: MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION=1.
#
# Without it this scenario is UNFALSIFIABLE on the machines this suite runs on, and the
# ambient DirectGLES.ForcedDepthStencilEmulation. lane says why: OpenGL ES has no depth or
# stencil readback in core, but Mesa accepts the reads anyway, so on llvmpipe every case goes
# green through a native path the Adreno device does not have - deleting the whole emulation
# left all of them passing. A split arm that inherited the ambient default would be measuring
# the same non-path three more times. So the pin is MIRRORED here, which is what the plan's
# row asks for.
foreach(mglItestDsArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestDsArm})
string(TOLOWER "${mglItestDsArm}" mglItestDsArmLower)
mgl_itest_join_environment(mglItestDsEnvironment
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION=1"
${mglItestArmTransportEnv} ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.${mglItestDsArm}.ForcedDs."
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
TEST_FILTER "DepthStencilReadbackMatrixScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-${mglItestDsArmLower}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${mglItestDsEnvironment}"
${mglItestArmProperties}
)
# Into the accumulated list like every other arm entry, so SplitLogPaths gives each of
# these a private MOBILEGL_LOG_FILE_PATH too - two processes append on the spawn arm.
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()
# ---- 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) ----------------------
#
# WHY A MONOLITH LANE CARRIES THE `integration-split` LABEL. That label does not mean "runs
# inproc" - it means "the set the disaggregation gate runs", which is exactly why it is
# registered inside this `if (MOBILEGL_BUILD_DISAGGREGATED)` and why the block above argues
# that a build without the option must match NOTHING under it. ID-81 gives the push build TWO
# server arms, selected at runtime by MG_Config::Transport, and until now only one of them had
# a gated entry: every Split block above exports MOBILEGL_TRANSPORT=inproc, and every
# split-only scenario skips itself the moment the runtime is not split (SplitRuntimeSkipReason
# in their SetUp), so the ambient monolith registration of those files runs zero cases. The
# arm the phone actually ships on was therefore ungated, and P5e landed a null dereference on
# it under 2250 green unit entries and 113 green split entries (ID-107: the game died in
# Lightmap.<init> -> clearColorTexture -> glClear). A second arm needs a second lane, in the
# same set, or "the gate is green" keeps meaning "one of the two arms is green".
#
# MOBILEGL_TRANSPORT=monolith IS NAMED, for review finding N-6's reason exactly as the
# PersistentMapArm pair above names it: a ctest ENVIRONMENT property overrides the job
# environment, and without it a gate-level `MOBILEGL_TRANSPORT=inproc` export would quietly
# turn this block into a fourth copy of the split lane - the one failure mode a lane whose
# whole purpose is to be the OTHER arm cannot survive.
#
# The scenario is registered ambiently as well (its source is in the list above), so
# `DirectGLES.MonolithAttachmentClearScenario.*` and `DirectVulkan.…` still exist in
# integration-gpu; this block is the copy the gate can see, under a prefix that says which arm
# it pins.
mgl_itest_join_environment(MGL_ITEST_GLES_PUSH_MONOLITH_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=monolith"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.PushMonolithArm."
TEST_LIST MGL_PUSH_MONOLITH_ATTACHMENT_TESTS
TEST_FILTER "MonolithAttachmentClearScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_PUSH_MONOLITH_ENVIRONMENT}"
)
# ---- P5b d1: the indexed / instanced / multi-draw / indirect draw family under inproc ----
#
# One block per scenario, the precedent above. IndexedDrawFamilyScenario is d1's own lane
# case: every case's picture depends on a d1 draw (an element-buffer glDrawElements, a
# client index array, a base vertex, the Minecraft trace's DrawElementsInstancedBaseVertex,
# the two multi-draws, an indirect draw), so a record that did not cross is a wrong picture
# and not a green. MultiDrawScenario, DrawParametersScenario and PrimitiveRestartScenario are
# the census's own DrawElements / MultiDrawElementsBaseVertex / DrawArraysInstancedBaseInstance
# / MultiDraw*Indirect* first-blocker scenarios, now at their pictures. The ONE case excluded
# by filter is MultiDrawScenario's ClientSideIndicesBatchMatchesUnrolledDraws: a multi-draw
# with client-side indices is refused BY NAME under split (Fatal{UnmigratedVerb,
# "MultiDrawElementsBaseVertex+CLIENT_INDICES"}, CONTRACT-P5B.md d1 - P8's HostResolve.cpp
# flattens it), which is its next first blocker and not a lane failure. It is listed in
# d1-v1.md, not deleted (G14). GuiBatchScenario (the census's other DrawElements scenario) is
# NOT registered: past its draws it stops at Fatal{UnmigratedVerb, "MemoryBarrier"}, which is
# i1's to flip; i1 registers it when that lands.
set(MGL_SPLIT_D1_SCENARIOS IndexedDrawFamilyScenario MultiDrawScenario DrawParametersScenario
PrimitiveRestartScenario)
set(MGL_SPLIT_D1_FILTER_IndexedDrawFamilyScenario "IndexedDrawFamilyScenario.*")
set(MGL_SPLIT_D1_FILTER_MultiDrawScenario
"MultiDrawScenario.*-MultiDrawScenario.ClientSideIndicesBatchMatchesUnrolledDraws")
set(MGL_SPLIT_D1_FILTER_DrawParametersScenario "DrawParametersScenario.*")
set(MGL_SPLIT_D1_FILTER_PrimitiveRestartScenario "PrimitiveRestartScenario.*")
foreach(mglItestD1Scenario IN LISTS MGL_SPLIT_D1_SCENARIOS)
mgl_itest_register_split_arms("${MGL_SPLIT_D1_FILTER_${mglItestD1Scenario}}" "")
endforeach()
# ---- P5e mv: THE MULTI-DRAW TIERS, INSIDE THE GATED SET (ID-109's rule, one level down) --
#
# WHY FIVE MORE LANES FOR ONE FILE. MultiDrawImpl asks the bound index buffer three questions
# and P5e (mv) moved all three onto the applier's record. Five of this driver's six tiers ask
# them from a DIFFERENT place in the batch - `RunIndirect` before any GL work, the rebased
# tier from the CPU shadow, `FlattenWithCompute` before PrepareForDraw has even run - and the
# resolved tier is ONE process-wide read of MOBILEGL_ESPRYT_MULTIDRAW_MODE (MultiDraw.cpp's
# ResolveTierOnce). The d1 block above leaves it at `auto`, and on every driver this gate has
# run against, `auto` lands on `ext` - a real multi-draw entry point that asks the index
# buffer nothing at all. Three of the five migrated sites therefore had no gated entry.
#
# That is ID-107's shape exactly one level down: code on a real arm, with no entry in the set
# the gate runs. The phase already paid 137 SEGFAULTs across 38 scenarios for the version of
# this that lived at the transport level, and the lesson ID-109 drew - "the gate runs the SET,
# so put the second arm in the set" - does not stop being true because the selector is an env
# knob rather than MG_Config::Transport. A manual sweep run once by one package decays to
# nothing by the next one.
#
# MOBILEGL_ESPRYT_MULTIDRAW_MODE IS A ctest ENVIRONMENT PROPERTY, not a job-level export, for
# review finding N-6's reason and the PushMonolithArm block's: the property overrides the job
# environment, so a gate that exported a mode of its own could not silently collapse these
# five lanes into five more copies of the `auto` one - the single failure mode a lane whose
# whole purpose is to pin a tier cannot survive.
#
# `ext` IS NOT REGISTERED HERE, deliberately: it is what `auto` already resolves to, so the
# d1 block above IS the ext lane and a sixth block would only run it twice. Every other tier
# was confirmed to resolve to ITSELF on this driver rather than falling back
# (`ResolveTier`'s "MOBILEGL_ESPRYT_MULTIDRAW_MODE=<x> -> <x> (driver supports: ext,
# basevertex, multiindirect, indirect, drawelements, compute (opt-in))"); a tier the driver
# refuses would resolve to `ext` and register an entry that quietly proves nothing, so if this
# list ever runs somewhere poorer, drop the refused tier rather than keeping a green that
# means "ext again".
#
# THE FILTER IS THE TIER-SENSITIVE WORKLOAD and nothing else, which is this file's own rule
# for an armed Split entry: MultiDrawScenario (its whole point is that a batch matches the
# unrolled draws, which is precisely what a wrong index buffer breaks quietly) and
# IndexedDrawFamilyScenario's three MultiDraw cases. The client-side-indices case keeps the
# d1 block's exclusion - it is refused by name under split before any tier is chosen.
#
# NOTE FOR THE STRICT-MARKER CENSUS (PREAMBLE-ADDENDUM-WAVE3 §4): these entries carry a THIRD
# name segment, so `strict_census2.sh` re-derives their gtest filter from the last two
# components and re-runs them WITHOUT the mode this block pins - which for these lanes is the
# whole point of the entry. They join Ct. / F1. / SmallRing. / PersistentMapArm. / NamedBlit.
# in that blind spot, so SplitLogPaths.cmake.in gives each of them a private log path: read
# the marker out of `build-split/MobileGL/MG_IntegrationTest/split-logs/<entry>.log`, which
# the LANE wrote under its own pin, instead of out of a re-run that lost it.
set(MGL_SPLIT_MULTIDRAW_TIERS basevertex multiindirect indirect drawelements compute)
set(MGL_SPLIT_MULTIDRAW_TIER_PREFIX_basevertex "BaseVertex")
set(MGL_SPLIT_MULTIDRAW_TIER_PREFIX_multiindirect "MultiIndirect")
set(MGL_SPLIT_MULTIDRAW_TIER_PREFIX_indirect "Indirect")
set(MGL_SPLIT_MULTIDRAW_TIER_PREFIX_drawelements "DrawElements")
set(MGL_SPLIT_MULTIDRAW_TIER_PREFIX_compute "Compute")
set(MGL_SPLIT_MULTIDRAW_TIER_FILTER
"MultiDrawScenario.*:IndexedDrawFamilyScenario.MultiDraw*-MultiDrawScenario.ClientSideIndicesBatchMatchesUnrolledDraws")
foreach(mglItestMultiDrawTier IN LISTS MGL_SPLIT_MULTIDRAW_TIERS)
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_MULTIDRAW_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ESPRYT_MULTIDRAW_MODE=${mglItestMultiDrawTier}"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX
"DirectGLES.Split.MultiDrawTier${MGL_SPLIT_MULTIDRAW_TIER_PREFIX_${mglItestMultiDrawTier}}."
TEST_LIST "MGL_SPLIT_MULTIDRAW_${mglItestMultiDrawTier}_TESTS"
TEST_FILTER "${MGL_SPLIT_MULTIDRAW_TIER_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_MULTIDRAW_ENVIRONMENT}"
)
endforeach()
# ---- P5b package i1 (MG_Remote/CONTRACT-P5B.md §2 i1) --------------------------------
#
# THE LANE CASE THAT PROVES THE RECORDS CROSSED, and it is a RESULT and not a probe (R-16:
# a probe may not arm against a stub). Each of these four scenarios asserts a value that
# only exists if the verb ran on the apply thread - the texel a compute shader stored
# through an image unit, the word glCopyImageSubData moved, the counter an atomic add left
# behind, the block a program pipeline rebound - so a sink that DECLINED, or a client that
# fell through to the driver, is red by the number it reads back and not by a tally.
#
# Before i1 every one of these aborted at the client's Fatal{UnmigratedVerb} on the first
# glBindImageTexture / glDispatchCompute / glCopyImageSubData / glShaderStorageBlockBinding;
# all four are green under inproc now (the census: 13 + 6 + 11 + 3 DirectGLES entries).
# RED ONCE BY DOING X: return false from ServerVerbSink::OnLaunchGrid before the
# gl.DispatchCompute call and UnboundImageDescriptor / AtomicCounter / ProgramPipeline all
# read back their initial values.
#
# THE FILTERS ARE NARROWED TO THE CASES THAT ACTUALLY EMIT, and that is ScenarioFixture's
# rule rather than a convenience: an armed `DirectGLES.Split.` case must move the client
# encoder's record ordinal (ScenarioFixture.h:86), because a lane whose workload produced no
# record is the "resolved the transport and then fell through to the driver" shape that
# every pixel assertion is blind to. ProgramPipelineScenario's other nine cases are pure
# name/state cases that draw nothing, so the whole-scenario filter would arm them and they
# would be red for having nothing to say. The two named here are the ones that were
# Fatal{UnmigratedVerb, "ShaderStorageBlockBinding"} on the c0b head.
#
# One block per scenario, following the three above: a `:`-separated multi-pattern
# TEST_FILTER is unproven through gtest_discover_tests' flat PROPERTIES forwarding.
set(MGL_SPLIT_I1_SCENARIOS
UnboundImageDescriptorScenario # bind_shader_image (72) + launch_grid (60), 13 cases
CopyImageLayeredScenario # resource_copy_region (53), 6 cases
AtomicCounterScenario # launch_grid (60) + memory_barrier (61), 3 cases
ProgramPipelineScenario) # set_storage_block_binding (75), the 2 storage-block cases
set(MGL_SPLIT_I1_FILTER_UnboundImageDescriptorScenario "UnboundImageDescriptorScenario.*")
set(MGL_SPLIT_I1_FILTER_CopyImageLayeredScenario "CopyImageLayeredScenario.*")
set(MGL_SPLIT_I1_FILTER_AtomicCounterScenario "AtomicCounterScenario.*")
set(MGL_SPLIT_I1_FILTER_ProgramPipelineScenario "ProgramPipelineScenario.*StorageBlock*")
foreach(mglItestI1Scenario IN LISTS MGL_SPLIT_I1_SCENARIOS)
mgl_itest_register_split_arms("${MGL_SPLIT_I1_FILTER_${mglItestI1Scenario}}" "")
endforeach()
# ---- P7 gate 5 (g5-imgwin): AN IMAGE UNIT NAMING A (LEVEL, LAYER) ITS TEXTURE LACKS ------
#
# GL 4.6 core 8.26 makes every access through such a unit invalid - zero loads, dropped
# stores - and never an error. Espryt forwards the unit to the driver, which applies the rule
# itself; these are its three arms. The Magma arms of the same scenario are laid by hand in
# the Fm block (`DirectVulkan.<arm>.ImageUnitWindow.`), because that is where the wire arm's
# gated flavour lives.
#
# ALL SIX CASES, THE TEXTURE-VIEW ONE INCLUDED. The view case waited outside the gated arms
# while every glTextureView under a transport ended the session at Fatal{ProtocolCorruption,
# "StagedTextureStore.NoteLevelDefined"} (p7/f2's view descriptor carried internalFormat
# 0xFFFFFFFF); the F2 repair (f2-latch slice A) retired that death, so it joins them here and
# in the Magma ImageUnitWindow foreach. The shared GLES split lists carry
# MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1, so it does not green-skip on these arms.
mgl_itest_register_split_arms("InvalidImageUnitScenario.*" "")
# ---- P9 W2: A TEXTURE RE-MINT NEEDS NO BYTE FROM THE CLIENT ------------------------------
#
# The ROADMAP's `TextureRemintPullScenario`, and it proves the opposite of its name: the
# server re-mints from the GPU level and its own staged store, so no pull protocol exists
# (notes/p9/W2-REMINT.md). Espryt's three arms here; the Magma arms are laid by hand in the
# `DirectVulkan.<arm>.Remint.` block, where the gated Magma flavour lives; both backends' monolith
# entries come from the whole-binary discovery.
mgl_itest_register_split_arms("TextureRemintPullScenario.*" "")
# W2-b's control. MGITEST_ESPRYT_FORCE_REMINT_READBACK_FAILURE is read by the SERVER (the
# promotion in RequireImageBindableStorageByHandle), so it reaches inproc and spawn - the spawned
# server copies this process's environment - and never the tcp lane's shared fixture: split and
# spawn only, the MAGMA_SERVER_ENV_KNOB_NO_TCP reason. The entries carry their own label rather
# than integration-{split,spawn} so the Espryt spawn-parity sets stay knob-free; integration-gpu
# is what runs them in the gate. Only the uploaded-only cases: their levels are covered by the
# store, so the fallback must still produce the right texels and the server log must name it.
foreach(mglItestArm IN ITEMS Split Spawn)
string(TOUPPER "${mglItestArm}" mglItestArmUpper)
string(TOLOWER "${mglItestArm}" mglItestArmLower)
foreach(remintFallbackCase AnUploadedMutableTextureKeepsItsTexelsAcrossTheImageBind
AWidenedFormatsUploadSurvivesTheCarrierRemint
AnRgba8SnormUploadSurvivesTheImageBind
AnRgba16SnormImmutableUploadSurvivesTheCarrierRemint)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.${mglItestArm}.RemintFallback."
TEST_FILTER "TextureRemintPullScenario.${remintFallbackCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\\;integration-remint-fallback-${mglItestArmLower}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_${mglItestArmUpper}_ENVIRONMENT}\;MGITEST_ESPRYT_FORCE_REMINT_READBACK_FAILURE=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p9-remint-fallback-${mglItestArmLower}-${remintFallbackCase}.log")
endforeach()
endforeach()
# ---- P11 M: DEV'S TWO GPU-CONTENT SCENARIOS ON THE SPLIT ARMS ----------------------------
#
# Merged from dev@c60639db with their monolith entries. ImageBindableRemintScenario is the
# monolith twin of TextureRemintPullScenario above (568090f0 made Espryt's frontend re-mint
# read the GPU level back as the server's already did); PartialUploadOverGpuContentScenario is
# 8966d5c2's sub-rect upload over converted/reshaped levels (the server's handle arm cuts the
# region from the conversion's buffer too) plus b1d60523's Magma ordering cases, which are
# plain GL and run here on Espryt as well. The Magma arms are laid by hand in the
# `DirectVulkan.<arm>.GpuContent.` block, where the gated Magma flavour lives.
mgl_itest_register_split_arms("ImageBindableRemintScenario.*" "")
mgl_itest_register_split_arms("PartialUploadOverGpuContentScenario.*" "")
# ---- P5b t2: the transform-feedback spans, the XFB object bind, the patch parameter -------
#
# MG_Remote/CONTRACT-P5B.md §2 t2. The three P5 lanes above are the REDUCED PATH's targets
# (a clear, a triangle, a persistent map); these two are the first lane entries whose GREEN
# DEPENDS ON A t2 RECORD HAVING CROSSED AND BEEN APPLIED BY THE BACKEND, which is the only
# statement a package flipping a verb can make that a unit case cannot:
#
# TessellationXfbCaptureScenario covers BOTH halves of t2 in one workload. Every case
# calls glPatchParameteri(GL_PATCH_VERTICES, n) and then draws GL_PATCHES into a
# transform-feedback capture, and asserts the CAPTURED BYTES. A patch_parameter (73)
# that did not reach the server tessellates at the previous patch size and the capture
# is the wrong length; a begin/end_stream_output (62/63) that did not reach it leaves
# the buffer holding the scenario's poison value, which is what those cases print.
# XfbCaptureBufferReuseScenario is the span family alone, across four buffer lifetimes
# (a buffer per span, one immutable-storage buffer, one respecified buffer, a
# respecification that changes the capture size). It is the case that would notice a
# span whose END crossed but whose BEGIN did not, because the second span's bytes
# would be the first span's.
#
# Both are DirectGLES only, deliberately, and the reason is measured rather than assumed:
# under Magma the capture is written into the server's resident slice and there is no route
# back, because MG_Backend/Init.cpp's ConsumedSubsystemsFor(DirectVulkan) withholds
# kMGPipeSubsystemResources, so BufferObject::SyncGpuWrites() emits no resource_readback.
# Every DirectVulkan XFB capture entry in the inproc census fails on exactly that (t2-v1.md
# §"the 51"), and it retires with P7 (Magma's resource family) / P9 (the readback carrier) -
# not here. A DirectVulkan arm of this lane would be red for a reason t2 cannot fix.
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.<arm>.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.
# Keep the original names and private logs; all six scenarios join the full
# GPU and split acceptance labels as well as their focused regression label.
mgl_itest_register_split_arms("ClientVertexArrayScenario.*" "" integration-clientarrays)
mgl_itest_register_split_arms("SyncWireScenario.*" "")
# =========================================================================================
# P3b/P4b WAVE 2-D PACKAGE D2 - OWN BLOCK. Package D1 (XFB / readback) registers its arms in
# its own block elsewhere in this file; keep the two apart so the integrator can merge both.
# =========================================================================================
#
# THE OWNER-KEYED EMISSION CURSOR, under all three transports. The claim is about WHICH
# emission cursor an upload through a texture VIEW lands on, and it is only interesting where
# the record actually crosses a wire: under monolith the drain's SubDataCount still moves but
# nothing downstream can disagree with the client's own dirty model, because there is one
# address space and one MipmapStorage. Under split the applier holds its own per-record
# pending-upload set, so a cursor that cleared the wrong flag produces a server-side level
# that never receives the texels - which is the failure this registration exists to reach.
#
# Every case draws and reads pixels, so each moves the client encoder's record ordinal and
# satisfies ScenarioFixture's armed-lane rule. The three GLES arm environments carry
# MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 (above); without it every case green-skips through
# TextureViewUsable() rather than failing - which is what the Tcp arm did until the fixture
# entry below got the same knob.
#
# ALL FOUR CASES RUN ON ALL THREE ARMS. TheOwnerUploadDrainRunsAgainAfterADrawBoundary was
# EXCLUDED BY NAME here by package D2, which found the defect but could not fix it inside its
# own footprint:
#
# after a view has been SAMPLED once, a later glTexSubImage through the OWNER's own name
# never becomes visible through the view.
#
# Package D3 fixed it and this is its red-once (rule J): the case is red on Split, Spawn AND
# Tcp at D2's head a7c06f4f with this exclusion lifted and nothing else changed, and green on
# all three with the fix. The client half was never at fault - the case's own counter
# assertions pass on the red run, so the records were emitted and the applier accepted them.
# The server's per-texture clean gate BackendTextureObject::IsDrawSyncCleanByRecord
# (MG_Backend/DirectGLES/Managers.cpp) compared the VIEW's record.Serial and
# record.PendingUploads, while an owner-side resource_subdata moves only the OWNER's
# (MG_Pipe/PipeApply.cpp ApplyTextureUpload). The gate now RESOLVES THROUGH Desc.ViewOf to the
# storage owner's record for those two clauses, which is the split equivalent of the monolith
# gate's GetContentVersion() forwarding (TextureObjectView.cpp:100-102). CONTRACT-P5E.md §5.2
# states the rule the code now implements.
mgl_itest_register_split_arms("TextureViewAliasScenario.*" "")
# ---- D2: THE UPLOAD-SHAPE GOLD, UNDER ALL THREE TRANSPORTS ------------------------------
#
# WRITTEN OUT PER ARM RATHER THAN THROUGH mgl_itest_register_split_arms, and the reason is
# structural rather than stylistic: the macro hands every arm the SHARED
# MGL_ITEST_GLES_<ARM>_ENVIRONMENT, and this case needs four things no shared list carries -
# MGITEST_TEXTURE_UPLOAD_SHAPE_LANE=1 (without it the case skips), MOBILEGL_PIPE_STATS=1 with
# PERIOD=1, MOBILEGL_PIPE_PUSH=0x1fff, and a MOBILEGL_LOG_FILE_PATH PRIVATE TO THE ARM. That
# last one is not negotiable: the library opens the log fopen(path, "w"), so two entries
# sharing a path truncate each other under `ctest -j` and the failure looks exactly like "the
# counter was never emitted". The PersistentMapArm pair above is the same shape for the same
# reason. A macro call here would produce three entries that all green-skip.
#
# WHAT THE SPLIT ARMS ADD OVER THE MONOLITH LANE. The monolith lane reads one log, because
# there is one role. Under SPAWN and TCP the client and the server are two PROCESSES with two
# independent counter sets - the client's line carries ctu= and the server's carries tex[] -
# and the `ctu == emit` comparison the whole scenario exists for is only a real comparison
# there. Under inproc it is one process with two log FILES, which is the arm that proves the
# role-derived path reading without needing two counter sets.
set(MGL_D2_TUS_FILTER "TextureUploadShapeScenario.TheEmittedUploadShapeIsRecordedAndTheTwoSidesAgree")
foreach(mglD2Arm Split Spawn Tcp)
string(TOLOWER "${mglD2Arm}" mglD2ArmLower)
set(mglD2Log "${CMAKE_CURRENT_BINARY_DIR}/texture-upload-shape-${mglD2ArmLower}-DirectGLES.log")
get_filename_component(mglD2LogName "${mglD2Log}" NAME)
set(mglD2Locks "${mglD2LogName}")
set(mglD2Extra)
if(mglD2Arm STREQUAL "Split")
set(mglD2Transport "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
elseif(mglD2Arm STREQUAL "Spawn")
set(mglD2Transport "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
else()
set(mglD2Transport "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}"
"MOBILEGL_IPC_DATA=stream" "MOBILEGL_IPC_REQUIRE_SAME_BUILD=1"
"MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1")
set(mglD2Extra FIXTURES_REQUIRED mobilegl-tcp)
# The loopback supervisor serves ONE session (ServerMain.cpp answers a second Hello
# Refuse{Busy}), and every other Tcp entry holds this lock. Without it `ctest -L
# integration-gpu -j N` ran this case beside another Tcp case and whichever client
# connected second died Refuse{Busy} -> Fatal{CapsBeforeFirstSnapshot}.
# scripts/ci/spawn_lane_parity.py and junit_tally.py --discovery now refuse any entry
# on the fixture that does not hold it.
set(mglD2Locks "${mglD2LogName}\;mobilegl-tcp")
endif()
mgl_itest_join_environment(MGL_D2_TUS_ENV_${mglD2Arm}
"MOBILEGL_BACKEND_TYPE=DirectGLES" ${mglD2Transport} "MGITEST_SPLIT_LANE=1"
"MGITEST_TEXTURE_UPLOAD_SHAPE_LANE=1" "MOBILEGL_PIPE_PUSH=0x1fff"
"MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
"MOBILEGL_LOG_FILE_PATH=${mglD2Log}"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.${mglD2Arm}.TextureUploadShape."
TEST_FILTER "${MGL_D2_TUS_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-${mglD2ArmLower}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK "${mglD2Locks}"
${mglD2Extra}
ENVIRONMENT "${MGL_D2_TUS_ENV_${mglD2Arm}}"
)
endforeach()
# ---- P7 CI: THE SPAWN CLIENT'S COLD-START BUDGET ----------------------------------------
#
# A spawned server brings its native backend up lazily, inside the first surface creation
# (Espryt) or the first MakeCurrent (Magma). On loaded CI runners that took longer than the
# client's 5 s steady reply bound, and retrace-split's spawn legs died on "no SurfaceReply for
# CreatePbufferSurface seq 2" / "for MakeCurrent seq 3" while the server was about to answer.
# ClientSession now gives those two kinds of op MOBILEGL_IPC_COLD_START_MS (default 20 s)
# until the session's first MakeCurrent is answered ok.
#
# These two entries are that rule's red-once: the server's test lever
# MOBILEGL_TEST_DELAY_FIRST_BRINGUP_MS holds the first surface creation and the first
# MakeCurrent back by 6 s each - past the steady bound, which stays at its 5 s default. With
# the cold-start budget both ops land inside 20 s and the case is green. Against the client as
# it was before (every op on a hard-coded 5 s), with the budget selection removed, or with the
# cold-start default lowered to the old 5 s, the first one times out and the case reds on
# "remote spawn bring-up failed" - the CI failure in miniature. A 3 s lever under a 2 s steady
# knob was faster but proved less: the pre-fix client never read MOBILEGL_IPC_CONTROL_TIMEOUT_MS,
# so its 5 s bound outlasted the lever and the entries were green at 14e1c8b9 (measured).
# SINCE p7/spawnhang THEY ARE NO LONGER THE BUDGET SELECTION'S RED-ONCE: a 20 s bring-up outran
# the cold-start budget too (run 35912252677), so both budgets now bound SILENCE - the server
# reports Wire::SurfaceProgress every 250 ms while it runs the op, and each report restarts the
# client's budget. These entries stay as the end-to-end check that a held bring-up is waited
# for on both backends; the mechanism's red-once is ServerSpawnTest's cold-bring-up case (unit).
# Each entry takes ~25 s, because the harness's pre-flight child brings a server up as well.
# NOT on integration-spawn: this is not a copy of the split lane (spawn_lane_parity.py). The
# DirectVulkan entry does carry integration-gpu, unlike the Magma arms' informational tiers
# below: it is one expected-GREEN case, and Magma's bring-up is the MakeCurrent half.
set(MGL_COLDSTART_FILTER "ClearThenReadPixelsScenario.ClearWithNoDrawIsVisibleToDefaultFramebufferReadPixels")
foreach(mglColdBackend DirectGLES DirectVulkan)
if(mglColdBackend STREQUAL "DirectVulkan")
set(mglColdDriverEnv ${MGL_ITEST_VULKAN_ENV})
else()
set(mglColdDriverEnv ${MGL_ITEST_COMMON_ENV})
endif()
mgl_itest_join_environment(MGL_COLDSTART_ENV_${mglColdBackend}
"MOBILEGL_BACKEND_TYPE=${mglColdBackend}" ${MGL_ITEST_SPAWN_ARM_TRANSPORT_ENV}
"MGITEST_SPLIT_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
"MOBILEGL_TEST_DELAY_FIRST_BRINGUP_MS=6000"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/cold-start-spawn-${mglColdBackend}.log"
${MGL_ITEST_CAPABILITY_ENV} ${mglColdDriverEnv})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglColdBackend}.Spawn.ColdStart."
TEST_FILTER "${MGL_COLDSTART_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-cold-start"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_COLDSTART_ENV_${mglColdBackend}}"
)
endforeach()
# ---- D2: THE TEXTURE / PROGRAM SPLIT-SCENARIO CENSUS ------------------------------------
#
# PLAN-PH-P34B-P7.md 1.2, "门:纹理 / program 场景 split 覆盖". Each candidate was run once
# under MOBILEGL_TRANSPORT=inproc on build-split and its FIRST BLOCKER recorded; the row per
# scenario x backend x blocker is in notes/p34b/split-scenario-census.md. What follows is the
# result of that census, not a guess: every scenario listed here passed, and every case that
# did not is excluded BY NAME below with its blocker.
#
# D1 owns PixelStoreSweep, DepthStencilReadbackMatrix, PackedWordReadback and
# LayeredTextureReadback - they are not here.
#
# DIRECTVULKAN ARMS DEFAULT TO NONE, and that is not an omission. The macro records every
# call and the informational tier-2 block at the end of this file replays all of them on
# DirectVulkan under integration-magma-all-{split,spawn,tcp} - so these scenarios DO get a
# Magma reading, just not a gating one. Gating them there would be asserting P7 wave 2's
# exit gate 1 from inside a P3b/P4b package, on a backend whose own @P7 named refusals are
# still being retired in waves A/B/C.
set(MGL_SPLIT_D2_SCENARIOS
TextureViewScenario # glTextureView end to end, 10 cases
TextureParamsWithoutASamplerViewScenario # G9's four cases; also settles the debt-table row
SampledSetStalenessScenario # 2 cases
ImageSizeAfterRespecScenario # 1 case
ImageTargetKindScenario # 29 cases
IntegerBorderColorScenario # 6 cases
SwizzleAccessRoutineScenario # 4 cases
PostLinkAttachScenario # 2 cases
RelinkStageSetScenario # 3 cases
UniformInitializerScenario # 3 cases
Glsl420DeclarationScenario # 6 cases
IoBlockNameCollisionScenario) # 2 cases
# NO PER-SCENARIO FILTER INDIRECTION, unlike the d1 and i1 blocks above: every scenario here
# is registered whole, because the census found no case in any of them that needs excluding.
# The d1/i1 shape (a MGL_SPLIT_<pkg>_FILTER_<Scenario> variable consulted per entry) is what
# to reach for the day one does; carrying an `if(DEFINED ...)` that is never true today would
# be a branch no run takes.
foreach(mglItestD2Scenario IN LISTS MGL_SPLIT_D2_SCENARIOS)
mgl_itest_register_split_arms("${mglItestD2Scenario}.*" "")
endforeach()
# P7 gate 5 (g5-msrbo): AN EMPTY TEXTURE LEVEL. glTexImage*D with a zero extent is legal GL
# and dEQP's resetStateGLCore issues it for every target after every case; PH-4's extent
# carrier refused it as ProtocolCorruption on the apply thread, so no KHR-GL case could
# finish on a split arm. Backend-agnostic (the refusal was in MGPipeApplyResourceRespecify),
# so the DirectGLES gated arms carry it here and the Magma gated lanes below carry it too.
mgl_itest_register_split_arms("EmptyTextureLevelScenario.*" "")
# ProgramPipelineScenario BEYOND *StorageBlock*: the i1 block above already registers the two
# storage-block cases. The other nine are pure name/state cases that draw nothing, and
# ScenarioFixture's armed-lane rule (the client encoder's record ordinal must move) makes a
# case that produced no record RED for having nothing to say - which is the rule working, not
# a defect. They stay unregistered for that reason and are listed in the census note.
# The split half of the counting pair. MGITEST_PERSISTENT_MAP_ARM=emulated is R-6: under split
# the adopt tier is pinned at T2, the resource owner declines every acquisition and the client
# pushes the mapping's dirty blocks - so pmap must be non-zero and mpr must be the monolith
# lane's number. pmap == 0 here means MGPipeApplyMapPersistent handed back a pointer, which is
# exit gate E3(d) failing, and under inproc that failure is invisible in pixels.
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_PMAP_ARM_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MGITEST_PMAP_LANE=1" "MGITEST_PERSISTENT_MAP_ARM=emulated"
"MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/persistent-map-arm-split-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.PersistentMapArm."
TEST_FILTER "PersistentCoherentMapScenario.TheMapLandsInTheArmItsLaneDeclares"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK persistent-map-arm-split-DirectGLES.log
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_PMAP_ARM_ENVIRONMENT}"
)
# --- EXIT GATE E3(e): the same checks with a ring small enough to force back-pressure -----
#
# BRIEF 7 E3(e) - "以上五条再跑一遍 ring 小到足以至少发生一次背压等待的配置" - was missing from
# the first cut of this package and missing from its report (review finding M-7). It is a
# LANE, not a new scenario: the same three split scenarios with SEG_CMD and SEG_STAGE at their
# floor, so a workload that fits comfortably in the 8 MiB / 32 MiB defaults has to wrap and
# wait at least once.
#
# 1 MiB is ConfigLoader's minimum for both (Config.h / ConfigLoader.cpp:363-364, floors of 1
# rather than 0 because a ring caps ONE record at half its size). That caps a record at 512
# KiB, which every record on the reduced path is far under, so the ring is legal and small
# rather than unusable.
#
# WHAT THIS LANE DOES NOT YET ASSERT, stated rather than implied: that a back-pressure wait
# ACTUALLY happened. That needs a counter only package s1 can publish (a producer-parked or
# ring-full tally on RingControl); until it exists this lane proves the five checks survive a
# small ring, not that the small ring bit. The gap is named in t1-v1.md's debts rather than
# left for someone to discover from a green.
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_SMALL_RING_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MGITEST_SMALL_RING_LANE=1" "MOBILEGL_IPC_RING_MB=1" "MOBILEGL_IPC_STAGE_MB=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
set(MGL_SPLIT_SMALL_RING_SCENARIOS ClearThenReadPixelsScenario TriangleScenario
PersistentCoherentMapScenario)
foreach(mglItestSmallRingScenario IN LISTS MGL_SPLIT_SMALL_RING_SCENARIOS)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.SmallRing."
TEST_LIST "MGL_SPLIT_SMALL_${mglItestSmallRingScenario}_TESTS"
TEST_FILTER "${mglItestSmallRingScenario}.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_SMALL_RING_ENVIRONMENT}"
)
endforeach()
# ---- P5e package pa: THE STRICT LANE GETS ENTRIES OF ITS OWN ------------------------------
#
# pa retired the two per-draw program rows - Fatal{UnmigratedPipeInput,
# "GetProgramForDraw@DrawArrays"} and "...GetProgramForDispatch@DispatchCompute", 69 of the
# 109 entries the strict lane was red on. NOTHING GATED THEM. MOBILEGL_IPC_STRICT_ERRORS=1 is
# a knob the phase's gate driver sets by hand, no REGISTERED entry exports it, and package
# pg's declared red-once for this exact marker never landed - so the row could come back and
# every gate would stay green. That is ID-109's finding in miniature: the gap was never a
# missing test case, it was a missing gated ENTRY for a whole reading.
#
# WHICH SCENARIOS MAY JOIN is decided by the knob itself: under it every BARRIER-PULLED read
# is Fatal, and most split scenarios end in a readback, whose GetFramebufferBindingSlot@ReadPixels
# is an allowlisted row that only P7 retires. So a scenario is eligible exactly when it
# reaches PrepareForDraw / PrepareForCompute and then does NOT read pixels back. Two do, one
# per half of pa, and both were red with pa's own marker before it landed:
# * MultiDrawScenario.BaseVertexDrawsRejectMalformedArguments - the DRAW half; it prepares a
# draw and then asserts on GL errors rather than on pixels.
# * AtomicCounterScenario.* - the DISPATCH half, and all three cases were
# GetProgramForDispatch@DispatchCompute entries.
#
# LABELS IS integration-split ALONE, deliberately, and it is not the hole ID-109 names. That
# hole was a runtime ARM with no entry anywhere; here the monolith arm of these same scenarios
# is registered under DirectGLES. already and this knob is a no-op on it - a monolith client
# fills and stamps all 63 fields at every verb, so no read is unfresh and nothing can trip.
# An entry that cannot fail for the reason it exists is worse than none (R-16), so this lane
# names the arm it is for in its own prefix. The F1. lane sets the same precedent.
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_STRICT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_IPC_STRICT_ERRORS=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.StrictProgramArm."
TEST_LIST MGL_SPLIT_PA_STRICT_DRAW_TESTS
TEST_FILTER "MultiDrawScenario.BaseVertexDrawsRejectMalformedArguments"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_STRICT_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.StrictProgramArm."
TEST_LIST MGL_SPLIT_PA_STRICT_DISPATCH_TESTS
TEST_FILTER "AtomicCounterScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_STRICT_ENVIRONMENT}"
)
# The configure_file that used to sit here MOVED TO THE END OF THIS FILE (P6 `t6`).
#
# It substitutes @MGL_SPLIT_ARM_TEST_LISTS@, which the registration macro appends to - so
# running it here captured only the calls made ABOVE this line and silently dropped the F1
# and Ct blocks below it. SplitLogPaths.PrivateAndDistinct is what caught that, naming
# F1WireScenario.ClearBufferfiPixels; the generated file now sees every call.
# Python is mandatory for this split integration gate (also used by the CI controls).
# Do not silently omit the ownership check when the interpreter is unavailable.
find_package(Python3 REQUIRED COMPONENTS Interpreter)
add_test(NAME SplitLogPaths.PrivateAndDistinct
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_CURRENT_SOURCE_DIR}/Harness/split_log_paths.py"
check "${CMAKE_CTEST_COMMAND}" "${CMAKE_BINARY_DIR}")
set_tests_properties(SplitLogPaths.PrivateAndDistinct PROPERTIES LABELS "integration-split")
endif()
# f1: split-only source keeps the monolith registry unchanged.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/F1WireScenario.cpp)
foreach(f1Slot ClearBufferfi ClearBufferfv ClearBufferiv ClearBufferuiv ClearNamedFramebufferfi ClearNamedFramebufferfv ClearNamedFramebufferiv ClearNamedFramebufferuiv CopyTexImage2D CopyTexSubImage2D GenerateMipmap GenerateMipmapPackedFloat GenerateMipmapDepth)
mgl_itest_register_split_arms("F1WireScenario.${f1Slot}Pixels" "F1.")
endforeach()
# THE TWO PACK-STATE CASES OF F1, which are not ${slot}Pixels-shaped (P3b/P4b espryt D1
# slice 4). ID-49 splits a readback in two: the server reads with NEUTRAL pack state into a
# tight w*h*bpp reply, and the CLIENT scatters those rows into the application's destination
# per its own GL_PACK_*. Only the client half has ever been exercised by a unit case over
# ScatterTightReadbackIntoPackState; these two run the whole seam, one for the padding a
# non-default pack state must leave untouched and one for the overflow that has to be refused
# BEFORE anything is written.
mgl_itest_register_split_arms(
"F1WireScenario.TextureAndFramebufferReadsPreservePackBufferPadding" "F1.")
mgl_itest_register_split_arms(
"F1WireScenario.TextureReadbackRejectsPackedDestinationOverflowBeforeWriting" "F1.")
# P5f fm: the framebuffer/copy/mipmap verbs now consume server records on Magma too.
#
# P7 package L: THE SAME CASES ON ALL THREE TRANSPORTS. The flavour is everything this lane
# is except the transport, which the arm now supplies - so the inproc arm is byte-for-byte
# the lane P6.5 left green (same names, same labels, same log paths) and the two new arms
# differ from it in exactly one dimension. That is what makes a red here readable: it is a
# TRANSPORT fact, because nothing else changed.
#
# ${MGL_ITEST_VULKAN_ENV} AND NOT ${MGL_ITEST_COMMON_ENV} (P7 package L, integrator ruling).
# Until this ruling the six Magma lanes appended the COMMON list, so the monolith
# `DirectVulkan.` arm ran with VK_ICD_FILENAMES pinned and the three lavapipe iterationRP
# repairs forced on while these 73 entries ran against whatever ICD the loader happened to
# find first, with the repairs at their device auto-detection default. That is not a
# semantic difference between two lanes, it is a latent flake: the day a runner or a
# workstation grows a second ICD, this lane measures a different driver from the gate it
# mirrors and nothing in its output says so. Consistency over "meaning unchanged" - and the
# re-run after the change is part of the ruling: integration-magma-split stayed 71/0/2.
set(MGL_ITEST_MAGMA_WIRE_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
# Every entry here is green on the inproc arm, R11F_G11F_B10F packed-float mip generation
# included: the GPU shader blit retires the named native-format refusal, so
# GenerateMipmapPackedFloatPixels carries its siblings' label and their pixels assertion.
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(mglItestMagmaWireEnvironment
${MGL_ITEST_MAGMA_WIRE_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(fmSlot ComputeImageStoreThroughViewPreservesOtherRootLayer EnabledVertexBufferDrawKeepsNamedP7Fatal SrgbDrawTracksFramebufferConversion Texture1DFramebufferClearPixels VertexIdSamplerAndScalarUniformPixels ComputeImageStoreFramebufferPixels PartialTextureUploadPreservesGpuClearPixels TextureViewClearTargetsItsRootMipAndLayer ClearBufferfiPixels ClearBufferfvPixels ClearBufferivPixels ClearBufferuivPixels ClearNamedFramebufferfiPixels ClearNamedFramebufferfvPixels ClearNamedFramebufferivPixels ClearNamedFramebufferuivPixels CopyTexImage2DPixels CopyTexSubImage2DPixels GenerateMipmapPixels GenerateMipmapPackedFloatPixels GenerateMipmapDepthPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "F1WireScenario.${fmSlot}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm${mglItestArmLogTag}-${fmSlot}.log")
endforeach()
foreach(fmCase ClipDistanceScenario.AnEnabledClipDistanceRemovesTheNegativeHalf
ClipDistanceScenario.ADisabledClipDistanceRemovesNothing
ClipDistanceScenario.TheEnablesAreIndependentPerDistance
CopyImageLayeredScenario.ArrayToArrayCopiesEverySlice
CopyImageLayeredScenario.ArrayToArrayHonoursDifferentLayerOffsets
CopyImageLayeredScenario.VolumeToVolumeHonoursNonZeroZ
CopyImageLayeredScenario.VolumeToVolumeAtNonZeroMipLevel
CopyImageLayeredScenario.ArrayToVolumeCopiesEverySlice
CopyImageLayeredScenario.VolumeToArrayCopiesEverySlice)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "${fmCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm${mglItestArmLogTag}-${fmCase}.log")
endforeach()
# P7 gate 5 (g5-msrbo): the empty-level pair, on the gated Magma lanes as well - the CTS
# arm gate 5 measures is inproc x DirectVulkan, and every one of its cases ends in the
# empty-level reset this scenario reproduces.
foreach(emptyLevelCase TheCtsStateResetDefinesEveryDefaultTargetEmpty
ALevelDefinedEmptyThenRedefinedCarriesTheNewTexels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "EmptyTextureLevelScenario.${emptyLevelCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-emptylevel${mglItestArmLogTag}-${emptyLevelCase}.log")
endforeach()
# ---- P7 wave 2-B: THE TWO SHADER MIP ARMS, FORCED ------------------------------------
#
# WHY A KNOB AND NOT A FORMAT. The refusal these two entries cover
# (`Magma:mipmap-shader-format-or-shape`) killed two Iris cases on an Adreno 830v2 and
# has never once fired on this host, because lavapipe reports BLIT_SRC|BLIT_DST for
# every colour format the integration binary can create - so GenerateWireMipmap takes
# its NATIVE arm for all of them and neither shader arm is reachable by choosing a
# format. `GenerateMipmapPackedFloatPixels` next door looks like it covers the shader
# arm and does not: R11F_G11F_B10F blits natively here too.
# MGITEST_MAGMA_FORCE_SHADER_MIPMAP drops that arm instead, one tier per shape, so the
# host lane exercises the code the device actually runs.
#
# ITS OWN ENTRIES RATHER THAN A LANE-WIDE FLIP, for the reason the strict-arming entry
# gives: the knob changes how EVERY mipmap in the process is generated, so putting it in
# the shared Fm environment would silently retarget GenerateMipmapPixels,
# GenerateMipmapPackedFloatPixels, GenerateMipmapDepthPixels and the two base/view cases
# as well - four green entries that would stop measuring the arm they were written for.
# ---- P7 wave 2-B2: A SERVER-SIDE KNOB HAS NO TCP ARM, AND THAT IS STRUCTURAL ---------
#
# Every MGITEST_MAGMA_FORCE_* knob in this block is read BY THE SERVER
# (WireFramebuffer.inc's three `std::getenv` readers run on the apply thread). A ctest
# ENVIRONMENT property reaches the process ctest starts - the CLIENT - and the two arms
# differ in where the server comes from:
# inproc the server is a thread of that same process, so it sees the knob;
# spawn ServerSpawn.cpp copies ::environ into the child, so it sees the knob;
# tcp the server is the LANE-WIDE TcpServer.Start fixture, started once from the
# fixture's own os.environ (scripts/ci/tcp_server_fixture.py) long before any
# case runs, and it forks a session child per Hello. Nothing a per-test
# ENVIRONMENT says can reach it.
#
# So a tcp copy of a knob entry does not exercise the arm it names - it runs the
# DEFAULT arm under a name that claims otherwise, which for ShaderMip is precisely what
# that case's own skip message says must not happen ("this case would assert the native
# blit twice over"). MEASURED, not deduced: a temporary fatal in each of the three
# readers killed all five knob=1 entries on split and on spawn and left ALL FIVE GREEN
# on tcp.
#
# Registering them on split+spawn only is therefore a coverage statement, not a gap, and
# it is NAMED in scripts/ci/spawn_lane_parity.py (MAGMA_SERVER_ENV_KNOB_NO_TCP) the way
# MAGMA_INPROC_ONLY and MONOLITH_ONLY are, so the parity gate keeps its teeth for
# everything else. The knob=0 twins (DefaultBlitShape0, MsResolve0) DO stay on tcp: zero
# is the default, so those entries mean the same thing on all three arms.
#
# Making the tcp lane able to carry these would need the fixture to take a per-case
# server environment - a supervisor control, not a ctest property - and that is a debt,
# recorded in notes/p7/magma-b2.md §6.
set(mglItestServerEnvKnobArm TRUE)
if(mglItestArm STREQUAL "Tcp")
set(mglItestServerEnvKnobArm FALSE)
endif()
foreach(shaderMipTier 1 2)
if(NOT mglItestServerEnvKnobArm)
continue()
endif()
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.ShaderMip${shaderMipTier}."
TEST_FILTER "F1WireScenario.GenerateMipmapWithoutNativeBlitPixels"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_MIPMAP=${shaderMipTier}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-shadermip${mglItestArmLogTag}-tier${shaderMipTier}.log")
endforeach()
# The DEPTH half of the same knob (CONTRACT-P7 §5.1 (A)). ONE TIER, not two: the depth
# pass renders into a depth ATTACHMENT view of the destination level, which a depth
# image always has usage for - there is no "cannot be attached" shape to force, so
# tier 2 would register a second copy of tier 1's run. Split+spawn only, for the
# server-side-knob reason above.
if(mglItestServerEnvKnobArm)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.DepthMip."
TEST_FILTER "F1WireScenario.GenerateMipmapDepthWithoutNativeBlitPixels"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_MIPMAP=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-depthmip${mglItestArmLogTag}.log")
endif()
# NO KNOB on the decline: it is decided on the aspect before the blit-support question
# is asked, so the plain Fm environment reaches it on every driver.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "F1WireScenario.GenerateMipmapDepthStencilDeclinesAndKeepsTheSession"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-dsmipdecline${mglItestArmLogTag}.log")
# `copy-image-in-place@P7`'s retirement and its one surviving decline. SPLIT-ONLY in the
# strongest sense: the monolith arm declines every in-place copy, so there is no
# DirectVulkan. entry to register these beside - the wire arm is the one that performs
# them, which is what §3.2 asks for.
# ---- P7 wave 2-B, EXIT GATE 3: the readback must not depend on how long a pipeline
# takes to create. --------------------------------------------------------------------
#
# The Redmi's OpenRA divergence reproduces only with a COLD driver pipeline cache (three
# cleared-cache runs: a bit-identical ssim 0.976494 / 14658 mismatched pixels; warm:
# 1.000000 from the second run on). What a cold cache changes is how long
# vkCreateGraphicsPipelines takes on the apply thread, and
# MOBILEGL_TEST_PIPELINE_CREATE_DELAY_MS buys that time on a host whose cache is warm.
#
# THESE ENTRIES ARE A REGRESSION GATE, NOT THE REPRODUCTION. The delay alone does NOT
# make lavapipe diverge, and the reason is in WireFramebuffer.inc's
# RecordWireReadbackWriteBarrier: the host's default framebuffer is tracked as
# VK_IMAGE_LAYOUT_GENERAL at the readback, which takes GetImageTransitionSourceState's
# `default:` arm (ALL_COMMANDS / MEMORY_WRITE) and orders the copy by accident. What these
# entries do pin is that a readback which follows a draw still returns that draw's pixels
# when every pipeline creation on the path costs 25 ms - i.e. that the answer does not
# move with timing.
foreach(pipelineDelayCase VertexIdSamplerAndScalarUniformPixels
ComputeImageStoreFramebufferPixels
GenerateMipmapPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.PipelineDelay."
TEST_FILTER "F1WireScenario.${pipelineDelayCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_TEST_PIPELINE_CREATE_DELAY_MS=25\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-pipelinedelay${mglItestArmLogTag}-${pipelineDelayCase}.log")
endforeach()
# ---- P7 wave 2 package B3, EXIT GATE 3: the streamed `glBufferSubData -> draw` pair.
#
# TWO ENTRIES OVER ONE CASE, for the reason the ShaderMip pair gives. The plain entry is
# a regression gate that runs on every driver. The forced entry is the red-once of the
# DEFENCE term: it makes the serial half of VkBufferManager's busy predicate answer
# "idle" - the state an unsound completed-serial floor put the wire arm into on the
# device - so only the submission-fence half is left to order the copy. It does NOT
# cover the floor fix itself (forcing the serial term bypasses the floor entirely); the
# floor's lane is the OpenRA split retrace, which run_trace_case.cmake reds on any
# "MGWIRE-FLOOR unsound-serial-complete" line.
#
# ITS OWN ENTRY RATHER THAN A LANE-WIDE FLIP: the knob changes how EVERY streamed buffer
# write in the process is answered, so putting it in the shared Fm environment would
# retarget every other draw case in this lane.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "F1WireScenario.StreamedBufferSubDataBeforeEachDrawIsOrdered"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-streamedsubdata${mglItestArmLogTag}.log")
# SPLIT AND SPAWN ONLY - a parity exception, named in scripts/ci/spawn_lane_parity.py
# (MAGMA_SERVER_ENV_KNOB_NO_TCP, the same list as the B2 knobs above), not an omission.
# The knob is read by the SERVER, and the tcp arm's server is the lane fixture
# (scripts/ci/tcp_server_fixture.py) started once from its own environment: an
# entry-level ENVIRONMENT never reaches it, so a Tcp.StaleSerial. entry would run the
# plain Fm case under a name that claims the knob, and could never red. The inproc arm
# hosts the server in the test process and the spawn arm's server inherits the client's
# environment, so on those two the knob is real.
if(mglItestServerEnvKnobArm)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.StaleSerial."
TEST_FILTER "F1WireScenario.StreamedBufferSubDataBeforeEachDrawIsOrdered"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-streamedsubdata-stale${mglItestArmLogTag}.log")
endif()
# `default-color-blit-shape@P7`'s retirement. TWO ENTRIES OVER ONE CASE, and the second
# is the only way its arm is reachable here: every surface this lane creates reports
# VK_SURFACE_TRANSFORM_IDENTITY, so the scratch path that exists FOR rotation would
# never run. Forced onto an identity surface it must produce the SAME pixels as the
# fall-through, which is what the shared assertions check.
# The knob=1 copy is split+spawn only (the server-side-knob note above); knob=0 is the
# default and means the same thing on all three arms, so it keeps its tcp entry.
foreach(defaultBlitScratch 0 1)
if(defaultBlitScratch AND NOT mglItestServerEnvKnobArm)
continue()
endif()
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.DefaultBlitShape${defaultBlitScratch}."
TEST_FILTER "F1WireScenario.ColorBlitToDefaultFromANonSampleableSourceDegrades"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_DEFAULT_BLIT_SCRATCH=${defaultBlitScratch}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-defaultblit${mglItestArmLogTag}-scratch${defaultBlitScratch}.log")
endforeach()
# ---- P7 wave 2-B2: `multisample-blit-shape@P7`'s retirement and its decline ----------
#
# SPLIT-ONLY, like the in-place copy pair below and for the same reason: the retired arm
# does something the monolith arm does not. A scaled multisample colour blit takes the
# monolith's `vkCmdResolveImage` at 1:1 into the destination's offset - the scale is
# dropped - so there is no `DirectVulkan.` reading to register these beside, and an
# equality between the two arms would be an assertion that the wire arm is as wrong.
#
# NO KNOB: every driver that can host a 4x multisample RGBA8 renderbuffer reaches both
# entries with the plain Fm environment, and one that cannot says so as a SKIP.
foreach(multisampleBlitCase MultisampleColorBlitScalesAndFlipsThroughTheResolveScratch
MultisampleBlitOntoAMultisampleDestinationDeclinesAndKeepsTheSession
MultisampleBlitFromASingleSampleSourceDeclinesAndKeepsTheSession)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.MsBlit."
TEST_FILTER "F1WireScenario.${multisampleBlitCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-msblit${mglItestArmLogTag}-${multisampleBlitCase}.log")
endforeach()
# ---- P7 wave 2-B2: `multisample-blit-aspect@P7`'s retirement, BOTH ARMS ---------------
#
# THE CASE IS PROMOTED, NOT WRITTEN. DepthStencilReadbackMatrixScenario already owns the
# observable - clear a 4x multisample DEPTH24_STENCIL8 renderbuffer, resolve it into a
# single-sampled framebuffer with glBlitFramebuffer, read both aspects back, and check
# that a depth-only resolve left the destination's stencil alone and vice versa - and it
# already ran on these three arms in the INFORMATIONAL tier (`…Full.`). What it did not
# have was a gated entry, which is what CONTRACT-P7 §3.2's aspect row needs.
#
# TWO ENTRIES OVER ONE CASE, and the second is the only way its arm is reachable here:
# lavapipe carries VK_KHR_create_renderpass2 AND VK_KHR_depth_stencil_resolve, so the
# extension arm answers every resolve on this host and the shader pass - which exists FOR
# the device that has neither, where the session used to end at
# `Magma:multisample-depth-resolve-capability` - would never execute.
# MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE drops the extension arm, and the two entries
# then assert the same depth values and the same stencil indices, which is the whole
# claim: sample zero either way.
#
# ITS OWN ENTRIES RATHER THAN A LANE-WIDE FLIP, the shader-mip block's reason: the knob
# changes how EVERY depth/stencil resolve in the process is performed.
foreach(shaderDepthResolve 0 1)
# Same split+spawn restriction, same reason, same parity exception: the knob is read
# on the server and the tcp server is the lane fixture. MsResolve0 stays everywhere.
if(shaderDepthResolve AND NOT mglItestServerEnvKnobArm)
continue()
endif()
# P7 gate 5 (g5-msprobe): MsResolve0 on split and spawn also pins the REAL resolve probe
# on this host - it must run at the server's bring-up, find lavapipe's no-draw resolve
# render pass clean, and leave that pass first. MGITEST_EXPECT_DEPTH_RESOLVE_PROBE is a
# marker only the scenario reads (DepthStencilReadbackMatrixScenario::
# ExpectTheResolveArmWhereTheLaneAsks), and only where the server's private log belongs
# to the entry - the tcp server is the lane fixture, so its MsResolve0 asserts pixels only.
set(msResolveProbeMarker "")
if(NOT shaderDepthResolve AND mglItestServerEnvKnobArm)
set(msResolveProbeMarker "\;MGITEST_EXPECT_DEPTH_RESOLVE_PROBE=clean")
endif()
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.MsResolve${shaderDepthResolve}."
TEST_FILTER "DepthStencilReadbackMatrixScenario.AResolvedMultisampleDepthReadsBackFromTheDestination"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE=${shaderDepthResolve}${msResolveProbeMarker}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-msresolve${mglItestArmLogTag}-shader${shaderDepthResolve}.log")
endforeach()
# ---- P7 gate 5 (g5-msrbo): the SINGLE-SAMPLED depth/stencil blit ----------------------
#
# KHR-GL46.direct_state_access.renderbuffers_storage_multisample's samples == 0 leg, every
# depth/stencil format: the wire arm moved every single-sample depth/stencil aspect with
# vkCmdBlitImage where the monolith copies at 1:1, and for one aspect of a packed format
# that moved the whole native word (a depth-only blit replaced the destination's stencil
# on lavapipe). NO KNOB: the packed-aspect leg is red on lavapipe without the copy arm
# (measured there only - a driver whose one-aspect blit keeps the other aspect stays green
# without it), and nothing in it is read on the server, so all three arms carry it.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.DsBlit."
TEST_FILTER "DepthStencilReadbackMatrixScenario.ASingleSampledDepthStencilBlitCopiesEveryAspect"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-dsblit${mglItestArmLogTag}.log")
# P7 wave 2-B2 (review round): a FLIPPED multisample depth/stencil resolve is a legal blit
# that used to end the session, and a SCALED one is INVALID_OPERATION that used to end it
# too. Both shapes are decided on the rectangles, before any capability question, so this
# entry needs NO knob and runs on all three arms.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.MsFlip."
TEST_FILTER "DepthStencilReadbackMatrixScenario.AFlippedMultisampleResolveMirrorsTheBandsAndAScaleDeclines"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-msflip${mglItestArmLogTag}.log")
# ITS KNOB TWIN (review round 2). Knob-free, lavapipe answers every resolve through the
# VK_KHR_depth_stencil_resolve arm, so the shader arm's min-corner rectangle under a
# flip - the device WITHOUT the extension - never ran. MsFlip1 forces it. Split+spawn
# only, the server-side-knob reason above, named in spawn_lane_parity.py's
# MAGMA_SERVER_ENV_KNOB_NO_TCP; the knob-free MsFlip. keeps all three arms.
if(mglItestServerEnvKnobArm)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.MsFlip1."
TEST_FILTER "DepthStencilReadbackMatrixScenario.AFlippedMultisampleResolveMirrorsTheBandsAndAScaleDeclines"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-msflip${mglItestArmLogTag}-shader1.log")
endif()
# ---- P7 gate 5 (g5-msrbo review round, g5-msprobe): THE DEFECT'S ARM ORDER, ON A HOST --
#
# What made KHR-GL46.direct_state_access.renderbuffers_storage_multisample pass on the
# Redmi is an arm ORDER: where the server's resolve probe measures the no-draw
# VK_KHR_depth_stencil_resolve render pass leaving its target unwritten (the Adreno 830's
# does) ResolveWireDepthStencil takes the shader pass first. Lavapipe resolves correctly
# through both arms - its probe verdict is clean, which MsResolve0 above pins - so no
# pixel on this host can see the order. MGITEST_MAGMA_DEPTH_RESOLVE_PROBE=bug replaces the
# probe's MEASUREMENT with a canned "the render pass wrote nothing, the shader control
# resolved" one (VulkanRenderer::ArmWireDepthResolveOrder) - nothing else reads it - and the
# two resolve cases then assert their pixels AND that the server's private log says the
# verdict was the defect, the shader pass resolved and the render pass never did
# (DepthStencilReadbackMatrixScenario::ExpectTheResolveArmWhereTheLaneAsks, which asserts
# the same of the MsResolve1./MsFlip1. entries above).
#
# Split+spawn only, the server-side-knob reason above, named in spawn_lane_parity.py's
# MAGMA_SERVER_ENV_KNOB_NO_TCP.
#
# Red once (executed, reverted): EvaluateWireDepthResolveProbe (WireDepthResolveArm.h)
# answering Clean for every measurement - the probe's detection switched off - fails all
# four entries on the arm assertions with their pixels green.
if(mglItestServerEnvKnobArm)
foreach(probeBugCase MsResolveBug:AResolvedMultisampleDepthReadsBackFromTheDestination
MsFlipBug:AFlippedMultisampleResolveMirrorsTheBandsAndAScaleDeclines)
string(REPLACE ":" ";" probeBugPair "${probeBugCase}")
list(GET probeBugPair 0 probeBugTail)
list(GET probeBugPair 1 probeBugTest)
string(TOLOWER "${probeBugTail}" probeBugLog)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.${probeBugTail}."
TEST_FILTER "DepthStencilReadbackMatrixScenario.${probeBugTest}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_DEPTH_RESOLVE_PROBE=bug\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-${probeBugLog}${mglItestArmLogTag}.log")
endforeach()
endif()
# ---- P7 gate 5 (g5-msprobe critic): THE REAL PROBE'S NEGATIVE CONTROL ------------------
#
# The Bug entries above hand the arm choice a CANNED measurement, and MsResolve0 only pins
# lavapipe's clean answer, so no entry could see the REAL probe (WireDepthResolveProbe.cpp -
# its recording, readback and tally) stop detecting a render pass that writes nothing.
# MGITEST_MAGMA_DEPTH_RESOLVE_PROBE=elide-subject runs the real probe with its render-pass
# resolve left unrecorded - the subject's target keeps the sentinel, the Adreno 830's
# reading - while the shader control runs as always. The entry asserts the case's pixels,
# that the real measurement reports verdict=render-pass-resolve-broken with a reading whose
# render pass kept the sentinel beside a resolving control, and that the shader pass
# resolved and the render pass never did
# (DepthStencilReadbackMatrixScenario::ExpectTheResolveArmWhereTheLaneAsks).
#
# Split+spawn only, the server-side-knob reason above, named in spawn_lane_parity.py's
# MAGMA_SERVER_ENV_KNOB_NO_TCP.
#
# Red once (executed, reverted): EvaluateWireDepthResolveProbe answering Clean for every
# measurement fails both entries; the probe's subject tally counting every texel as
# resolved fails both entries while the four Bug entries stay green.
if(mglItestServerEnvKnobArm)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.MsResolveElide."
TEST_FILTER "DepthStencilReadbackMatrixScenario.AResolvedMultisampleDepthReadsBackFromTheDestination"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_DEPTH_RESOLVE_PROBE=elide-subject\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-msresolveelide${mglItestArmLogTag}.log")
endif()
foreach(inPlaceCase CopyImageInPlaceAcrossLevelsAndLayers
CopyImageInPlaceOverlapDeclinesAndLeavesTheLevelAlone)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.CopyInPlace."
TEST_FILTER "F1WireScenario.${inPlaceCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-copyinplace${mglItestArmLogTag}-${inPlaceCase}.log")
endforeach()
# ---- P7 gate 5 (g5-imgwin): the image-unit window ------------------------------------
#
# KHR-GL46.shader_image_load_store.incomplete_textures ended the inproc Redmi run at
# Fatal{UnmigratedVerb, "Magma:image-view-window"}: the unit named level 2 of a texture
# with only level 0, a monolith Fail turned into a SIGABRT. GL 4.6 core 8.26 makes that
# access invalid - zero loads, dropped stores - and the wire descriptor resolve now binds a
# null storage descriptor for it where the device enables VK_EXT_robustness2 nullDescriptor,
# else a placeholder private to the unit (UniformManager::ResolveWireImageDescriptor and
# ResolveWirePlaceholderImage). One entry per case for the private log path; NO KNOB,
# so all three arms. The monolith `DirectVulkan.` entry of the same scenario skips by
# name (it drops the draw: the gate 5 BASE, and a pull-build .text change to move).
# ALevelPastATextureViewsWindowReadsZero joined once the F2 repair retired the transport
# glTextureView death (see the split-arm registration of this scenario).
foreach(imageWindowCase AMissingMipLevelOfAnIncompleteTextureReadsZeroInADraw
AMissingMipLevelOfAnIncompleteTextureReadsZeroInADispatch
ALevelPastAnImmutableTexturesStorageReadsZero
ALayerPastAnArraysLastSliceReadsZero
ATextureWithNoStorageReadsZero
ALevelPastATextureViewsWindowReadsZero
AStoreThroughAnInvalidUnitIsLoadedThroughNeitherAnotherInvalidUnitNorItself
AStoreThroughAnEmptyUnitIsLoadedThroughNeitherAnotherEmptyUnitNorItself)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.ImageUnitWindow."
TEST_FILTER "InvalidImageUnitScenario.${imageWindowCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-imagewindow${mglItestArmLogTag}-${imageWindowCase}.log")
endforeach()
# ---- Codex closeout finding 2 (cf-magma): THE ARM WITHOUT A NULL DESCRIPTOR -----------
#
# The two AStoreThrough... cases above run the null-descriptor arm on this host: lavapipe
# enables VK_EXT_robustness2 nullDescriptor, so an invalid or empty storage unit binds a
# null descriptor. A device without it binds a placeholder PRIVATE to the unit (per shape)
# instead; MGITEST_MAGMA_FORCE_PRIVATE_IMAGE_PLACEHOLDER=1 puts the server on that arm
# (UniformManager::SetWireInvalidStorageImageArm), and the client reads the same marker to
# expect it: B's load zero (no alias), A's own load of its store = the recorded CONTRACT-P7
# §12 residual, which is also what proves the knob reached the server.
#
# Split+spawn only, the server-side-knob reason above, named in spawn_lane_parity.py's
# MAGMA_SERVER_ENV_KNOB_NO_TCP.
if(mglItestServerEnvKnobArm)
foreach(privateCase AStoreThroughAnInvalidUnitIsLoadedThroughNeitherAnotherInvalidUnitNorItself
AStoreThroughAnEmptyUnitIsLoadedThroughNeitherAnotherEmptyUnitNorItself)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.ImageUnitPrivate."
TEST_FILTER "InvalidImageUnitScenario.${privateCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_PRIVATE_IMAGE_PLACEHOLDER=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-imageprivate${mglItestArmLogTag}-${privateCase}.log")
endforeach()
endif()
endforeach()
endif()
# P7 gate 5 (g5-readback): BANDED READBACK ON MAGMA, all three arms, GATED. The flavour is the
# one the device CTS window ran KHR-GL46 under (role-split state, strict errors, run-ahead), so the
# host lane measures the configuration that aborted on the Redmi with
# Fatal{ReplyTooLarge, "ReadPixels 256x512 0x1908/0x1406 2097152 > 2097136"}. One entry per case
# for a private log each - two processes append to it on the spawn arm.
if (MOBILEGL_BUILD_DISAGGREGATED)
# P11: LargeArenaAdoptionScenario's cases that run on every Magma arm - the five behavioural
# cases and the tier assertion (the mpr and adopt-tier-refusal cases need lane markers of their
# own). The `Arena.` block below and the Buffers lane both walk it.
set(MGL_ITEST_ARENA_CASES
SubDataAfterAnInFlightDrawReachesTheNextDraw
RespecifiedVertexArenaKeepsVaoBindings
RespecifiedIndexArenaKeepsVaoBinding
ReadbackSeesTheLatestCpuWrite
GpuWriteIntoTheArenaIsReadBack
TheArenaLandsInTheTierItsLaneDeclares)
set(MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1" "MOBILEGL_IPC_RUN_AHEAD=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) # the ICD pin, see the Fm lane above
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(mglItestMagmaBandEnvironment
${MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(bandCase RenderbufferReadOfExactlyTwoMiBIsBandedNotRefused
TwoMiBPlusOneRowIsBanded
AReadLargerThanTheWholeReplySegmentIsBanded
BandedReadsHonourPackAlignmentRowLengthAndSkips
BandedReadIntoAPixelPackBufferKeepsItsPadding
BandedDepthAndDepthStencilReads
GetTexImageLargerThanAReplySlotIsWindowed)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Band."
TEST_FILTER "BandedReadbackScenario.${bandCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaBandEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/g5-band${mglItestArmLogTag}-${bandCase}.log")
endforeach()
# P9 (W1): the pack-buffer readback on Magma. The server half is backend-neutral - the
# reply form's read, then the applier's buffer-write gate (WriteWireBuffer here) - so the
# same seven cases, same flavour.
foreach(pboCase ReadPixelsIntoAPackBufferMatchesClientMemoryUnderEveryPackState
MapBufferRangeAfterAPackBufferReadSeesThePixels
SwapBytesIntoAPackBufferMatchesClientMemory
GetTexImageIntoAPackBufferMatchesClientMemory
APackBufferReadFeedsAnUploadFromTheSameBuffer
ALaterBufferSubDataWinsOverThePackReadWhereTheyOverlap
APackBufferReadPostsNoReplyAndMarksTheBuffer)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Pbo."
TEST_FILTER "PackBufferReadbackScenario.${pboCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaBandEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p9-pbo${mglItestArmLogTag}-${pboCase}.log")
endforeach()
# P10 (A): the fence polls on Magma. The server half is backend-neutral (the backend
# table's FenceSync / GetSyncStatus / ClientWaitSync), so the same three cases.
foreach(fenceCase ZeroTimeoutPollLoopsEndInBoundedTime
PollsOfASignaledFenceCrossNothing
AFenceThatFinishesWhileTheClientOnlyPollsIsReported
PacedFrameFenceWaitsBench)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fence."
TEST_FILTER "FencePollScenario.${fenceCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaBandEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p10-fence${mglItestArmLogTag}-${fenceCase}.log")
endforeach()
# P11 A2 (MG_Remote/CONTRACT-P11.md §2): the >= 16 MiB arena on Magma's three arms, in the
# same flavour. Declared emulated: every split acquisition declines (the wire resource
# table's MapPersistent returns null, VkBufferManager.cpp), so the tier case asserts T2
# on every arm; DirectVulkan.ArenaArm. is its monolith (adopted) half.
foreach(arenaCase IN LISTS MGL_ITEST_ARENA_CASES)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Arena."
TEST_FILTER "LargeArenaAdoptionScenario.${arenaCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaBandEnvironment}\;MGITEST_PERSISTENT_MAP_ARM=emulated\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p11-arena${mglItestArmLogTag}-${arenaCase}.log")
endforeach()
# P11 A1 (CONTRACT-P11 §1): the tcp arm with MOBILEGL_IPC_ADOPT_TIER=0 - refused by name at
# the client's handshake, T2, the scenario green. TCP ONLY by construction (over shared
# segments the knob dies at the handshake); spawn_lane_parity.py names the tail in
# MAGMA_TCP_ONLY.
if(mglItestArm STREQUAL "Tcp")
foreach(arenaCase IN LISTS MGL_ITEST_ARENA_CASES ITEMS AStreamSessionRefusesTheAdoptTierOnceByName)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Tcp.AdoptTier0."
TEST_FILTER "LargeArenaAdoptionScenario.${arenaCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaBandEnvironment}\;MOBILEGL_IPC_ADOPT_TIER=0\;MGITEST_ADOPT_TIER_REFUSAL=T0\;MGITEST_PERSISTENT_MAP_ARM=emulated\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p11-adopt-tier0-tcp-${arenaCase}.log")
endforeach()
endif()
endforeach()
endif()
# P9 W2: THE TEXTURE RE-MINT ON MAGMA, all three arms, GATED. A storage-usage upgrade recreates
# the VkImage and copies the old one into it GPU to GPU (PreserveTextureContentsOnRecreate), so
# no byte comes from the client here either (notes/p9/W2-REMINT.md). The gated band flavour
# (role-split state, strict errors, run-ahead), one entry per case for a private log each.
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(mglItestMagmaRemintEnvironment
${MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(remintCase AnUploadedMutableTextureKeepsItsTexelsAcrossTheImageBind
AGpuClearAfterTheUploadSurvivesTheImageBind
AnImmutableTexturesGpuClearSurvivesTheImageBind
ANullDefinedTextureWrittenOnlyByTheGpuSurvivesTheImageBind
APendingPartialUploadMergesOverGpuWrittenTexels
AGeneratedMipLevelSurvivesTheImageBind
AGpuClearedMipLevelSurvivesTheImageBind
ALevelDefinedWithoutDataAfterTheLastSyncDoesNotEndTheSession
ALevelRedefinedLargerWithoutDataAfterTheLastSyncDoesNotEndTheSession
APartialUploadIntoALevelDefinedAfterTheLastSyncReachesTheImage
AWidenedFormatsGpuClearSurvivesTheCarrierRemint
AWidenedFormatsUploadSurvivesTheCarrierRemint
AnRgba8SnormUploadSurvivesTheImageBind
AnRgba16SnormImmutableUploadSurvivesTheCarrierRemint)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Remint."
TEST_FILTER "TextureRemintPullScenario.${remintCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaRemintEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p9-remint${mglItestArmLogTag}-${remintCase}.log")
endforeach()
endforeach()
endif()
# P11 M: DEV'S TWO GPU-CONTENT SCENARIOS ON MAGMA, all three arms, GATED, in the band flavour -
# ImageBindableRemintScenario (Magma is its control backend: a storage upgrade copies image to
# image) and PartialUploadOverGpuContentScenario (8966d5c2's RGB->RGBA region cut and b1d60523's
# upload-after-clear/draw ordering, both of which run in the server's renderer on these arms).
# One entry per scenario and arm; every entry gets a private log through MGL_SPLIT_ARM_TEST_LISTS.
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(mglItestMagmaGpuContentEnvironment
${MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(mglItestGpuContentScenario ImageBindableRemintScenario PartialUploadOverGpuContentScenario)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.GpuContent."
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
TEST_FILTER "${mglItestGpuContentScenario}.*"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaGpuContentEnvironment}")
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()
# 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.
if (MOBILEGL_BUILD_DISAGGREGATED)
set(MGL_ITEST_MAGMA_BUFFER_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_ADOPT_TIER=2" "MGITEST_PERSISTENT_MAP_ARM=emulated"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) # the ICD pin, see the Fm lane above
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm} buffers)
mgl_itest_join_environment(MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT
${MGL_ITEST_MAGMA_BUFFER_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(bufferCase
F1WireScenario.EnabledVertexBufferDrawKeepsNamedP7Fatal
F1WireScenario.UniformBufferRangeAndRebindPixels
F1WireScenario.ShortUniformBufferRangePadsMissingBytes
F1WireScenario.SubWordUniformBufferRangePadsMissingBytes
F1WireScenario.UnalignedAtomicCounterRangeDeclinesAndTheSessionLives
F1WireScenario.ComputeWrittenVertexAndIndexBuffersDrawAndReadBack
F1WireScenario.ColorBlitToDefaultIgnoresViewportAndPreservesOrientation
F1WireScenario.ColorBlitToDefaultHonorsScissorAndReversedRect
IndexedDrawFamilyScenario.AnElementBufferDrawElementsOffsetSelectsTheRightQuad
IndexedDrawFamilyScenario.DrawElementsBaseVertexMovesTheSameIndicesToTheOtherQuad
IndexedDrawFamilyScenario.DrawRangeElementsDrawsTheRangedRun
IndexedDrawFamilyScenario.DrawElementsInstancedBaseVertexPaintsOneQuadPerInstance
IndexedDrawFamilyScenario.MultiDrawElementsBaseVertexPaintsEverySubDraw
IndexedDrawFamilyScenario.MultiDrawElementsIndirectDrawsFromTheIndirectBuffer
CrossFrameBufferScenario.VertexBufferSubData
CrossFrameBufferScenario.IndexBufferSubData
CrossFrameBufferScenario.VertexOrphanAndReupload
CrossFrameBufferScenario.IndexOrphanAndReupload
PersistentCoherentMapScenario.TwoWritesThroughTheCoherentPointerEachReachTheirOwnDraw
PersistentCoherentMapScenario.AWriteAfterAFrameBoundaryReachesTheNextFramesDraw
StorageBufferRegrowScenario.AGrownStoreIsVisibleThroughItsExistingIndexedBinding
# P11 A2: the >= 16 MiB arena, the flavour's MGITEST_PERSISTENT_MAP_ARM=emulated
# asserted by its tier case (MG_Remote/CONTRACT-P11.md §2).
LargeArenaAdoptionScenario.SubDataAfterAnInFlightDrawReachesTheNextDraw
LargeArenaAdoptionScenario.RespecifiedVertexArenaKeepsVaoBindings
LargeArenaAdoptionScenario.RespecifiedIndexArenaKeepsVaoBinding
LargeArenaAdoptionScenario.ReadbackSeesTheLatestCpuWrite
LargeArenaAdoptionScenario.GpuWriteIntoTheArenaIsReadBack
LargeArenaAdoptionScenario.TheArenaLandsInTheTierItsLaneDeclares)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Buffers."
TEST_FILTER "${bufferCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-buffers${mglItestArmLogTag}-${bufferCase}.log")
endforeach()
endforeach()
endif()
# Real Magma run-ahead, including client lead and present-credit backpressure.
# The test fixture requires an actually armed production session; a missing cap
# fails rather than turning this dedicated lane into a skip or a lockstep pass.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaRunAheadScenario.cpp)
# P7 package L: THE INPROC ARM ALONE, AND IT IS A PROPERTY OF THE SCENARIO, NOT A GAP.
# MagmaRunAheadScenario::HoldNextBatch arms the hold through
# ServerLoopInstance().SetBeforeRetireHookForTesting (Harness/SplitRuntimePeek.cpp:43-50) -
# a hook on THIS PROCESS's server loop. Under spawn or tcp the server loop is in another
# process, so the hook is installed on a loop that never runs and the wait times out with
# "the clear waited for apply instead of returning while its server batch was held".
# MEASURED, not assumed: registering all three arms made all 14 entries red on both new
# arms, with that sentence and no Fatal in either role log. An entry that cannot pass for a
# reason that is not the subject of its lane is the mirror image of R-16's rule, and this
# file already keeps four DirectGLES lanes (DualBlock, StrictProgramArm, PersistentMapArm,
# StrictArming) on one arm for exactly this reason. The two-process reading of run-ahead
# needs a cross-process hold - a server-side knob, not a function pointer - and that is
# named in this package's report as a debt rather than left as a red nobody can act on.
foreach(credit 1 3)
foreach(mglItestArm IN ITEMS Split)
mgl_itest_magma_arm_shape(${mglItestArm} runahead)
mgl_itest_join_environment(MGL_ITEST_MAGMA_RUNAHEAD_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_RUN_AHEAD=1" "MOBILEGL_IPC_PRESENT_CREDIT=${credit}"
"MOBILEGL_IPC_SPIN_US=0" "MOBILEGL_IPC_ADOPT_TIER=2"
"MGITEST_MAGMA_RUNAHEAD_LANE=1" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV} # the ICD pin, see the Fm lane
${mglItestArmTransportEnv})
foreach(runAheadCase
QueuedBufferVersionsAndDeletedNameReuseKeepTheirPixels
QueuedProgramRebindsKeepEachUniformSnapshot
QueuedGpuWritesReadBackTheLastDispatchBytes
MixedNativeAndConvertedGpuVertexStreamsKeepTheirReservation
TextureUploadCannotOvertakeThePreviouslyQueuedDraw
GpuClearSurvivesTheFirstStorageImageUpgrade
PresentCreditActuallyParksTheClientAtItsConfiguredLimit)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.RunAhead.Credit${credit}."
TEST_FILTER "MagmaRunAheadScenario.${runAheadCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_RUNAHEAD_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-runahead${mglItestArmLogTag}-credit${credit}-${runAheadCase}.log")
endforeach()
endforeach()
endforeach()
endif()
# Magma wire caches: exact view/attachment identity across public GL mutations.
# Split-only source preserves pull discovery; generic split-build registrations
# retain these names but skip outside this dedicated, strict inproc environment.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaWireCacheScenario.cpp)
set(MGL_ITEST_MAGMA_CACHES_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_RUN_AHEAD=1" "MOBILEGL_IPC_PRESENT_CREDIT=3"
"MOBILEGL_IPC_SPIN_US=0" "MOBILEGL_IPC_ADOPT_TIER=2"
"MGITEST_MAGMA_CACHES_LANE=1" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) # the ICD pin, see the Fm lane above
# P7 package L: THE INPROC ARM ALONE, for the run-ahead lane's reason one step more
# explicit - MagmaWireCacheScenario::SetUp asserts `runtime.transportName == "inproc"`
# outright (MagmaWireCacheScenario.cpp:53), because the whole lane reads the SERVER's own
# view and attachment identity out of this process. MEASURED: all 7 entries red on both new
# arms with `Which is: "non-monolith" ... "inproc"` and no Fatal in either role log.
foreach(mglItestArm IN ITEMS Split)
mgl_itest_magma_arm_shape(${mglItestArm} caches)
mgl_itest_join_environment(MGL_ITEST_MAGMA_CACHES_ENVIRONMENT
${MGL_ITEST_MAGMA_CACHES_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(cacheCase
SamplerSwizzleAtoBtoAKeepsEachQueuedPixel
SamplerRespecifyKeepsOldAndNewNativeImages
SamplerViewsDistinguishMipLayerAndViewType
FramebuffersAtoBtoAKeepDistinctAttachments
FramebufferReattachmentDistinguishesMipAndLayer
FramebufferSrgbPolicyAtoBtoAUsesDistinctFormats
FramebufferRespecifyRebindsTheNewNativeImage)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Caches."
TEST_FILTER "MagmaWireCacheScenario.${cacheCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_CACHES_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-caches${mglItestArmLogTag}-${cacheCase}.log")
endforeach()
endforeach()
endif()
# =====================================================================================
# P7 WAVE 2 PACKAGE C: THE `vertex-layout` RETIREMENT (CONTRACT-P7 §3.2)
# =====================================================================================
#
# The source is NOT inside the `if (MOBILEGL_BUILD_DISAGGREGATED)` above, and that is the
# point of the case pair: the claim is "the wire arm now does what the MONOLITH arm does",
# so the monolith DirectVulkan arm has to run the very same two cases. The ambient
# `TEST_PREFIX "DirectVulkan."` discovery near the top of this file picks them up from the
# target sources with no entry of its own; the three transports are added below.
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaVertexLayoutScenario.cpp)
if (MOBILEGL_BUILD_DISAGGREGATED)
# The flavour block is the buffers lane's minus the persistent-map knobs, which nothing
# here touches. MOBILEGL_BACKEND_TYPE and the ICD pin are the load-bearing pair: without
# them the entries run DirectGLES under a DirectVulkan prefix and skip themselves in
# SetUp, which reads as six green skips and proves nothing (measured, first cut).
set(MGL_ITEST_MAGMA_VERTEXLAYOUT_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
# ALL THREE ARMS, unlike the caches and run-ahead lanes above: nothing here reads this
# process's server loop, so there is no inproc-only property to declare. The scenario's own
# SetUp skips DirectGLES, so a DirectGLES registration would only add three skips.
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm} vertexlayout)
mgl_itest_join_environment(MGL_ITEST_MAGMA_VERTEXLAYOUT_ENVIRONMENT
${MGL_ITEST_MAGMA_VERTEXLAYOUT_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(vertexLayoutCase
AnUnmappableVertexFormatDeclinesTheDrawInsteadOfEndingTheSession
AnUnreadUnmappableArrayDoesNotStopTheRestOfTheDraw)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.VertexLayout."
TEST_FILTER "MagmaVertexLayoutScenario.${vertexLayoutCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_VERTEXLAYOUT_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-vertexlayout${mglItestArmLogTag}-${vertexLayoutCase}.log")
endforeach()
endforeach()
endif()
# =====================================================================================
# P7 WAVE 4 PACKAGE M2: THE WIRE ARM RECLAIMS ORPHANED BUFFER STORES INSIDE A FRAME
# =====================================================================================
#
# ID-P7-27 / ID-P7-32: bsl-esc-menu-854 delivers one present per replay, and the split server
# held every orphaned VkBuffer until a frame boundary that never came. The three cases read the
# server's own wbuf[] gauges (PipeStats.h) off its `MGPipe stats:` line, so the flavour pins the
# stats channel at one line per swap, and MOBILEGL_IPC_WIRE_DEFERRED_MB=8 keeps the watermark
# case at 48 MiB of traffic instead of 400.
#
# INPROC AND SPAWN ONLY - the ID-P7-14 shape, named in scripts/ci/spawn_lane_parity.py
# (MAGMA_SERVER_ENV_KNOB_NO_TCP, one tail per case). Both knobs the lane depends on are SERVER-process environment: under inproc
# and spawn the server inherits this entry's ENVIRONMENT, under tcp the server is the
# TcpServer.Start supervisor's session child, started once for the whole lane with the fixture's
# environment - setting the stats channel and an 8 MiB watermark there would change every other
# tcp entry's server - and its log is not this entry's private server log to read.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaWireReclaimScenario.cpp)
set(MGL_ITEST_MAGMA_RECLAIM_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_IPC_WIRE_DEFERRED_MB=8"
"MGITEST_MAGMA_RECLAIM_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) # the ICD pin, see the Fm lane above
foreach(mglItestArm IN ITEMS Split Spawn)
mgl_itest_magma_arm_shape(${mglItestArm} reclaim)
mgl_itest_join_environment(MGL_ITEST_MAGMA_RECLAIM_ENVIRONMENT
${MGL_ITEST_MAGMA_RECLAIM_FLAVOUR_ENV} ${mglItestArmTransportEnv})
# Round 2 (ID-P7-43) adds the fourth: the reclaim's own memo hazard. M3 adds the fifth:
# fixed-store descriptor churn in a long frame. Both use this private-log fixture and two arms.
foreach(reclaimCase
RespecifiesWithNoDrawBetweenKeepTheLiveStoreCountBounded
RespecifyAndDrawEachStoreInOneFrameStaysWithinTheDeferredBudget
ManySmallRespecifyAndDrawRoundsStayUnderTheStoreCountCeiling
ADrawAfterTheEarlyReclaimFollowsTheNewStoreNotTheMemoizedHandle
DescriptorSetsRewindInsideOneLongFrameAfterTheirSubmitRetires)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Reclaim."
TEST_FILTER "MagmaWireReclaimScenario.${reclaimCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_RECLAIM_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-reclaim${mglItestArmLogTag}-${reclaimCase}.log")
endforeach()
endforeach()
endif()
# P5c ct (MG_Remote/CONTRACT-P5C.md §5): the two control records, split-only source for the
# same reason as f1's - the scenario reads the SERVER sink's tallies, which a monolith build
# has no symbol for. One block per case with a LOG PATH OF ITS OWN, the F1 pattern:
# SplitLogPaths.PrivateAndDistinct fails a lane whose cases share one file, and the death
# case's child truncates whatever path it inherits.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/CtWireScenario.cpp)
# P7 wave 2 package C adds the fifth: the OQ-10 capability read. It belongs in THIS list
# rather than in a buffer lane because the thing it reads is a property of the SESSION -
# what the server published at handshake and the client's mirror received - and this list
# is the one that is replayed on DirectVulkan by tier 2, so one name here gives the bit a
# reading on both backends and all three transports.
foreach(ctCase ApplierResetCrossesAtThePrimedEdgeInSerialOrder
TextureDeathCrossesAndTheRecycledSlotAnswersTheNewObject
FramebufferDeathCrossesAndTheRecycledSlotAnswersTheNewObject
TheServerPublishesTheResidentSubDataCapabilityFromItsOwnTable
TheDirectApplierResetCallOnTheGLThreadIsRoleViolation)
mgl_itest_register_split_arms("CtWireScenario.${ctCase}" "Ct.")
endforeach()
endif()
# P5b named-blit cases, now green on both backends after P5f fm's server framebuffer
# and texture consumers. Keep the backend-specific label: the Magma lane has its own
# strict + dual-block hard gate, while integration-split keeps the Espryt workset.
# The separate spelling also avoids ctest's substring label match (see below).
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(namedBlitBackend DirectGLES DirectVulkan)
# P7 package L: the Magma half gets the three arms; the Espryt half stays inproc-only,
# because its spawn and tcp coverage of this scenario comes from the F1. blocks the
# registration macro already emits, and a second copy would only double the count.
set(namedBlitArms Split)
if (namedBlitBackend STREQUAL "DirectVulkan")
set(namedBlitArms ${MGL_ITEST_MAGMA_ARMS})
endif()
# The ICD pin follows the BACKEND here, not the lane: this block registers both, and
# handing VK_ICD_FILENAMES to the DirectGLES half would pin an ICD for a lane that
# never opens Vulkan (see the Fm lane above for the ruling).
if (namedBlitBackend STREQUAL "DirectVulkan")
set(namedBlitBaseEnv ${MGL_ITEST_VULKAN_ENV})
else()
set(namedBlitBaseEnv ${MGL_ITEST_COMMON_ENV})
endif()
foreach(mglItestArm IN LISTS namedBlitArms)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(MGL_ITEST_NAMED_BLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=${namedBlitBackend}"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${namedBlitBaseEnv} ${mglItestArmTransportEnv})
# THE LABEL IS `integration-magma-split` AND NOT `integration-split-magma`, and that is not
# a preference: `ctest -L` takes a REGEX, not an exact name, so `-L integration-split`
# MATCHES a label spelled `integration-split-magma` as a substring. The obvious name would
# have left both entries in the Espryt lane while every listing showed them relabelled - a
# split that looks done and is not. Measured: with that spelling
# `ctest -N -L integration-split` still listed both DirectVulkan entries.
if (namedBlitBackend STREQUAL "DirectVulkan")
set(MGL_ITEST_NAMED_BLIT_LABELS "${mglItestMagmaLabels}")
else()
set(MGL_ITEST_NAMED_BLIT_LABELS "integration-split")
endif()
foreach(namedBlitCase NamedBlitPreservesBindingsAndRestoresNextVerbsPixels NamedBlitDefaultEndpointPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${namedBlitBackend}.${mglItestArm}.NamedBlit."
TEST_FILTER "F1WireScenario.${namedBlitCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${MGL_ITEST_NAMED_BLIT_LABELS}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_NAMED_BLIT_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5b-${namedBlitBackend}${mglItestArmLogTag}-${namedBlitCase}.log")
endforeach()
endforeach()
endforeach()
endif()
# =====================================================================================
# P5e (gl), ID-115 / ID-119: THE STRICT LANE'S POSITIVE CONTROL, AND THE ONE COUNTING ENTRY
# =====================================================================================
#
# ONE ENTRY, TWO JOBS, AND BOTH NEED THE SAME THING - a drawing split scenario that can read its
# own PipeStats window.
#
# ID-115: prove strict was ARMED. Of the seven entries that passed the strict lane before this
# phase, three were monolith transport (where nothing stamps a verb boundary and the whole
# mechanism is structurally unreachable), two self-skipped, one was a death test and one was a
# Python check - so "116/116" and "strict never ran on anything that draws" were the same
# observation. `vbs` on the summary line is the arming proof and this entry is where it is read.
#
# ID-119: the `rsp` pin. The old wording ("rsp = 0 on unbarriered records") was true of every
# possible implementation, because CountBarrierPull's unbarriered arm is [[noreturn]] and runs
# BEFORE the counter. The checkable statement is the relation to `draws`, which is what the
# device measured (rsp ~= the draw count under inproc, 0 under monolith).
#
# IT IS ITS OWN ENTRY WITH ITS OWN LOG PATH, NOT A WHOLE-LANE ENV FLIP. The library opens
# MOBILEGL_LOG_FILE_PATH with "w", so every process in a lane TRUNCATES it; two entries sharing
# one path under `ctest -j` race into an empty read that looks exactly like "the counter was
# never emitted" (Harness/PipeStatsWindow.h:19-24 has the long version). RESOURCE_LOCK is the
# same belt as the PersistentMapArm entry's.
#
# BLOCK PLACED AT THE END OF THE FILE ON PURPOSE (wave-3 integration): `pa`'s
# DirectGLES.Split.StrictProgramArm. block and `mv`'s multi-draw tiers are added inside the big
# disaggregated section above, so keeping this one textually apart lets all three merge cleanly.
if (MOBILEGL_BUILD_DISAGGREGATED)
mgl_itest_join_environment(MGL_ITEST_GLES_SPLIT_STRICT_ARMING_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MGITEST_STRICT_ARMING_LANE=1"
"MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5e-strict-arming-DirectGLES.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.StrictArming."
TEST_FILTER "TriangleScenario.TheServerStampedAVerbBoundaryOnThisDrawingFrame"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-gpu\;integration-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK p5e-strict-arming-DirectGLES.log
ENVIRONMENT "${MGL_ITEST_GLES_SPLIT_STRICT_ARMING_ENVIRONMENT}"
)
endif()
# =====================================================================================
# P5f (f1), P5F-WIRE-COMPLETENESS.md §4/§6: THE DUAL-BLOCK REHEARSAL'S OWN LANE
# =====================================================================================
#
# The lane has TWO halves, and only one of them registers entries here:
#
# - the CENSUS half is an environment-variable lane, exactly like strict: the gate runs the
# EXISTING `integration-split` entries under MOBILEGL_IPC_ROLE_SPLIT_STATE=1 +
# MOBILEGL_IPC_STRICT_ERRORS=1, and every BARRIER-PULLED read there aborts with a named
# Fatal{UnmigratedPipeInput, "<field>@<verb>"} - the red IS the census, collected and
# ratcheted against Harness/dualblock-expected-fatals.txt by split_log_paths.py's
# `expect-fatal` mode. Re-registering the whole set under a second prefix would double the
# discovered test count for zero new information.
#
# - the CONTROL half is the one entry below: DualBlockScenario is the mechanism's negative
# control (§6: turning the knob OFF must turn a named case from green to red), so it needs
# an entry of its own, under a label of its own.
#
# THE LABEL IS `integration-dualblock-split`, and the spelling is load-bearing twice over
# (ID-131): `ctest -L` is a REGEX, so a label CONTAINING `integration-split` as a substring
# would be selected by the main lane's runs - and this one is expected-red there, which must
# never poison the hard-green gate. Checked both directions: `-L integration-split` does not
# match it (`dualblock` stands between the two words), and `-L integration-dualblock-split`
# matches nothing else in the tree. It does not carry `integration-gpu` either: that label must
# be able to go green, and this entry goes green only under the armed knob.
#
# THE KNOB IS NOT PINNED IN THE ENTRY'S ENVIRONMENT, deliberately, and that is the ONE deviation
# from the N-6 pinning rule every other split entry follows: a ctest ENVIRONMENT property
# overrides the process environment, so pinning MOBILEGL_IPC_ROLE_SPLIT_STATE=1 here would make
# the knob=0 form - which IS the negative control - unreachable through ctest. The failure
# direction is safe: a bare `-L integration-dualblock-split` run without the knob is RED by
# name, never silently green.
#
# MOBILEGL_IPC_RUN_AHEAD=0 IS pinned: the serial-separation half asserts on the fill side's
# behaviour per verb boundary, and under run-ahead an unbarriered verb fills nothing, which
# would make the assertion timing-dependent instead of deterministic.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE
Scenarios/DualBlockScenario.cpp Harness/DualBlockPeek.cpp)
mgl_itest_join_environment(MGL_ITEST_GLES_DUALBLOCK_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_IPC_RUN_AHEAD=0"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.Split.DualBlock."
TEST_FILTER "DualBlockScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-dualblock-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_DUALBLOCK_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/split-logs/DirectGLES.Split.DualBlock.TheTwoRolesHaveDistinctBlocks.log"
)
endif()
# P5f exit: observe every one of three real drawing frames on both backend roles.
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(backend DirectGLES DirectVulkan)
# P7 package L: the Magma half on all three transports. `integration-p5f-rsp` itself
# stays on the INPROC entries alone - the CI step that reads it require_greens exactly
# the two names it has always had, and `ctest -L` would have matched a suffixed spelling.
set(p5f_rsp_arms Split)
set(p5f_rsp_base_env ${MGL_ITEST_COMMON_ENV})
if (NOT backend STREQUAL "DirectGLES")
set(p5f_rsp_arms ${MGL_ITEST_MAGMA_ARMS})
# The ICD pin follows the backend, as in the NamedBlit block (see the Fm lane).
set(p5f_rsp_base_env ${MGL_ITEST_VULKAN_ENV})
endif()
foreach(mglItestArm IN LISTS p5f_rsp_arms)
mgl_itest_magma_arm_shape(${mglItestArm} p5f-rsp)
if (backend STREQUAL "DirectGLES")
set(p5f_rsp_label "integration-split\\;integration-p5f-rsp")
elseif (mglItestArm STREQUAL "Split")
set(p5f_rsp_label "integration-magma-split\\;integration-p5f-rsp")
else()
set(p5f_rsp_label "${mglItestMagmaLabels}")
endif()
mgl_itest_join_environment(p5f_rsp_environment
"MOBILEGL_BACKEND_TYPE=${backend}" "MGITEST_SPLIT_LANE=1"
"MGITEST_P5F_RSP_LANE=1" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-rsp-${backend}${mglItestArmLogTag}.log"
${MGL_ITEST_CAPABILITY_ENV} ${p5f_rsp_base_env} ${mglItestArmTransportEnv})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${backend}.${mglItestArm}.P5fRsp."
TEST_FILTER "F1WireScenario.EachWireFrameHasZeroResidualPulls"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${p5f_rsp_label}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK "p5f-rsp-${backend}${mglItestArmLogTag}.log"
${mglItestArmProperties}
ENVIRONMENT "${p5f_rsp_environment}")
endforeach()
endforeach()
endif()
# =====================================================================================
# P7 PACKAGE L: THE INFORMATIONAL MAGMA CENSUS - TIER 2 OF TWO
# =====================================================================================
#
# THE TWO TIERS, STATED ONCE AND IN ONE PLACE.
#
# TIER 1 - GATED. `integration-magma-split` (inproc, and its meaning is unchanged: the same
# 73 entries, names, labels and private log paths P6.5 left green), plus the two arms this
# package adds beside it, `integration-magma-spawn` and `integration-magma-tcp`. They run the
# SIX HAND-LAID MAGMA LANES - Fm, Buffers, RunAhead, Caches, NamedBlit, P5fRsp - because each
# carries a flavour (strict + dual-block state, adopt tier, run-ahead credits, cache pinning)
# that a shared scenario filter cannot express. A label here may enter a CI gating step only
# after it has been measured green.
#
# TIER 2 - INFORMATIONAL, THIS BLOCK. Every scenario the DirectGLES split arms run, on
# DirectVulkan, on all three transports: `integration-magma-all-split` / `-spawn` / `-tcp`.
# It is in NO CI gating step and must not be added to one wholesale. Its first run's RED LIST
# IS THE P7 WORK LIST - the cases wave 2's clusters A (UniformManager alignment), B
# (blit/copy/mip) and C (vertex / death ops / resident subdata / reflection) divide between
# them - and a red list you cannot record without breaking the build's green is a red list
# nobody writes down. As a cluster retires its share, its cases move UP into tier 1 with the
# commit that retires them, and the gate is honest at every step in between.
#
# WHY IT REPLAYS A RECORDED LIST INSTEAD OF NAMING SCENARIOS. The same argument the spawn arm
# won in P6 (`t6`), one dimension over: a hand-written second list agrees with the first today
# and drifts the first time somebody adds a scenario to one of them, and a Magma census covering
# LESS than the Espryt lane looks exactly like a Magma census covering all of it. The
# registration macro records every call it is given; this replays them, so a scenario added to
# the split arms tomorrow joins the Magma census the same day.
#
# THE THREE ARMS INCLUDE INPROC, and that is the block's diagnostic half: a case red on spawn
# and tcp but GREEN on inproc is a two-process defect (plumbing, a death notice, a reply that
# never crossed), while a case red on all three is Magma's own missing verb and belongs to a
# wave 2 cluster. Without the inproc arm every red would need a hand re-run to tell those apart.
if (MOBILEGL_BUILD_DISAGGREGATED)
list(LENGTH MGL_SPLIT_ARM_CALLS mglItestSplitArmCallCount)
message(STATUS "Integration tests: P7 package L replays ${mglItestSplitArmCallCount} split-arm "
"registration(s) on DirectVulkan under the informational "
"integration-magma-all-{split,spawn,tcp} labels")
foreach(mglItestCall IN LISTS MGL_SPLIT_ARM_CALLS)
# The recorded form is "<filter>|<tail>", with "-" standing for an empty tail. Split by
# regex rather than by list(GET): a filter is allowed to contain anything but `|`, and a
# CMake list cannot represent a trailing empty element unambiguously.
string(REGEX REPLACE "\\|[^|]*$" "" mglItestReplayFilter "${mglItestCall}")
string(REGEX REPLACE "^.*\\|" "" mglItestReplayTail "${mglItestCall}")
if(mglItestReplayTail STREQUAL "-")
set(mglItestReplayTail "")
endif()
mgl_itest_register_split_arms_for_backend(DirectVulkan "${mglItestReplayFilter}"
"${mglItestReplayTail}")
endforeach()
endif()
# =====================================================================================
# P7 PACKAGE L: THE WHOLE INTEGRATION BINARY UNDER MAGMA SPLIT - TIER 3, INFORMATIONAL
# =====================================================================================
#
# WHY A THIRD TIER, AND WHY IT IS THE ONE THAT ANSWERS THE EXIT GATE. Tier 2 above replays the
# split-arm registrations, which is ~100 scenarios - the set Espryt's disaggregation work has
# been carrying since P5. It measured GREEN on Magma, all three transports, and that is a real
# result but it is NOT exit gate 1. The gate says the INTEGRATION BINARY is green under Magma
# split, and the set that phrase names is the one the monolith `DirectVulkan.` arm runs: the
# whole suite minus MGL_ITEST_MONOLITH_MECHANISM_FILTER (the mechanism oracles, which toggle
# process-local push masks, pointer-key ABA, direct persistent adoption or synchronous stats
# slots and therefore must not inherit a transport). 511 cases, against tier 2's 102.
#
# THIS IS WHERE THE @P7 REFUSALS LIVE. None of tier 2's scenarios reaches one; the readback
# matrices, the same-texture copy shapes and the odd-offset uniform ranges do, and they are in
# this set and nowhere else in the disaggregated registry. THE FIRST RUN'S RED LIST IS WHAT
# WAVE 2's CLUSTERS ARE SCHEDULED FROM - see notes/p7/magma-two-process-first-run.md.
#
# IN NO CI GATING STEP, and that is the whole design: a lane that must be green cannot carry a
# census. A case leaves this tier for a gated one with the commit that retires its blocker.
# The label spelling follows tier 2's rule (`ctest -L` is a regex, ID-131): the tier word goes
# in the MIDDLE, so `-L integration-magma-split` and `-L integration-magma-all-split` cannot
# reach `integration-magma-full-split` and vice versa.
#
# THE SAME PRIVATE-LOG DISCIPLINE as every other split-family entry, through a list of its own
# rather than the shared MGL_SPLIT_ARM_TEST_LISTS: that list ALSO carries the per-entry lane
# markers (strict-arming, pmap, server counters) and applying them to a census would arm three
# unrelated oracles on cases that are here to be read, not to assert. SplitLogPaths.cmake.in
# walks this list for the log path alone.
#
# PLACED AFTER TIER 2 AND BEFORE THE configure_file, for that file's stated reason.
#
# TWO DIFFERENCES FROM TIERS 1 AND 2's ENVIRONMENT, BOTH MEASURED RATHER THAN ASSUMED.
#
# 1. NO MGITEST_SPLIT_LANE=1. That marker arms ScenarioFixture's destructor assertion
# (ScenarioFixture.h:85-100): a case in an armed split lane must have MOVED the client
# encoder's record ordinal, because "the workload drew, cleared and read pixels, so
# records were due". That is exactly right for a CURATED lane, where every entry draws.
# It is wrong for a whole-binary census, which also contains query-only cases: the first
# run of this tier with the marker set produced 13 reds - AdvertisedLimitsScenario (8),
# SpirvShaderBinaryScenario (4) and ProgramPipelineScenario.AReservedName… - every one of
# them `EmitSeq was 20 at SetUp and is 20 now`, because a limits query is answered from
# the client's CapsMirror and a shader-binary error surface never reaches a verb. Those
# 13 would red on a DirectGLES census too; they are a property of the census, not of
# Magma, and leaving them in would have buried the real list under noise.
# WHAT THIS GIVES UP, stated rather than discovered later: this tier does not prove its
# records crossed the wire, and the tcp arm's "Dial=Connect created no local server child"
# topology proof (ScenarioFixture.h:160-171, inside the same armed block) is inert here.
# Tiers 1 and 2 keep both, and they are the tiers that gate. MGITEST_TCP_LANE is still in
# the shared tcp fragment - it simply has no reader in this tier.
# 2. DualBlockScenario.* IS FILTERED OUT. Its green REQUIRES MOBILEGL_IPC_ROLE_SPLIT_STATE=1,
# and a census must not set that knob - under it every barrier-pulled read aborts, which
# would replace this tier's subject with a different experiment. Without the knob the case
# is RED BY NAME (`MGPipeRoleSplitRehearsalActive() is false`), which is its documented
# negative-control behaviour and not a finding. The monolith `DirectVulkan.` arm has the
# same case and it SKIPS there, because that runtime is not split at all. Its own lane,
# `integration-dualblock-split`, is where it is read.
if (MOBILEGL_BUILD_DISAGGREGATED)
set(MGL_MAGMA_FULL_TEST_LISTS "")
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
string(TOUPPER "${mglItestArm}" mglItestArmUpper)
mgl_itest_join_environment(mglItestMagmaFullEnvironment
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV} ${mglItestArmTransportEnv})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Full."
TEST_LIST "MGL_MAGMA_FULL_TESTS_${mglItestArmUpper}"
TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:DualBlockScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-magma-full-${mglItestArmLower}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaFullEnvironment}"
)
list(APPEND MGL_MAGMA_FULL_TEST_LISTS "MGL_MAGMA_FULL_TESTS_${mglItestArmUpper}")
endforeach()
message(STATUS "Integration tests: P7 package L tier 3 - the whole integration binary on "
"DirectVulkan x {inproc, spawn, tcp} under the informational "
"integration-magma-full-{split,spawn,tcp} labels (no CI gate)")
endif()
# =====================================================================================
# P7 WAVE 3 (V1): integration-verify-split - THE COMPARATOR ON THE SPLIT ARM
# =====================================================================================
#
# CONTRACT-P7 §6, exit gate 2: "verify x {monolith, split(inproc)} x Magma, zero divergence".
# Until this block the verify block near the top of this file registered `MOBILEGL_TRANSPORT=
# monolith` on every one of its 1136 entries, so the gate's second column had no entries at all
# - not merely unmet, UNMEASURABLE, exactly as package L found exit gate 1's Magma column.
#
# IT HAD A PREREQUISITE AND THE PREREQUISITE IS PAID. A verify build under `inproc` used to die
# on the server apply thread before one case could arm:
#
# Fatal{PipeRespecifyScope} resource_respecify {slot=12, gen=0}: the descriptor carries a
# per-level respecify scope (target=258, level=0), and no path in this phase may set one
#
# That pin is now "a per-level producer must cover the range it declares"
# (MG_Pipe/PipeApply.cpp), which is the invariant it was actually guarding.
#
# BOTH BACKENDS, AND THE MAGMA HALF IS THE HALF THE GATE NAMES. `${MGL_ITEST_VULKAN_ENV}` and
# not `${MGL_ITEST_COMMON_ENV}` on the DirectVulkan entries, for package L's reason: that list
# carries VK_ICD_FILENAMES and the three lavapipe iterationRP repairs the monolith `DirectVulkan.`
# arm has been pinned to, and a lane that appended the common list would measure a different
# driver from the gate it is compared against. `MOBILEGL_ITEST_REQUIRE_GPU=1` is pinned for the
# same reason every split-family lane pins it: a lane that skipped everything and a lane that
# passed everything are the same green in ctest, and this lane is here to be an ARM.
#
# THE CASE SET IS THE MONOLITH VERIFY LANE'S, MINUS THREE THINGS, the first two because
# this arm carries a TRANSPORT and that lane does not:
#
# 1. ${MGL_ITEST_MONOLITH_MECHANISM_FILTER}. Those oracles toggle process-local push masks,
# pointer-key ABA, direct persistent adoption or synchronous stats slots and must not
# inherit a transport - which is why the ambient DirectGLES./DirectVulkan. registrations
# subtract them too and re-register them with MOBILEGL_TRANSPORT=monolith pinned. The
# monolith verify lane keeps them because there the pin and the lane agree. NOTE that the
# filter names PipeVerifyArmingScenario.* and PoisonOmissionScenario.*, which is why the
# arming entry and the two negative controls below are registered by hand, one per backend,
# exactly as the monolith verify block registers its own.
# 2. DualBlockScenario.*. Its green REQUIRES MOBILEGL_IPC_ROLE_SPLIT_STATE=1, and pinning that
# knob here would replace this lane's subject (the comparator) with a different experiment;
# without it the case is red by name. Tier 3 above filters it for the same reason and says
# so at more length. Its own lane, `integration-dualblock-split`, is where it is read.
# 3. On the DirectGLES half only, four Magma wire-arm decline cases that are red on DirectGLES
# x inproc with the comparator OFF (MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER below
# says which and why).
#
# NO MGITEST_SPLIT_LANE=1, AND THIS IS THE ONE PLACE THAT COSTS SOMETHING, so it is stated
# rather than discovered. That marker arms ScenarioFixture's destructor assertion "this case
# must have MOVED the client encoder's record ordinal", which is right for a curated lane where
# every entry draws and wrong for a whole-binary set: tier 3 measured 13 reds from it
# (AdvertisedLimitsScenario x8, SpirvShaderBinaryScenario x4, ProgramPipelineScenario's reserved
# name), every one of them a query answered from the client's CapsMirror without a verb. They
# would red on a DirectGLES set too - a property of the census, not of the transport.
#
# WHAT REPLACES IT IS STRONGER HERE THAN IT IS IN TIER 3, and it is why this lane is armed
# rather than green-skipping: EVERY ENTRY GETS A PRIVATE LOG PATH (below, through
# MGL_VERIFY_SPLIT_TEST_LISTS), and `.github/workflows/test.yml`'s integration-verify-split job
# reads all of them: ConfigLoader's resolved `MOBILEGL_TRANSPORT=inproc` line is required in EVERY
# client log, so a lane that silently ran monolith fails that step by name. The comparator's
# `MGPipe: verify armed` line is latched at a process's FIRST FILL, so it is absent - honestly -
# from the processes that never reach a verb (limits queries, CapsMirror answers, the poison
# parent that only forks; 155 of 1064 on the landing run, 99 of them skips); the step therefore
# requires it in both VerifySplitArming. logs and holds the per-entry count to a stated floor.
# The VerifySplitArming. entries assert it from inside the process as well, which is the shape
# the monolith lane's VerifyArming. entries already have.
if (MOBILEGL_BUILD_DISAGGREGATED AND MOBILEGL_PIPE_VERIFY)
# The transport half, joined onto each backend's own list. One place says what "the verify
# split arm" means, as MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV does for the Magma lanes.
set(MGL_ITEST_VERIFY_SPLIT_ARM_ENV
"MOBILEGL_TRANSPORT=inproc" "MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}"
"MOBILEGL_PIPE_VERIFY=1" "MOBILEGL_ITEST_REQUIRE_GPU=1")
mgl_itest_join_environment(MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectGLES" ${MGL_ITEST_VERIFY_SPLIT_ARM_ENV}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" ${MGL_ITEST_VERIFY_SPLIT_ARM_ENV}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
# THE FOUR MAGMA DECLINE CASES ARE SUBTRACTED FROM THE DirectGLES HALF ONLY, and not because
# of the comparator. They assert Magma's wire-arm decline contract (`@P7` retirements: the
# depth-stencil mip decline, the two multisample blit declines, the overlapping in-place copy)
# and skip on every monolith arm, so the only arm that registers them is DirectVulkan's
# split family. On DirectGLES x inproc they are RED WITH THE COMPARATOR OFF - measured on
# this build with MOBILEGL_PIPE_VERIFY=0 in the same environment, the same four assertions
# (GL error 0x0502 where the decline promises none, or none where it promises one; the
# overlap copy writes the level the decline leaves alone) - because Espryt does not decline
# those shapes at all. That is a finding about the DirectGLES whole-binary set on split, not
# about verify, and it is recorded in notes/p7/verify-split.md rather than hidden in a green.
# This lane was NOT the only DirectGLES split lane to reach them: the primary integration job
# runs every integration-gpu entry under MOBILEGL_TRANSPORT=inproc, and there the same four
# were red in CI (the depth-stencil and overlap pair from run 35781886930, the two blits from
# 35793903365). Each case now skips by backend name at its top (F1WireScenario.cpp,
# "Magma wire-arm decline"), in every DirectGLES lane; this subtraction is therefore
# redundant, and kept so the verify-split registration and its counts do not move. The
# DirectVulkan half keeps them.
set(MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER
"F1WireScenario.GenerateMipmapDepthStencilDeclinesAndKeepsTheSession:F1WireScenario.MultisampleBlitOntoAMultisampleDestinationDeclinesAndKeepsTheSession:F1WireScenario.MultisampleBlitFromASingleSampleSourceDeclinesAndKeepsTheSession:F1WireScenario.CopyImageInPlaceOverlapDeclinesAndLeavesTheLevelAlone")
set(MGL_VERIFY_SPLIT_TEST_LISTS "")
# The ambient set, per backend. The GLES half is registered TWICE for the monolith verify
# lane's reason and with its spelling: the texture-view cases need
# MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 or DirectGLES withholds GL_ARB_texture_view and they
# green-skip, so they are subtracted from the first registration and re-registered with the
# knob. "Every existing verify case on the split arm" is false without the second block.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.VerifySplit."
TEST_LIST MGL_VERIFY_SPLIT_TESTS_GLES
TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:${MGL_ITEST_GLES_VIEW_FILTER}:DualBlockScenario.*:${MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.VerifySplit."
TEST_LIST MGL_VERIFY_SPLIT_TESTS_GLES_VIEW
TEST_FILTER "${MGL_ITEST_GLES_VIEW_FILTER}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}\;MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.VerifySplit."
TEST_LIST MGL_VERIFY_SPLIT_TESTS_VULKAN
TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:DualBlockScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT}"
)
list(APPEND MGL_VERIFY_SPLIT_TEST_LISTS MGL_VERIFY_SPLIT_TESTS_GLES
MGL_VERIFY_SPLIT_TESTS_GLES_VIEW MGL_VERIFY_SPLIT_TESTS_VULKAN)
# The arming assertion on this arm, one entry per backend, with a log path nothing else
# writes to - the monolith VerifyArming. entries' shape and their reason (the case reads the
# whole file, and a path shared with 500 neighbours races them under `-j 4`). This is the
# entry that cannot be green against a library with no comparator compiled in, and unlike the
# monolith pair it also cannot be green against one whose comparator never survived the
# server's bring-up - which is precisely what the relaxed respecify pin unblocked.
#
# MGITEST_PIPE_ARMING_LANE=1 is a harness marker the library never reads; it is what makes
# the case skip in an ambient lane rather than race there.
foreach(mglItestVerifyBackend DirectGLES DirectVulkan)
if (mglItestVerifyBackend STREQUAL "DirectGLES")
set(mglItestVerifyArmEnv "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}")
else()
set(mglItestVerifyArmEnv "${MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT}")
endif()
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestVerifyBackend}.VerifySplitArming."
TEST_FILTER "PipeVerifyArmingScenario.Armed"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${mglItestVerifyArmEnv}\;MGITEST_PIPE_ARMING_LANE=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-split-arming-${mglItestVerifyBackend}.log"
RESOURCE_LOCK "pipe-verify-split-arming-${mglItestVerifyBackend}.log"
)
# THE TWO NEGATIVE CONTROLS ON THIS ARM (CONTRACT-P7 §6), the monolith verify block's
# four entries with the split environment underneath and nothing else changed: each is
# green when its control REPORTS, so each goes red the day the comparator or the poison
# stops reaching the split arm. Their CI halves - the same knob exported against the
# ambient VerifySplit. entries, where ctest has to FAIL - live in test.yml's
# integration-verify-split job.
#
# A (G4): the corruption perturbs the snapshot arm at the CLIENT's entry compare, so the
# report lands in the client role's log, which is the half LibraryLog() reads.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestVerifyBackend}.VerifySplitCorrupted."
TEST_FILTER "PipeVerifyArmingScenario.CorruptedFieldIsReported"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${mglItestVerifyArmEnv}\;MOBILEGL_PIPE_VERIFY_CORRUPT=GetRenderStateParameters\;MOBILEGL_PIPE_VERIFY_FATAL=0\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-split-corrupt-${mglItestVerifyBackend}.log"
RESOURCE_LOCK "pipe-verify-split-corrupt-${mglItestVerifyBackend}.log"
)
# A ON THE OTHER ARM (P7 wave 3, V1). Control A above perturbs EntryCompare's snapshot,
# which runs on the CLIENT thread at a verb boundary and reports `where=entry`; the
# compare-at-read hook, which runs on the SERVER's apply thread at every backend read and
# is the only comparator that arm ever runs, had no control at all until this entry. The
# knob names GetPixelStoreParameters because ReadPixels is where the hook does its one
# piece of arm-specific reasoning - the ID-49 neutral pack window, whose oracle it rewrites
# - so a control aimed anywhere else would leave exactly that branch unproven.
#
# FATAL=0 for the corrupt entry's reason and one more: this field IS in kReadback's fill
# mask (FillPoints.def), so the client's entry compare fires first and with FATAL at its
# default the process would die before the server reached the read. The case reads the
# SERVER role's half of its private log and nothing else.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestVerifyBackend}.VerifySplitReadCorrupted."
TEST_FILTER "PipeVerifyArmingScenario.CorruptedFieldIsReportedOnTheServerRead"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${mglItestVerifyArmEnv}\;MOBILEGL_PIPE_VERIFY_CORRUPT=GetPixelStoreParameters\;MOBILEGL_PIPE_VERIFY_FATAL=0\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-split-read-corrupt-${mglItestVerifyBackend}.log"
RESOURCE_LOCK "pipe-verify-split-read-corrupt-${mglItestVerifyBackend}.log"
)
# B (G5): the child brings up its own inproc session from the inherited environment, and
# PoisonOmissionScenario's ReadChildLog reads BOTH role halves of the child's log, because
# under a transport the poisoned read can fire on either side of the seam.
#
# A DIFFERENT PAIR FROM THE MONOLITH ENTRIES', and the monolith pair is not "also fine
# here": GenerateMipmap:GetActiveTextureUnit is inert on this arm - the split backend's
# generate_mipmap resolves its texture from the verb's handle and never reads the active
# unit, so the child exited 0 with that stamp withheld (measured, both backends).
# ReadPixels:GetPixelStoreParameters is read on the server under the server's stamp,
# which is the stamp the knob has to withhold on this arm (PipeInputs.cpp's
# ServerPoisonOmission). PoisonOmissionScenario.cpp's kOmittedPairs carries both.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestVerifyBackend}.VerifySplitPoisonOmitted."
TEST_FILTER "PoisonOmissionScenario.OmittedFieldAbortsOnThatVerb"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${mglItestVerifyArmEnv}\;MOBILEGL_PIPE_POISON_OMIT=ReadPixels:GetPixelStoreParameters\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-poison-omit-split-${mglItestVerifyBackend}.log"
RESOURCE_LOCK "pipe-poison-omit-split-${mglItestVerifyBackend}.log"
)
# B's AMBIENT TARGET. The monolith verify lane's control-B step aims its knob at
# `Verify.PoisonOmissionScenario.WithoutOmissionCompletes`, the one integration entry that
# calls glGenerateMipmap at all - and the mechanism filter took that entry out of the
# ambient set above along with the rest of the scenario. Registered back by hand, with no
# knob, so the CI step has an entry on THIS arm to turn red.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${mglItestVerifyBackend}.VerifySplit."
TEST_LIST "MGL_VERIFY_SPLIT_TESTS_POISON_${mglItestVerifyBackend}"
TEST_FILTER "PoisonOmissionScenario.WithoutOmissionCompletes"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-verify-split"
TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT}
ENVIRONMENT "${mglItestVerifyArmEnv}"
)
list(APPEND MGL_VERIFY_SPLIT_TEST_LISTS "MGL_VERIFY_SPLIT_TESTS_POISON_${mglItestVerifyBackend}")
endforeach()
# NOT ON SPAWN, AND THIS IS A PROPERTY OF THE INSTRUMENT, NOT A GAP IN THE REGISTRATION. The
# comparator is a same-address-space oracle: its two arms are the applier-written gPipeInputs
# and the frontend GLContext, and only inproc puts them in one process. Measured on this build
# (VerifySplitArming's DirectGLES entry with MOBILEGL_TRANSPORT=spawn): the client's entry
# compare aborts at the first verb with Fatal{PipeVerifyDiffer, "GetClearColor@Clear", verb=1,
# where=entry}, because the fill leaves every record-supplied field to the applier and the
# applier now writes ANOTHER process's block; and the server process runs no compare at all.
#
# THE SECOND HALF IS NOT "MG_Impl IS NOT IN THE SERVER" - it is, and saying otherwise sent a
# reader looking for a link-time gap that does not exist. MobileGLServer is an executable over
# ServerEntry.cpp linked against the WHOLE library (top-level CMakeLists.txt), PipeFill.cpp
# included, so MGPipeVerifyReadHook is present in that process and is called on every backend
# read. What is absent is its ORACLE: the server image's main reaches
# MG_Backend::InitServerRoleForSpawn() and never MG_State::Init(), so MG_State::pGLContext is
# null and the hook returns at its `ctx == nullptr` line before comparing anything. Same
# conclusion, different mechanism, and the difference matters because the fix is a cross-
# process compare shape (CONTRACT-P7 §12) rather than a link edit.
message(STATUS "Integration tests: P7 wave 3 - the verify comparator on the split (inproc) arm, "
"both backends, under integration-verify-split")
endif()
if (MOBILEGL_BUILD_DISAGGREGATED)
# LAST, so every mgl_itest_register_split_arms call above has already contributed its list
# name. Apply per-entry paths after GoogleTest discovery has populated the TEST_LISTs.
configure_file(Harness/SplitLogPaths.cmake.in SplitLogPaths.cmake @ONLY)
set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
"${CMAKE_CURRENT_BINARY_DIR}/SplitLogPaths.cmake")
add_test(NAME SplitLogPaths.ResultAccountingControls
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/Harness/test_split_log_paths.py)
set_tests_properties(SplitLogPaths.ResultAccountingControls PROPERTIES LABELS "unit")
endif()