[MG_IntegrationTest, docs] (P7): twelve texture and program scenarios join the split arms, with the census that put them there

P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, "门:纹理 /
program 场景 split 覆盖", wave 2-D package D2). Each candidate was run once under
MOBILEGL_TRANSPORT=inproc on build-split and its first blocker recorded; the row per
scenario is in notes/p34b/split-scenario-census.md.

Registered (all green on inproc, spawn and tcp): TextureView,
TextureParamsWithoutASamplerView, SampledSetStaleness, ImageSizeAfterRespec,
ImageTargetKind, IntegerBorderColor, SwizzleAccessRoutine, PostLinkAttach,
RelinkStageSet, UniformInitializer, Glsl420Declaration, IoBlockNameCollision. 71 cases
per arm, 213 new gating entries; the recorded split-arm registration count the tier-2
Magma replay walks goes 33 -> 46.

TextureParamsWithoutASamplerView settles the debt table's 待核 row: all four G9 cases
pass under all three transports, so the P6 inspection-forwarder debt is closed for this
half - and it is now re-taken on every CI run rather than by inspection.

ProgramPipelineScenario beyond *StorageBlock* is NOT registered, and that is the rule
working rather than a blocker to retire: the other nine cases are pure name/state cases
that draw nothing, and an armed DirectGLES.Split. case whose workload produced no record
is red by design (ScenarioFixture.h:84-97 - the client encoder's record ordinal must
move). Registering them would assert "records crossed" about cases with no records to
send.

DirectVulkan arms default to none, deliberately, and the note says why: the
informational tier-2 block already replays every recorded registration on DirectVulkan
under integration-magma-all-{split,spawn,tcp}, so these scenarios do get a Magma x
three-transport reading - just not a gating one. Gating them would assert P7 wave 2's
exit gate 1 from inside a P3b/P4b package, on a backend whose own @P7 refusals are still
being retired in waves A/B/C.

