[docs] (P7): package D3's note, and the census row its fix falsified

P3b/P4b wave 2-D package D3, slice 3.

docs/Disaggregated/notes/p34b/espryt-d3.md, in espryt-d1.md's shape: the mechanism end to end,
the decision between resolving the predicate and indexing the reverse edge with the argument
that decided it (deletion ordering), the red-once evidence with the exact ctest invocations and
the red and green lines per arm, the gate numbers, and six things that remain.

The decision, stated once here because the note argues it at length: the gate resolves through
Desc.ViewOf to the storage record; the reverse index was rejected because it needs pruning on
VIEW death or an owner upload bumps a recycled slot's Serial, because it makes
ApplyTextureUpload write a record other than the one the call names, and because
VkTextureManager::ResolveWireTextureStorage already resolves the same way on the Magma side -
an index would have given the two backends two answers to one question.

notes/p34b/split-scenario-census.md is updated where the fix falsified it - the summary row,
the texture-family row and the exclusion section - and NOT rewritten anywhere else. D2's text
stands and D3's resolution sits above it in a quoted block, because a package note is a record
of what that package did rather than a live statement of the tree. Two citation corrections
taken while reading the device-window baseline: the CTS block is KHR-GL46 and not KHR-GL43, and
texture_view is 1/7 fail there with the failing case view_sampling, NOT coherency - coherency
reads Pass, which is what D2 claimed and is now checked per case against report-texture.json
rather than against a summary line.

espryt-d2.md itself is left alone and the note says why it is left alone.

