mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-11 12:03:24 +09:00
- 144 commits from785fed0b0onward were rewritten to drop the Co-Authored-By trailer the project forbids; origin/feat/disaggregated moved from 1135c664 to3c80cd62(same trees) - the old->new map is ~/w7/logs/sha-map-20260922.txt; every 7..40-hex citation in the Disaggregated docs and the MG_Remote contracts that matched an old SHA is replaced by the same-length prefix of its rewrite; no other content changes
355 lines
21 KiB
Markdown
355 lines
21 KiB
Markdown
# P3b/P4b wave 2-D package D2 — the Espryt stream, part 2
|
|
|
|
The verification gates P3b/P4b owes, plus the texture / program split-scenario census.
|
|
Base `cf7ca59f` (`feat/disaggregated`), worktree `~/w7/p7-espryt-d2`, branch `p7/espryt-d2`.
|
|
|
|
Package D1 owns `MG_Backend/DirectGLES/{DirectGLES.cpp,Managers.cpp}`, the XFB/readback
|
|
scenarios and their split-arm registrations. Nothing here touches those; every
|
|
`MG_IntegrationTest/CMakeLists.txt` edit sits in a block headed `package D2`.
|
|
|
|
---
|
|
|
|
## Slice 1 — `TextureViewAliasScenario`
|
|
|
|
The verification half of "按存储属主键控的发射游标与 view 索引重映射". The code half landed in
|
|
P4a/P5e: the drain cursor is owner-keyed (`MG_Impl/Pipe/TextureEmit.h`, `NoteLevelDirty` +
|
|
`DrainTextureSubData`), the index remap is `TextureObjectView::ToOwnerLevel` /
|
|
`ToOwnerUploadTarget` / `ToOwnerRegionOffset`, the wire half is `MGPSamplerView` +
|
|
`MGPResourceDesc::ViewOf`.
|
|
|
|
Four cases, each asserting on TWO channels at once — sampled texels AND
|
|
`MGPipeTextureEmitter::SubDataCount()` / `RefusedSubDataCount()` / `DrainListSize()`, read through
|
|
the new `Harness/TextureEmitPeek.{h,cpp}`:
|
|
|
|
| case | direction | drains |
|
|
|---|---|---|
|
|
| `SubImageThroughAViewIsSampledThroughTheOwner` | view upload → owner sample | 1 |
|
|
| `SubImageThroughTheOwnerIsSampledThroughTheView` | owner upload → view sample | 1 |
|
|
| `TheViewUploadDrainRunsAgainAfterADrawBoundary` | view upload → owner sample | 3 |
|
|
| `TheOwnerUploadDrainRunsAgainAfterADrawBoundary` | owner upload → view sample | 3 |
|
|
|
|
### Red-once (R-16)
|
|
|
|
`TextureObjectView::MarkStorageDirtyRegion` patched to call `PipeNoteLevelDirty` on ITSELF instead
|
|
of forwarding to the storage owner — the two-cursor shape the design rejects.
|
|
|
|
```
|
|
DirectGLES.TextureViewAliasScenario.TheViewUploadDrainRunsAgainAfterADrawBoundary FAILED
|
|
the first view write, through the owner: 11408 of 11408 pixels disagree;
|
|
first at (2, 2) is rgba(50,160,30,255), expected rgba(255,0,255,255)
|
|
Expected: (window.SubDataDelta()) > (0u), actual: 0 vs 0
|
|
the SECOND drain (first view write after a draw boundary): the client texture emitter
|
|
described 0 texture(s) across this draw and put NO resource_subdata on the wire.
|
|
... and the same pair again for the THIRD drain.
|
|
```
|
|
|
|
**Both channels red simultaneously**, which is the property the file was written for: stale texels
|
|
AND a drain that emitted nothing.
|
|
|
|
**Deviation from the plan's prescription, recorded rather than papered over.** The plan says
|
|
"case (a) must go red". It does not — case (c) does. Case (a) creates the texture, writes through
|
|
the view and drains ONCE, and that first drain of a texture's life carries the whole level anyway
|
|
(the storage definition already marked it dirty), so a cursor keyed on the wrong object still
|
|
ships the right texels by accident. It is the SECOND and THIRD drains, where only the sub-region
|
|
written since the last validate point is owed, that can lose a record. Cases (c)/(d) exist for
|
|
exactly that and are where the red lands. The scenario header states this; case (a) is kept
|
|
because it is the cheapest statement of the remap itself.
|
|
|
|
### A defect this slice FOUND: owner writes are invisible through a sampled view under split
|
|
|
|
`TheOwnerUploadDrainRunsAgainAfterADrawBoundary` is **red on inproc, spawn and tcp, green under
|
|
monolith**, on the unmodified tree.
|
|
|
|
Once a view has been SAMPLED, a later `glTexSubImage` through the OWNER's own name never becomes
|
|
visible through the view. The client half is provably correct — the case's own counter assertions
|
|
pass, so the records were emitted and the applier accepted them.
|
|
|
|
* The server's per-texture clean gate `BackendTextureObject::IsDrawSyncCleanByRecord`
|
|
(`Managers.cpp:15433`) compares the VIEW's `record.Serial` and `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, and the applier reads it only
|
|
in the descriptor-equality helper (`PipeApply.cpp:666`).
|
|
* Under monolith the same gate reads `GetContentVersion()` THROUGH the view, which
|
|
`TextureObjectView` forwards to the owner (`TextureObjectView.cpp:100-102`). The split gate has
|
|
no equivalent of that forwarding.
|
|
* `MG_Remote/CONTRACT-P5E.md:387-395` states the split gate in full and has the same hole, so the
|
|
implementation is faithful to the contract. **The contract is what is wrong.**
|
|
|
|
`KHR-GL43.texture_view.coherency` is exactly this test and reads Pass in the CTS baseline — which
|
|
is a **monolith** reading (`notes/p7/device-window-1/CTS-base/README.md:16`).
|
|
|
|
**Not fixed here.** The fix is either at the gate (`Managers.cpp` — package D1's file) or at the
|
|
publisher (`MG_Pipe/PipeApply.cpp`'s `ApplyTextureUpload`, outside D2's declared footprint), and
|
|
the publisher-side form needs either an O(#texture records) scan per `resource_subdata` or a new
|
|
reverse index on `MGPipeResourceRecord` — a design decision with a contract amendment attached.
|
|
The case is **excluded by name from the three split arms** with the cause stated in the CMake
|
|
comment, kept in the monolith lanes where it is the regression net for the forwarding that works,
|
|
and listed in `split-scenario-census.md`. G14: the name still exists in every lane.
|
|
|
|
### The tcp arm was green-skipping everything
|
|
|
|
`MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1` on `MGL_ITEST_GLES_TCP_ENVIRONMENT` is not enough: the tcp
|
|
lane's server is **pre-started by the `TcpServer.Start` fixture**, not spawned from a client that
|
|
carries the lane environment, so the server withheld `GL_ARB_texture_view` and all four cases
|
|
SKIPPED while the identical Split and Spawn arms ran. Fixed by putting the knob on the fixture
|
|
entry's own `ENVIRONMENT` property (`tcp_server_fixture.py` builds the supervisor's environment
|
|
from `os.environ` and strips only the transport keys). A feature knob that reaches two arms of
|
|
three is the worst of the three states: the lane is green and tests nothing.
|
|
|
|
---
|
|
|
|
## Slice 2 — `TextureUploadShapeScenario` promoted from record to gate (R-11 / D-D4)
|
|
|
|
`RecordProperty` → `EXPECT_EQ` against a gold row measured on this cursor, plus a third texture
|
|
uploaded through a `glTextureView` so the view/owner remap is inside the counted workload.
|
|
|
|
### The gold row
|
|
|
|
Workload constants `kScatteredRects=40`, `kFrames=3`, one contiguous band, three textures.
|
|
|
|
| | emit | box | rect | jobs | client emitter |
|
|
|---|---|---|---|---|---|
|
|
| **gold (this cursor)** | **9** | **9** | **0** | **9** | **9** |
|
|
| P4a's record (two textures, no client emitter) | 6 | 6 | 0 | 6 | ctu=0 |
|
|
|
|
Identical on all four arms — `DirectGLES.TextureUploadShape.` (monolith), `.Split.`, `.Spawn.`,
|
|
`.Tcp.`.
|
|
|
|
### The client half is read from the emitter, not from `ctu=`
|
|
|
|
Measured, and it is a correction rather than a preference:
|
|
|
|
| arm | where `tex[]` is | where `ctu=` is |
|
|
|---|---|---|
|
|
| monolith | the one log | same line |
|
|
| inproc | the SERVER's log (two files, one process, one counter set) | same line |
|
|
| spawn / tcp | the SERVER's log | the CLIENT process's own counters, on a **different Present cadence** — measured `ctu=13` against `emit=9`, and usually not yet written at all when the case reads |
|
|
|
|
So `ctu == emit` is not a well-posed comparison under spawn/tcp from the summary lines. The log
|
|
field is kept as a RECORD and asserted only where the two are window-aligned (decided by asking
|
|
`PeekSplitRuntime()` which transport resolved — **not** by testing whether the number is >= 0,
|
|
which was this case's first mistake: the server publishes a perfectly readable `ctu=0` under
|
|
spawn and the comparison silently became `0 == 9`). The ASSERTION reads
|
|
`MGPipeTextureEmitter::SubDataCount()` in-process, which is the same counter's source and is the
|
|
client's true count in every arm, because the test process is the client under all four.
|
|
|
|
`Harness/PipeStatsWindow.h` gains `LastFromClientLog()` / `LastFromServerLog()` for this.
|
|
|
|
### Red-once (R-16)
|
|
|
|
**The prescribed flip does not reach this workload — but not for the reason this note first
|
|
gave.** Flipping `summedArea * 4 >= unionArea * 3` in `MipmapStorage::GetDirtyRects` leaves the
|
|
gate green, and so do two other client-side mutations:
|
|
|
|
1. flip `summedArea*4 >= unionArea*3` -> green
|
|
2. `rects.size() < 2` -> `rects.empty()` -> green
|
|
3. remove the union-box re-seed in `MarkDirtyRegion` -> green
|
|
4. `MOBILEGL_ESPRYT_DISABLE_UNPACK_RING=1` alone -> green **(before the geometry fix)**
|
|
|
|
The first three are green because they are mutations of a decision the CLIENT has already made
|
|
correctly: with the inset scatter the client hands over thirty rects, and none of those three
|
|
predicates is the one that takes the box arm. Attempt 4 was green for a completely different and
|
|
much worse reason, and finding it is the reviewer's (fable, ID-P7-8):
|
|
|
|
> the original stride `x = ((i*7) % 32) * 2`, `y = ((i*5) % 32) * 2` reaches x=62 (rect 9) and
|
|
> y=62 (rect 19) in a 64-px atlas, so the rects' union box covered the WHOLE LEVEL — and the
|
|
> server's `subRectEligible` (`Managers.cpp:8486-8491`) requires
|
|
> `!dirtyRegion.CoversWholeLevel`, a **bounding-box** test (`MipmapStorage.h:30-33`). Both
|
|
> scatter textures were rect-INELIGIBLE before `:8649`'s ring policy was consulted.
|
|
|
|
So the gate's numbers were right and its subject was wrong: the box-versus-rect decision it
|
|
exists to pin was never reached for the two textures the workload scatters into, and the only
|
|
texture that could move under any red-once was the contiguous control band. The first
|
|
substitute red-once's `box=6 rect=3 jobs=12` was exactly that band (64x8, cut in two, three
|
|
frames) — **neither scatter texture moved**, which is what gave the wrong explanation away.
|
|
|
|
**The fix** is `kScatterMargin`: inset the scatter by one rect so the union box bounds at
|
|
`(2,2)..(62,54)` and covers no level. Same 40 writes, same coarse stride, decision point live.
|
|
The gold row is UNCHANGED at `emit=9 box=9 rect=0 jobs=9` — but it now means what it says, and
|
|
`rect=0` is genuinely the unpack-ring policy's output rather than a bounding-box accident.
|
|
|
|
**The red-once after the fix is ZERO-PATCH**, which is stronger than any throwaway source edit:
|
|
|
|
```
|
|
MOBILEGL_ESPRYT_DISABLE_UNPACK_RING=1
|
|
tex[emit=9 box=3 rect=6 jobs=183] bytes/f[tex=9024, was 104448]
|
|
the BOX/RECT split moved: 3 box emissions against a gold of 9
|
|
the BOX/RECT split moved: 6 rect-list emissions against a gold of 0
|
|
the JOB count moved: 183 against a gold of 9
|
|
```
|
|
|
|
**Which texture moved: BOTH SCATTER TEXTURES.** `box=3` is the contiguous control band alone
|
|
(one contiguous region -> one rect -> not >= 2 -> box), `rect=6` is the plain scatter atlas AND
|
|
the atlas written through the `glTextureView`, three frames each, and `jobs=183 = 3 + 6 x 30`
|
|
confirms thirty rects per scatter emission. All 26 pixel cases of `TextureView` /
|
|
`TextureViewAlias` / `SampledSetStaleness` / `ImageSizeAfterRespec` / `CopyImageLevelRange` /
|
|
`ClearThenReadPixels` stay GREEN under the same knob — the required property, and the point of
|
|
the gate: every pixel assertion is blind to a shape that inverted.
|
|
|
|
### The Mali frame-time delta is NOT published
|
|
|
|
D-D4 asks for the +6 ms/frame reading beside the gold. **Not schedulable**: this phase has one
|
|
device, a Redmi with an Adreno, and no Mali part. Recorded as a declared deviation in the scenario
|
|
header and in `docs/Disaggregated/MEASUREMENTS.md` as "Adreno-only; Mali delta deferred" rather
|
|
than modelled or copied from the 2026 measurement's conditions. What the gate pins is the SHAPE,
|
|
on the reasoning that the shape is the cliff's cause and the frame time is its consequence on one
|
|
vendor's hardware.
|
|
|
|
### Stale prose corrected
|
|
|
|
All three said the client emitter had not landed. `MG_Impl/Pipe/TextureEmit.h`'s `EmitOneLevel`
|
|
increments `CallClass::ClientTextureUploadEmissions` on every piece it emits, and the build's own
|
|
probe hits (`MGITEST_PIPE_CLIENT_TEXTURE_UPLOAD_EMITTER_PRESENT=1` is in every lane's environment).
|
|
|
|
* `Scenarios/TextureUploadShapeScenario.cpp` header and the client-half comment block
|
|
* `MG_IntegrationTest/CMakeLists.txt`, the probe's comment ("Once package B's texture emitter
|
|
lands"). The `else()` arm is KEPT — it is what makes the arming decision falsifiable in both
|
|
directions — but it is unreachable on this tree and now says so.
|
|
* `notes/p4a/p4a-results/gates-v1.md`'s re-run table
|
|
|
|
---
|
|
|
|
## Slice 3 — the memo purity gate
|
|
|
|
`scripts/ci/espryt_memo_purity.py`, a sibling of `link_seam_purity.py`, wired into `test.yml`
|
|
beside it. Scoped to the BRACES of the families the plan names (`ResolvedTextureBindingMemo`,
|
|
`SamplerPassMemo`, `UnitSamplerLookupMemo`, `TwinLookupMemo`, `StateBackendObjectRegistry`) plus
|
|
the image sweep's seven file statics, because these two files pass frontend pointers around
|
|
legitimately in hundreds of places and a file-wide grep would be a list of exceptions.
|
|
|
|
Guard-awareness is a small conditional walker, not a preprocessor: it recognises
|
|
`#if MOBILEGL_PIPE_LEGACY_MEMOS`, `#if !MOBILEGL_BUILD_DISAGGREGATED` and the `#else` of
|
|
`#if MOBILEGL_BUILD_DISAGGREGATED`, which is every spelling these files use.
|
|
|
|
**Six allow-list entries, each with its reason.** The two that matter:
|
|
`StateBackendObjectRegistry`'s `UnorderedMap<StateObject*, Entry>` (`Managers.h:330`, and the
|
|
`m_entries` member behind it) and `ResolvedTextureBindingMemo`'s type-erased `const void* program`
|
|
are the PULL build's only arms — deleting them moves pull `.text` and fails G1, so they retire
|
|
with the pull path (P13). The other four are memo VALUES rather than keys.
|
|
|
|
**Red-once (R-16)**: 7 negative controls in `--self-test`, 4 positive controls (a
|
|
`LEGACY_MEMOS` arm, the `#else` of a `DISAGGREGATED` arm, the allow-listed type-erased key, and a
|
|
frontend pointer outside every memo family) — plus one taken against the real tree: injecting
|
|
`MG_State::GLState::ProgramObject* regressionKey` into the actual `ResolvedTextureBindingMemo`
|
|
reddens the gate and names `DirectGLES.cpp:7266`.
|
|
|
|
**What the sweep found that is NOT in scope**: seven unguarded frontend-pointer-keyed containers
|
|
under `MG_Backend/DirectVulkan` (`VkTextureManager`'s five `TextureIdentity`-keyed containers,
|
|
`VkClearManager`'s two, `VkRenderPassManager`'s two raw `RenderbufferObject*` maps, and
|
|
`VulkanRenderer::VaoDrawMemo`'s `vaoKey`+`vaoLifetimeId` pair sitting beside the correctly fenced
|
|
handle key). Magma's key inventory is P7 wave 2's, so the gate does not look there; recorded here
|
|
so the next pass meets a known list.
|
|
|
|
---
|
|
|
|
## Slice 4 — R-5 (D-K2's dependency rule in one place) and R-3
|
|
|
|
### R-5
|
|
|
|
The rule had **six** statements and nothing compared them, and **two of the four prose ones were
|
|
wrong in the same way**: `MG_Pipe/MGPipe.h:115-125` and `MG_Backend/DirectGLES/Managers.h:690-695`
|
|
both said "THREE OF THEM HAVE A DEPENDENCY" (there are six rows) and both said "the mirror pairs
|
|
(10 without 11, ...) are all fine" — when 10-without-11 is precisely D-K2's FOURTH row
|
|
(ID-14/ID-15), refused by the server and withheld by the client, with `PipeFill.cpp` saying so out
|
|
loud: "The brief's original 'bit 10 without 11 is fine' is WITHDRAWN for P4a as built." Neither
|
|
wrong comment could fail anything. `Managers.h`'s copy is in the header of the file that
|
|
implements the refusal.
|
|
|
|
**The rows, once**, in `MG_Pipe/SubsystemDeps.def` (X-macro, `FatalFamilies.def`'s convention),
|
|
expanded by `MGPipe.h` into `kMGPipeSubsystemDependencies[]` / `MGPipeSubsystemRequires()` /
|
|
`MGPipeSubsystemDependenciesAreSet()`, with four `static_assert`s over it:
|
|
|
|
| family | requires |
|
|
|---|---|
|
|
| bit 8 VertexInput | bit 7 |
|
|
| bit 9 Framebuffer | bit 10 |
|
|
| bit 10 TextureResources | bit 7 **and bit 11** |
|
|
| bit 11 Samplers | bit 10 |
|
|
| bit 12 Programs | — (a ROW, not an absence) |
|
|
| bit 13 BufferBindings | bit 7 |
|
|
|
|
Bits 8 and 13 were the two the old comment did not know about; bit 13's row lived fifteen lines
|
|
further down in `MGPipe.h`, which is how "THREE OF THEM" survived two phases.
|
|
|
|
**The two readers do NOT yet read it, deliberately.** `MG_Impl/Pipe/PipeFill.cpp` is the contract
|
|
package's file for the whole phase (`TextureEmit.h` states that rule) and
|
|
`MG_Backend/DirectGLES/Managers.cpp` belongs to package D1 while it is in flight. Switching them
|
|
is two one-line changes for the integrator. **The anti-drift property does not wait for it**:
|
|
`MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp` is the first thing in the tree that calls BOTH
|
|
readers at the same mask, sweeping the phase constants, the two documented refusal lanes and one
|
|
mask per row, and compares each against the `.def`. It is in that binary because that binary is
|
|
the one that links both sides.
|
|
|
|
Both comparisons are **one-directional**, and each for a measured reason:
|
|
|
|
* the server resolvers also fold in the family's own bit and (for the framebuffer one) D-C3's
|
|
separate wire-caps refusal, so a resolver may say NO for a reason of its own but may never say
|
|
YES at a mask the table refuses;
|
|
* `MGPipeP4aFamilyEmits` is a QUADRUPLE — the operator's bit, the wired constant, a registered
|
|
consumer, and the dependency rule — and the first version of this case asserted equality and
|
|
reddened at `0x1fff` on the sampler and program families because a bare unit binary registers no
|
|
consumer. That was the assertion being wrong, not the product; it is recorded because the
|
|
temptation to assert equality here is strong and wrong.
|
|
|
|
**Red-once (R-16), twice:**
|
|
|
|
1. drop D-K2's fourth row from the `.def` → **compile-time** failure, `MGPipe.h:225` and `:230`
|
|
("D-K2's fourth row (bit 10 requires bit 11) has gone missing again").
|
|
2. make the SERVER's `ResolveSamplerSubsystemArm` stop checking bit 10 (throwaway patch to
|
|
`Managers.cpp`, reverted) → `TheServerConsumerGateNeverArmsAFamilyTheTableRefuses` reds and
|
|
names the mask: "at MOBILEGL_PIPE_PUSH=0x9ff the SERVER's ResolveSamplerSubsystemArm ARMED the
|
|
handle arm for family 0x800 while MG_Pipe/SubsystemDeps.def says its dependency bits are not
|
|
all set." `0x9ff` is exactly the lane `CMakeLists.txt` already pins for G12.
|
|
|
|
Stale prose corrected in `MGPipe.h` (both blocks), `MG_Impl/Pipe/PipeFill.h` and
|
|
`MG_Impl/Pipe/TextureEmit.h`. **`MG_Backend/DirectGLES/Managers.h:690-695` is NOT corrected here**
|
|
— it is package D1's file. Its two defects are named above so the integrator can take them in one
|
|
line.
|
|
|
|
### R-3 (the cheap half)
|
|
|
|
`MG_Remote/CONTRACT-P5.md` already claimed the image-access, sampler-view-target and draw-buffer
|
|
encodings as contract, but did so **by pointing at package-header line ranges, and all three had
|
|
drifted** — `ImageEmit.h:146-159` no longer holds the encoding at all, `SamplerEmit.h:900` is off
|
|
by six lines, `FramebufferEmit.h:146-163` by one. That is the exact failure the table's own
|
|
`MGPSubData::Target` row warns about.
|
|
|
|
All three rows now state the encoding **by enumerator and function name** rather than by line, and
|
|
the two confusable siblings are named out loud: `MGPImageBind::Access` carries the raw GL token
|
|
(not this encoding), and `SamplerEmit.h`'s `SamplerTarget[]` is a different, biased encoding of the
|
|
same enum living 200 lines from the wire one.
|
|
|
|
**The remaining half of R-3 is stated, not closed**: `MGPSamplerView::Target` has no `Count`
|
|
bound, no `...IsValid` predicate and no `Fatal{ProtocolCorruption}` for an out-of-range value,
|
|
unlike `MGPipeResourceTarget`. Giving it the `MGPipeImageAccess` treatment in
|
|
`MGPipeValueTypes.h` is a `MG_Pipe` change outside this package's declared footprint.
|
|
|
|
---
|
|
|
|
## Slice 5 — the raw-depth-fetch sampler, step 1 only
|
|
|
|
Step 1 done: `ContextEpochTest` gains a case that drives `GetRawDepthFetchSampler()` on BOTH arms
|
|
in one process and asserts they are two different `BackendSamplerObject`s — the observable form of
|
|
`DirectGLES.cpp:334-336`'s prose claim that the legacy pair "is not constructed or consulted by
|
|
the server".
|
|
|
|
**Step 2 NOT done, and the package's own condition is why.** Every deletion candidate — the two
|
|
file-static `SharedPtr`s (`DirectGLES.cpp:82-83`), the monolith arm (`:361-371`),
|
|
`NeedsRawDepthFetchSampler` (`:393-399`) and the pre-handle sampler-pass branch (`:8015-8024`) —
|
|
is UNCONDITIONAL code. None sits behind `#if !MOBILEGL_BUILD_DISAGGREGATED`; the pull build
|
|
(`DISAGGREGATED=OFF`, `PIPE_PUSH=OFF`) compiles and links all of it, and the monolith arm is the
|
|
ENTIRE body `GetRawDepthFetchSampler` has there. Deleting any of it moves pull `.text` and fails
|
|
G1's 0/0/0/0 — `ARCHITECTURE.md:340` states that rule for exactly this class of
|
|
retired-but-compiled code. Filed as **P13**, beside the existing S7 entry in
|
|
`notes/p5f/f0-statics.md`.
|
|
|
|
---
|
|
|
|
## Slice 6 — the census
|
|
|
|
`notes/p34b/split-scenario-census.md` carries the table. Twelve scenarios newly gating in the
|
|
three GLES split arms; `ProgramPipelineScenario`'s nine non-storage-block cases deliberately not
|
|
registered (ScenarioFixture's armed-lane rule); DirectVulkan arms deliberately none, with the
|
|
tier-2 informational replay named as the reason it is not a coverage hole.
|