D1 owns PixelStoreSweep, DepthStencilReadbackMatrix, PackedWordReadback and
LayeredTextureReadback; they are not in this census.
This commit is contained in:
2026-09-22 17:31:51 -04:00
parent 6567bc1e16
commit 9a69e08365
2 changed files with 159 additions and 0 deletions
@@ -2738,6 +2738,50 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
)
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
foreach(mglItestD2Scenario IN LISTS MGL_SPLIT_D2_SCENARIOS)
if(DEFINED MGL_SPLIT_D2_FILTER_${mglItestD2Scenario})
mgl_itest_register_split_arms("${MGL_SPLIT_D2_FILTER_${mglItestD2Scenario}}" "")
else()
mgl_itest_register_split_arms("${mglItestD2Scenario}.*" "")
endif()
endforeach()
# 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
@@ -0,0 +1,115 @@
# Texture / program split-scenario census (P3b/P4b wave 2-D, package D2)
`PLAN-PH-P34B-P7.md` §1.2, row **门:纹理 / program 场景 split 覆盖**: "~20 个候选场景…先在
inproc 跑一遍记首阻塞,按 P7/P8/P9 归属决定注册或具名排除".
Head `7ed5da52`, build `~/w7/p7-espryt-d2/build-split` (Release, clang, lavapipe ICD, WSL
desktop). Every candidate was run under `MOBILEGL_TRANSPORT=inproc` first; the ones that passed
were then registered through `mgl_itest_register_split_arms` and re-run under all three
transports, which is the reading in the table.
Package D1 owns `PixelStoreSweep`, `DepthStencilReadbackMatrix`, `PackedWordReadback` and
`LayeredTextureReadback`. They are not in this census.
## Summary
| | registered | excluded by name | blocked, not registered |
|---|---|---|---|
| texture family | 7 scenarios | 1 case | 0 |
| program family | 5 scenarios | 9 cases (one scenario's remainder) | 0 |
**12 scenarios newly carry `integration-split` / `-spawn` / `-tcp` entries**, 71 cases per arm.
Plus `TextureViewAliasScenario` (this package's own, 3 of 4 cases). The split-arm registration
count recorded for the tier-2 Magma replay went from 33 to 46.
## Texture family
| scenario | cases | inproc | spawn | tcp | first blocker |
|---|---|---|---|---|---|
| `TextureViewScenario` | 10 | pass | pass | pass | — (needed `MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1` on the three arm environments AND on the `TcpServer.Start` fixture; without it every case green-skipped) |
| `TextureParamsWithoutASamplerViewScenario` | 4 | pass | pass | pass | — |
| `SampledSetStalenessScenario` | 2 | pass | pass | pass* | one lane-interaction flake, see below |
| `ImageSizeAfterRespecScenario` | 1 | pass | pass | pass | — |
| `ImageTargetKindScenario` | 29 | pass (24 run, 5 skip) | pass | pass | — the 5 skips are `*Texture2DMultisample*` capability skips that also skip under monolith |
| `IntegerBorderColorScenario` | 6 | pass | pass | pass | — |
| `SwizzleAccessRoutineScenario` | 4 | pass | pass | pass | — |
| `TextureViewAliasScenario` (this package) | 4 | 3 pass, 1 red | 3 pass, 1 red | 3 pass, 1 red | **`TheOwnerUploadDrainRunsAgainAfterADrawBoundary`**, excluded by name — see below |
### The debt-table 待核 row: is the P6 inspection forwarder debt closed?
`PLAN-PH-P34B-P7.md` §1.3 carries "债务表「22 → P4b/P7 texture readback」…待核" and names
`TextureParamsWithoutASamplerView` as the case that settles it. **It is closed for this half.**
All four G9 cases pass under inproc, spawn and tcp on the current head — the parameter sync does
not depend on a sampler view existing, under a transport any more than under monolith, and the
white-box half (`PipeApplyPeek`) agrees with Espryt's applied value in every arm. The scenario is
now registered in the three arms, so the answer is re-taken on every CI run rather than by
inspection.
### `TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary` — excluded by name
Red on inproc, spawn AND tcp; green under monolith. **Not a lane problem — a product defect this
package found.** After a view has been SAMPLED once, a later `glTexSubImage` through the OWNER's
name never becomes visible through the view.
* client half provably correct: the case's own emitter-counter assertions pass, so the records
were emitted and the applier accepted them;
* `BackendTextureObject::IsDrawSyncCleanByRecord` (`Managers.cpp:15433`) compares the VIEW's
`record.Serial` / `record.PendingUploads`;
* an owner-side `resource_subdata` moves only the OWNER's (`MG_Pipe/PipeApply.cpp:1175`);
* nothing propagates a serial bump from a storage owner to the records that view it —
`MGPResourceDesc::ViewOf` is a forward edge with no reverse index, read only by the
descriptor-equality helper (`PipeApply.cpp:666`);
* monolith works because the same gate reads `GetContentVersion()` THROUGH the view, which
`TextureObjectView` forwards to the owner (`TextureObjectView.cpp:100-102`);
* `MG_Remote/CONTRACT-P5E.md:387-395` states the split gate in full and has the same hole.
**Owner**: not P7/P8/P9 — a new finding. The fix is at the gate (`Managers.cpp`, package D1's
file) or at the publisher (`MG_Pipe/PipeApply.cpp`'s `ApplyTextureUpload`, outside D2's
footprint), and the publisher form needs an O(#texture records) scan or a reverse index on
`MGPipeResourceRecord`, plus a `CONTRACT-P5E` amendment. `KHR-GL43.texture_view.coherency` is
exactly this test and reads Pass in the CTS baseline, which is a **monolith** reading.
### `SampledSetStalenessScenario` on tcp
`AQueuedClearIsMaterialisedWhenAFilterChangeCompletesTheTexture` aborted once in a full
`ctest -L integration-tcp -j 1` run (182 entries, 1 failure) and passes when run alone and on a
re-run of the whole lane. The tcp lane serialises through one supervisor
(`RESOURCE_LOCK mobilegl-tcp`) that serves one session at a time, so a subprocess abort there is a
session-reuse interaction rather than a property of this scenario. **Recorded as informational,
not excluded**; if it recurs it belongs with the tcp supervisor's own work, not with the texture
family.
## Program family
| scenario | cases | inproc | spawn | tcp | first blocker |
|---|---|---|---|---|---|
| `PostLinkAttachScenario` | 2 | pass | pass | pass | — |
| `RelinkStageSetScenario` | 3 | pass | pass | pass | — |
| `UniformInitializerScenario` | 3 | pass | pass | pass | — |
| `Glsl420DeclarationScenario` | 6 | pass (5 run, 1 skip) | pass | pass | — the skip is `AnArrayOfSamplerArraysIsHonouredOrDeclinedCleanly`, a capability skip that also skips under monolith |
| `IoBlockNameCollisionScenario` | 2 | pass | pass | pass | — |
| `ProgramPipelineScenario` beyond `*StorageBlock*` | 9 | **not registered** | | | **ScenarioFixture's armed-lane rule.** The two storage-block cases are already registered by the P5e i1 block. The other nine are pure name/state cases that draw nothing, and an armed `DirectGLES.Split.` case whose workload produced no record is RED by design (`ScenarioFixture.h:84-97`: the client encoder's record ordinal must move). That is the rule working, not a blocker to retire — registering them would be asserting "records crossed" about cases that have no records to send. |
## DirectVulkan arms: none, deliberately
No `DirectVulkan.Split.` / `.Spawn.` / `.Tcp.` **gating** entry is added for any of these.
It is not an omission and it is not a coverage hole either: `mgl_itest_register_split_arms`
records every call, and the informational tier-2 block replays all 46 of them on DirectVulkan
under `integration-magma-all-{split,spawn,tcp}` — so every scenario in this census DOES get a
Magma × three-transport reading the day it is registered. What it does not get is a **gate**.
Gating them would assert P7 wave 2's exit gate 1 ("集成 + trace 在 Magma push 与 split 下全绿")
from inside a P3b/P4b package, on a backend whose own `@P7` named refusals are still being retired
in waves A/B/C — the vertex-layout split, the blit/copy/mip cluster and the alignment cluster are
all in flight. A red there would be wave 2's to fix and would block this package's lane for
reasons it cannot act on. The tier-2 replay is exactly the right instrument for that: it produces
the red list without making it a gate.
## What was re-run after
* `scripts/ci/spawn_lane_parity.py build-split`
* the G14 name-only-grows check
* `ctest -L unit`
See `espryt-d2.md` for the readings.