Gates on this head, all measured rather than carried over: G1 .text 0xa52203, nm --defined-only
30570 symbols 0 added / 0 removed, -D 0/0, ninja -C build-linux rc 0. fatal_census rc 0 (79
abort sites, 0 unmarked - unchanged, rule I). link_ratchet --assert-monotone rc 0 (unchanged at
186). spawn_lane_parity rc 0. Lanes: unit 2418/2418, integration-split 264/264,
integration-spawn 180/180, integration-tcp 183/183, integration-magma-split 75/75, all 100%.
Name sets against a real ctest -N at a7c06f4f: +1 on each of split/spawn/tcp (the un-excluded
case), 0 elsewhere, 0 removed anywhere.
This commit is contained in:
2026-09-22 18:10:56 -04:00
parent 1c36987e84
commit 00d0239696
2 changed files with 405 additions and 5 deletions
+380
View File
@@ -0,0 +1,380 @@
# espryt D3 — the Espryt (DirectGLES) stream, part 3
The defect package D2 found and could not fix, plus the two D-K2 loose ends D2 left for
whoever owned `MG_Backend/DirectGLES/` next. Base `p7/espryt-d2 @ a7c06f4f`, worktree
`~/w7/p7-espryt-d3`, branch `p7/espryt-d3`.
Per-slice red-once notes (R-16 / rule J). A slice is not done until the case it turns on has
been seen RED against the tree without that slice's fix and GREEN with it, on the arms the fix
is for — and for this package that means the two-process arms, not only inproc.
Four commits, in cherry-pick order:
| # | files | what is true after it |
|---|---|---|
| 1 | `MG_Test` | the pull build compiles again — `SubsystemDepsTest`'s server half is `MOBILEGL_PIPE_PUSH`-only |
| 2 | `MG_Backend`, `MG_IntegrationTest`, `MG_Remote`, `docs` | an owner-side upload shows through a sampled texture view, because the split clean gate resolves to the storage record |
| 3 | `MG_Backend`, `MG_Pipe`, `MG_Impl` | D-K2's dependency rule has one statement, and every reader reads it |
| 4 | `docs` | this note, and the census row the fix falsified |
Commit 1 is not a deliverable and is first for a reason: without it `ninja -C build-linux` exits
1 at D2's head, so every later commit would be measured on a tree whose pull build does not
build.
---
## slice 0 — the pull build compiles again
Not a deliverable; a prerequisite for this package's own G1, and worth stating first because it
means D2's head does not pass gate C as it stands.
D2's new `MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp` guards its CLIENT case with
`#if MOBILEGL_PIPE_PUSH` + `GTEST_SKIP` and does not guard its two SERVER cases, which take the
addresses of `ResolveFramebufferSubsystemArm` / `ResolveTextureResourceSubsystemArm` /
`ResolveSamplerSubsystemArm` / `ResolveProgramSubsystemArm`. `Managers.h` declares all four
inside `#if MOBILEGL_PIPE_PUSH` and `Managers.cpp` defines them inside it, so with the pull
flags the file does not compile:
```
../MobileGL/MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp:200:11:
error: use of undeclared identifier 'ResolveFramebufferSubsystemArm'
... 9 errors generated.
ninja: build stopped: subcommand failed.
```
`libMobileGL.so` has already linked by then, so G1's `.text` and symbol numbers are still
readable — but `~/w7/logs/p7-gate-c-inner.sh` reports `=== linux build rc= ===` and it was 1.
The two cases get the same guard and the same skip the client case already carries. Nothing
else moves; `ninja -C build-linux` rc 0.
---
## slice 1 — an owner-side upload is visible through a sampled view
### The hole
`TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary`, registered by D2 and
excluded by name from the three split arms with the cause in the CMake comment: once a
`glTextureView` has been SAMPLED, a later `glTexSubImage` through the OWNER's own name never
becomes visible through the view. Red on inproc, spawn and tcp; green under monolith.
The mechanism, end to end:
* A view owns no texels, and the client keeps **one emission cursor per storage**. An upload
through a view's own name is remapped onto its storage owner before it is emitted
(`MG_Impl/Pipe/TextureEmit.h`, `MGPipeTextureEmitter`; `TextureEmitTest.cpp`'s
`AnUploadThroughAViewKeysOnTheStorageOwner` pins it). So every `resource_subdata` for either
name is keyed on the OWNER.
* `MG_Pipe/PipeApply.cpp`'s `ApplyTextureUpload` accumulates into that record and does
`++stored->Serial` on it — the owner's. Nothing moves the view's.
* `BackendTextureObject::IsDrawSyncCleanByRecord` (`MG_Backend/DirectGLES/Managers.cpp`) read
`record.Serial` and `record.PendingUploads` **of the record it was handed**, which for a bound
view is the view's. A view's `Serial` is moved by nothing an upload does, so after the view's
first sample the gate answered CLEAN forever and `SyncTextureViewToBackendByRecord` — the only
thing that drains the owner's pending uploads on a view's behalf, because it syncs the storage
twin by handle at its head — never ran again.
* Under monolith the same gate reads `GetContentVersion()` THROUGH the view, which
`TextureObjectView` forwards to its owner (`TextureObjectView.cpp:100-102`). The split gate
had no equivalent of that forwarding.
* `CONTRACT-P5E.md` §5.2 stated the split gate in full, `rec->Serial` and all, so the code was
faithful to a wrong contract. **The contract is amended, not restated.**
The client half was never at fault, and the red run proves it rather than arguing it: the
case's own `MGPipeTextureEmitter::SubDataCount()` / `RefusedSubDataCount()` / `DrainListSize()`
assertions PASS on the red run. Only the pixel channel is red.
### The decision: resolve the predicate, not index the reverse edge
**Chosen (a): the gate's two STORAGE clauses resolve through `Desc.ViewOf` to the storage
record.** `PipeTextureStorageRecordForRecord` (new, `Managers.cpp`, beside
`PipeTextureRecordForHandle`) answers with the record itself for a texture that owns its texels
and with the record `Desc.ViewOf` names for a view. `IsDrawSyncCleanByRecord` asks it for
`Serial` and `PendingUploads`; the three PARAMETER clauses and `Desc.StorageKind` stay the
view's own record's, because a view has its own texture parameters and its own built-in sampler
and that is the whole reason the second name exists. `SyncTextureViewToBackendByRecord` stamps
that same storage serial at both its arms — the steady one and the one after the native view
call — so the stamp and the gate name one quantity rather than two.
**Rejected (b): a reverse index owner → views, so an owner-side `resource_subdata` bumps every
viewing record's `Serial`.** Three reasons, in increasing order of how much they would have
cost to discover later:
1. It puts new mutable state in `MG_Pipe`'s applier, which BOTH backends read, to answer a
question one backend's gate asks. Magma does not need it (below).
2. It makes `ApplyTextureUpload` write a record other than the one the call names. The
applier's serial discipline is stated in that function's own comment — the twin stamps its
synced serial from inside the sync that reads THIS record — and a bump arriving from a
different record's apply is exactly the shape that comment exists to forbid.
3. **Deletion ordering, which is what actually decided it.** The index has to be pruned when a
VIEW dies, or an owner upload bumps a slot that has since been recycled to an unrelated
texture — a silent cross-texture serial skew with no assertion anywhere that would catch it.
The resolve direction needs no pruning at all, and it is checked at every use:
`PipeTextureRecordForHandle` tests `Live` and `Gen`, so a recycled slot answers null rather
than a stranger's record.
**Deletion ordering for the chosen shape, checked rather than assumed.** A view may outlive its
owner's GL NAME — `glDeleteTextures(owner)` while the view is alive is legal and the storage
must survive. It cannot outlive the owner's RECORD, and that is by construction on the client:
`TextureObjectView::m_storageOwner` is a strong `SharedPtr`, and
`MGPipeEmitTextureDestroyAndFree` is called from `TextureObjectBase`'s DESTRUCTOR, whose own
comment says why — *"the last SharedPtr to this object dropping, not the glDelete* that only
marks the name and leaves a still-bound object very much alive"* (`TextureObject.cpp:63`). So
`Desc.ViewOf` cannot dangle while the record that carries it is live, whatever order the
application deletes the two names in. The walk validates anyway, and **a null answer is NOT
clean** — the direction that re-syncs, never the direction that shows stale texels. It is not a
refusal and raises nothing (rule I: no new abort site, no new `Fatal` family word).
**Views of views resolve transitively.** One hop always reaches storage in practice —
`glTextureView` composes a view-of-a-view onto the ROOT at creation, which is what the spec's
additive min-level rule means; the client's emitter says so in as many words
(`TextureEmit.h EmitResourceRespecify`) and `TextureObjectView`'s own invariant is that its
owner "is never a view itself". The walk is written transitively anyway and BOUNDED, because
this side may not depend on a client invariant to terminate: a chain the wire could forge into a
cycle ends as a null answer rather than as a hang.
**The tree already agreed with (a), on the other backend.** `VkTextureManager::
ResolveWireTextureStorage` (`MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp:2603`) is the
same walk — follow `Desc.ViewOf`, bound the hops, check `Live`/`Gen`, return null on failure —
and its comment states the same two reasons: *"Production views point directly to their root.
The bound also makes a corrupt or future multi-hop record graph terminate without ever following
client data."* Magma therefore never had this defect: it resolves the storage at every use
instead of memoising a per-view serial. Picking (b) would have given the two backends two
different answers to one question.
### Red-once (rule J)
At D2's head `a7c06f4f`, with the CMake exclusion lifted and **nothing else changed**:
```
$ ctest -R 'DirectGLES\.(Split|Spawn|Tcp)\.TextureViewAliasScenario' -j 3
79% tests passed, 3 tests failed out of 14
The following tests FAILED:
4042 - DirectGLES.Split.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed) integration-gpu integration-split
4046 - DirectGLES.Spawn.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed) integration-gpu integration-spawn
4050 - DirectGLES.Tcp.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed) integration-gpu integration-tcp
```
and the failure itself, verbatim from the Split entry:
```
../MobileGL/MG_IntegrationTest/Scenarios/TextureViewAliasScenario.cpp:328: Failure
the first owner write, through the view: 11408 of 11408 pixels disagree;
first at (2, 2) is rgba(50,160,30,255), expected rgba(0,0,255,255) +/- 2
../MobileGL/MG_IntegrationTest/Scenarios/TextureViewAliasScenario.cpp:328: Failure
the second owner write, through the view: 11408 of 11408 pixels disagree;
first at (2, 2) is rgba(50,160,30,255), expected rgba(255,255,0,255) +/- 2
```
`rgba(50,160,30,255)` is the LAYER SEED — what the view was minted holding. Both writes are
lost, not one, which is the signature of a gate that latched rather than of a record that got
dropped. The drain's counter assertions are silent in the failure list: they passed.
The MONOLITH control in the same tree is 4/4:
```
$ ctest -R 'DirectGLES\.TextureViewAliasScenario'
100% tests passed, 0 tests failed out of 4
```
With the fix, the same invocation on the three arms:
```
$ ctest -R 'DirectGLES\.(Split|Spawn|Tcp)\.TextureViewAliasScenario' -j 3
100% tests passed, 0 tests failed out of 14
```
Rule J is satisfied on spawn AND tcp, not only inproc: entries 4046 and 4050 are the
two-process arms and both went red and then green.
---
## slice 2 — D2's D-K2 loose ends, now in-partition
D1 has landed on `feat/disaggregated`, so `MG_Backend/DirectGLES/` is free and the two items
D2 listed as the integrator's are taken here.
### The stale prose in the header of the file that implements the refusal
`MG_Backend/DirectGLES/Managers.h`'s resolver block said **"THREE OF THEM CARRY A DEPENDENCY"**
(there are six rows; bits 8 and 13 were the two it did not know about) and listed
**"10 without 11"** among the mirror pairs that are FINE — when 10-without-11 is precisely
D-K2's fourth row (ID-14/ID-15), refused twenty lines below by
`ResolveTextureResourceSubsystemArm` and withheld by the client. `MGPipe.h` lost the identical
pair of defects with R-5; this copy was left behind because the file belonged to a package in
flight. It does not restate the rows again: the file that states them is the file the code
reads.
### Both readers read the table
More than the two one-line changes D2 estimated, because the rule had **six** executable and
prose statements and the estimate counted two:
| reader | was | now |
|---|---|---|
| `MG_Impl/Pipe/PipeFill.cpp` `P4aFamilyDependencyBits` | its own `kMGPipeP4aFamilyDependencies[]`, four rows | `MGPipeSubsystemRequires()`; the local table is deleted |
| `MG_Impl/Pipe/PipeFill.cpp` `P5eFamilyIsLive` | hand-coded `(pushMask & kMGPipeSubsystemResources) == 0` | `MGPipeSubsystemDependenciesAreSet(bit 13, mask)` |
| `MG_Backend/DirectGLES/Managers.cpp` `PipeSubsystemDependencyMissing` | took a literal dependency BIT per call site | takes the FAMILY and asks the table |
| …its four `Resolve<Family>SubsystemArm` call sites | five calls with five hand-written sentences | four calls, one per family, naming only the family |
| `MG_Backend/DirectGLES/Managers.cpp` `ResolveVertexInputSubsystemArm` | hand-rolled `bitSet && !resourcesBitSet` | the table |
| `MG_Backend/DirectGLES/DirectGLES.cpp` `ResolveBufferBindingSubsystemArm` | hand-rolled `bitSet && !resourcesBitSet` | the table |
`MGPipe.h` gains one accessor, `MGPipeSubsystemDependencyWhy()`, so a reader that refuses
prints the ROW'S OWN sentence instead of a copy of it — the `.def` has carried a `Why` column
since R-5 and nothing read it.
**One behaviour improvement falls out of it rather than being designed in.** The texture family
is the only row with two required bits, and it used to be two guarded calls here, so a mask
missing bit 11 but carrying bit 7 was reported with the bit-7 sentence. One call now computes
`required & ~mask` from the row, so the refusal names whichever bit is actually missing.
**What this does to the anti-drift property, said out loud because it is a real weakening.**
`SubsystemDepsTest` used to compare two COPIES of the rule; it now compares two READERS of one
table, which cannot catch a typo in a row. It is kept, and the `.def`'s prose now says why: the
two sides still fold in reasons of their own — the server's own family bit and D-C3's wire-caps
refusal, the client's consumer and wired conjuncts — and those can still disagree at a mask. The
compile-time half of D2's red-once (drop the fourth row from the `.def` → `MGPipe.h:225`/`:230`
fail) is untouched and is now the load-bearing one.
`SubsystemDepsTest` 5/5 after the switch, including D2's two refusal-lane cases at `0x1fff`
and `0x7ff`.
---
## Gates
Measured on `p7/espryt-d3 @ HEAD`, `build-split` configured by `p7_worktree.sh`, `build-linux`
configured with the same compilers and `DISAGGREGATED=OFF PIPE_PUSH=OFF PIPE_LEGACY_MEMOS=ON`
to match `~/w7/pipe/build-linux`.
### G1 — the pull build is byte-identical
| | value |
|---|---|
| `readelf -S -W build-linux/libMobileGL.so` `.text` | **`0xa52203`** (required `0xa52203`) |
| `nm --defined-only` symbols | 30570 |
| vs `~/w7/p7-before/pull-syms.txt` | **0 added / 0 removed** |
| `nm --defined-only -D` vs `pull-dynsyms.txt` | **0 added / 0 removed** |
| `ninja -C build-linux` | rc 0 (rc 1 at base — slice 0) |
Measured three times: after slice 1, after slice 0, and after slice 2. Identical every time.
**Why nothing this package touches reaches the pull build**, per file:
| file | where the change sits |
|---|---|
| `Managers.cpp` `PipeTextureStorageRecordForRecord`, `PipeSubsystemDependencyMissing`, the four resolvers, `ResolveVertexInputSubsystemArm` | inside `#if MOBILEGL_PIPE_PUSH` |
| `Managers.cpp` `IsDrawSyncCleanByRecord` | inside `#if MOBILEGL_PIPE_PUSH` |
| `Managers.cpp` `SyncTextureViewToBackendByRecord` | inside `#if MOBILEGL_BUILD_DISAGGREGATED` |
| `Managers.h` the declaration and the prose | inside `#if MOBILEGL_PIPE_PUSH` |
| `DirectGLES.cpp` `ResolveBufferBindingSubsystemArm` | inside `#if MOBILEGL_BUILD_DISAGGREGATED` |
| `MGPipe.h` `MGPipeSubsystemDependencyWhy` | `inline constexpr`, unreferenced in the pull build |
| `PipeFill.cpp` | `MOBILEGL_PIPE_PUSH`-only translation unit content |
| `SubsystemDepsTest.cpp`, `MG_IntegrationTest/CMakeLists.txt`, the two `.md` files | not `libMobileGL.so` |
The numbers are the proof; the table is what makes them checkable.
### The three scripts
```
python3 scripts/ci/fatal_census.py rc 0
79 abort sites over 20 files of the split server image, 44 distinct family words,
3 refusal words, 0 unmarked (79 is D1's number; this package adds none — rule I)
python3 scripts/link_ratchet.py --build-dir build-split \
--baseline scripts/data/link_ratchet_baseline.txt --assert-monotone rc 0
ratchet: unchanged at 186 symbol(s)
python3 scripts/ci/spawn_lane_parity.py build-split rc 0
```
### Lanes
All five at 100%, each run on its own so that "The following tests FAILED" belongs to the lane
that printed it:
| lane | base (`a7c06f4f`) | D3 | delta |
|---|---|---|---|
| `unit` | 2418 | **2418 / 2418** | 0 |
| `integration-split` | 263 | **264 / 264** | +1 |
| `integration-spawn` | 179 | **180 / 180** | +1 |
| `integration-tcp` | 182 | **183 / 183** | +1 |
| `integration-magma-split` | 75 | **75 / 75** | 0 |
**Names only grow, and the growth is named.** The base column is a real `ctest -N -L` taken on
this worktree with `MG_IntegrationTest/CMakeLists.txt` reverted to `a7c06f4f` and nothing else,
not an arithmetic guess. Set difference, per lane:
```
unit added=0 removed=0
integration-split added=1 removed=0
+ DirectGLES.Split.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary
integration-spawn added=1 removed=0
+ DirectGLES.Spawn.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary
integration-tcp added=1 removed=0
+ DirectGLES.Tcp.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary
integration-magma-split added=0 removed=0
```
Three names, one per arm, and they are the un-exclusion. Nothing was removed from any lane.
**The DirectVulkan arms of the same scenario: 30 / 30.** `ctest -R
'DirectVulkan\..*TextureViewAliasScenario'` covers the monolith entry plus the six informational
Magma tiers (`integration-magma-{all,full}-{split,spawn,tcp}`), four cases each, and every one
passes on this head — as they did at base. Magma never had this defect, because
`VkTextureManager::ResolveWireTextureStorage` resolves the storage at every use instead of
memoising a per-view serial. They are informational, not gating: `integration-magma-split` (75)
does not carry this scenario.
**One tcp-lane flake, already on record and not this package's.** The FIRST full gate run had
`integration-tcp` at 182/183; the lane is clean on re-run and clean in the final run above.
`split-scenario-census.md`'s own "`SampledSetStalenessScenario` on tcp" section records the same
shape from D2's measurements and attributes it to the tcp lane serialising through one
supervisor (`RESOURCE_LOCK mobilegl-tcp`) that serves one session at a time. Recorded here so the
count is not quietly a best-of-two.
---
## What remains
**1. `KHR-GL46.texture_view.coherency` has no SPLIT reading.** It is exactly slice 1's test
(`tools/cts/caselists/p7-texture-gl46.txt:1050`), and the device-window baseline confirms D2's
claim case by case — `report-texture.json`'s results map has
`"KHR-GL46.texture_view.coherency": "Pass"`. That is a **monolith** reading; 門 5's split
comparison is the device window's, so on host hardware the integration case is the only thing
standing behind this fix. When the window runs, `texture_view.coherency` is the row to read
first. Two corrections to the citation while it is being read:
* the block is `KHR-GL46`, not `KHR-GL43` as `espryt-d2.md` and `split-scenario-census.md` write
it. The caselist, the baseline and `CONTRACT-P7.md` §7.3 all say GL46;
* `texture_view` is **1/7 fail** in that baseline (`report-texture.txt:24`) and the failing case
is `KHR-GL46.texture_view.view_sampling`, NOT `coherency`. It is a pre-existing monolith
Magma conformance failure, on the list `CTS-base/README.md` calls "monolith Magma 的既有一致性
状态", and it is not this defect — worth naming so that a 6/7 reading after the fix is not
mistaken for a regression this package caused.
**2. The Magma arms of `TextureViewAliasScenario` are informational, not gating.** Magma has no
defect to fix, but nothing in `integration-magma-split` watches the property on that backend
either. Promoting the four cases by name into the gating tier is a `test.yml` `require_green`
edit, which is not this package's file.
**3. `SubsystemDepsTest` compares two READERS now, not two copies.** Stated in slice 2 and in the
`.def`, repeated here because it is the one thing D3 made weaker: a typo in a `.def` row can no
longer be caught by that case. The compile-time half of D2's red-once (`MGPipe.h:225`/`:230`) is
what carries the anti-drift weight, and the four `static_assert`s over the table are what stand
behind the rows themselves.
**4. The remaining half of D2's R-3, untouched.** `MGPSamplerView::Target` still has no `Count`
bound, no `...IsValid` predicate and no `Fatal{ProtocolCorruption}` for an out-of-range value,
unlike `MGPipeResourceTarget`. It is an `MG_Pipe/MGPipeValueTypes.h` change and nothing in this
package needed it.
**5. D2's own note is not rewritten.** `espryt-d2.md` still says `Managers.h:690-695` "is NOT
corrected here" and that switching the readers "is two one-line changes for the integrator". Both
were true of D2 and are the record of what D2 did; a package note is not a live statement of the
tree. The tree's own live statements — `SubsystemDeps.def`'s "WHO READS IT", `Managers.h`'s
resolver block and `split-scenario-census.md`'s exclusion row — are the ones corrected, and
`split-scenario-census.md` says so in a quoted block above D2's original text rather than by
overwriting it.
**6. The seven unguarded frontend-pointer-keyed containers under `MG_Backend/DirectVulkan`** that
D2's memo-purity sweep listed are still there. They are wave 2 A/B/C's territory and this package
did not look at them.
@@ -15,12 +15,16 @@ Package D1 owns `PixelStoreSweep`, `DepthStencilReadbackMatrix`, `PackedWordRead
| | registered | excluded by name | blocked, not registered |
|---|---|---|---|
| texture family | 7 scenarios | 1 case | 0 |
| texture family | 7 scenarios | ~~1 case~~ **0** (package D3 fixed the defect) | 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.
Plus `TextureViewAliasScenario` (this package's own, ~~3 of 4 cases~~ **all 4 since D3**). The
split-arm registration count recorded for the tier-2 Magma replay went from 33 to 46.
**Updated by package D3** (`notes/p34b/espryt-d3.md`): the one excluded case is the only row of
this census that has moved, and it moved because the defect behind it was fixed rather than
because the exclusion was widened or narrowed. Everything else below is as D2 measured it.
## Texture family
@@ -33,7 +37,7 @@ count recorded for the tier-2 Magma replay went from 33 to 46.
| `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 |
| `TextureViewAliasScenario` (this package) | 4 | 4 pass | 4 pass | 4 pass | ~~`TheOwnerUploadDrainRunsAgainAfterADrawBoundary`, excluded by name~~ — **fixed by package D3**, see below |
### The debt-table 待核 row: is the P6 inspection forwarder debt closed?
@@ -45,7 +49,18 @@ white-box half (`PipeApplyPeek`) agrees with Espryt's applied value in every arm
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
### `TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary` — ~~excluded by name~~ FIXED (package D3)
> **D3's resolution, at the head of D2's own diagnosis because the diagnosis was right.** The
> fix is at the GATE: `IsDrawSyncCleanByRecord`'s two STORAGE clauses resolve through
> `Desc.ViewOf` to the storage record (`PipeTextureStorageRecordForRecord`), and
> `SyncTextureViewToBackendByRecord` stamps the same storage serial, so the stamp and the gate
> name one quantity. The three PARAMETER clauses stay the view's own record's. The publisher-side
> reverse index was rejected: it needs pruning on VIEW death or an owner upload bumps a recycled
> slot's `Serial`, and `VkTextureManager::ResolveWireTextureStorage` already resolves the same way
> on the Magma side, so the index would have given the two backends two answers to one question.
> The case is un-excluded and green on all three arms; `CONTRACT-P5E.md` §5.2 now states the rule
> the code implements. Everything from here to the end of this section is D2's finding as written.
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
@@ -69,6 +84,11 @@ footprint), and the publisher form needs an O(#texture records) scan or a revers
`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.
> **D3**: taken at the gate. `KHR-GL43.texture_view.coherency` still has no SPLIT reading on this
> tree — the CTS baselines are monolith and the split comparison is the device window's (門 5) —
> so the integration case is the only thing standing behind the fix on host hardware. Listed in
> `espryt-d3.md`'s "what remains".
### `SampledSetStalenessScenario` on tcp
`AQueuedClearIsMaterialisedWhenAFilterChangeCompletesTheTexture` aborted once in a full