mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-12 04:23:23 +09:00
Two things land together: the plan and contract draft P6 needs before it starts, and the
working notes that until now existed on exactly one machine.
1. P6's plan and contract draft (neither started; not one line of code)
docs/Disaggregated/P6-SPAWN-PLAN.md the package plan
docs/Disaggregated/P6-CONTRACT-DRAFT.md the contract draft (moves to
MG_Remote/CONTRACT-P6.md when c6 lands)
The three findings that mattered, all written into the documents:
a. P6 is SMALLER than its roadmap cell suggests. The transport primitives are already in
the tree and already tested: SocketDoorbell including hangup detection and the two
lost-wakeup fences (Doorbell.cpp:211-360, four cases in FdPassingTest), SCM_RIGHTS fd
passing, ShmSegment::Adopt, and the SurfaceOp / WindowKind schema already defined in
protocol.fbs. inproc uses a real second shm mapping rather than an alias, and
SessionRings.h:22-28 says that was done so today is not the first time it runs. P6 is
assembly plus a control plane plus a process, not "write a socket transport".
b. The evidence for "P6 is only a transport swap" has EXPIRED. It was bought by P5c, whose
audit found 59 direct memory accesses in a tree that already looked clean. P5e changed
the tree again. So the first package, a6, is a read-only audit that writes no code, and
every contract row that depends on it is marked PENDING a6 rather than decided in
advance.
c. P6 does not get a game running on the phone. ANativeWindow* is meaningless in the child,
and protocol.fbs:186-196's own comment says Android transfers the window out of band -
that band is P12. P6 lands pbuffer / surfaceless / offscreen, which is what HeadlessGL,
the split-equivalent lane and trace replay need, and which is exactly what P6's own exit
gate measures. A real window reaching the server is a named refusal. This gets its own
section because "P6 is done" would otherwise read as "the game runs now".
The contract adds rule G: a role may not name a process-local handle. It extends P5c's
rule E (a role may not name the other role's memory) from memory to identity - EGLDisplay /
EGLSurface / EGLContext / ANativeWindow* / fd number / pid / mapped address either cross as
a token this contract defines or they do not cross, and a descriptor crosses only through
SCM_RIGHTS, where the kernel renumbers it.
What P5e left for P6 gets its own section. The latch semantics are already designed
(ARCHITECTURE.md:504) and are copied unchanged. What is new is that after run-ahead the
client no longer waits while the peer process can DIE: the client holds records that were
published and will never be applied, and Android's freezer suspends the child without
closing anything. So slow and dead must be distinguishable WITHOUT a timeout threshold.
That is P6's only new design; everything else is carriage. It shares a predicate with E1's
outstanding re-specification (ID-122), and the two should be designed together.
Two gates carried over from P5e's lessons: G2 requires integration-spawn's test-name set to
match integration-split's name for name, because a differing set means the lane is quietly
running less; and the arm-proof gate requires every entry to record the child pid and
transport=spawn in its OWN private log - ID-124 established that this kind of false green
really happens, and a spawn lane that actually ran monolith would pass every other gate.
S2's shape must be settled before it is written, and the document says why: E1 is the
cautionary case.
2. The working notes move into the repository (docs/Disaggregated/notes/, 415 .md files)
ROADMAP / CURRENT_STAGE_PROGRESS / MEASUREMENTS cite ruling numbers, audit line numbers and
the provenance of gate figures from ~/w7/notes/, a directory that exists on one machine and
is under no version control. A record cited hundreds of times that lives only locally is not
a record, so it moves in whole, with its directory structure intact.
Only .md moves. Scripts, run logs, census and gate result JSON, patches, APKs and nm dumps
stay where they are: they are evidence DATA rather than documents - large, regenerated per
run, and mostly carrying absolute paths and device serials that mean something only on the
machine that produced them. The mapping and this split are written in
docs/Disaggregated/notes/README.md.
Two exceptions are recorded there too: P6's BRIEF has been promoted to a first-class
document and keeps no copy under notes/, so the two cannot drift apart; and recovered/ holds
material salvaged from failed workflow runs, which may duplicate the like-named phase
directories and is kept because a few of those were the only complete version at the time.
CI's citation lint takes docs/Disaggregated/*.md only (non-recursive), and notes/ is
deliberately outside it: those notes' file:line citations were written against their own
code heads, and resolving them against today's HEAD would fail wholesale - which is not an
error, it is their correct state as a historical record. To check one, use the revision it
declares (--rev).
3. Inconsistencies fixed in passing
- README.md's status line still said P5e was in progress while the stage table already said
closed.
- CURRENT_STAGE_PROGRESS's next-step item 1 still listed the exit gate as pending, though
(a) and (b) were run in the previous commit; rewritten to closed plus the one item that
actually remains (E1).
- ROADMAP's P6 row still had the pre-phase plan in three of its cells; it now carries the
package order, the scope boundary and the two new gates.
Checked with check_doc_citations.py: 125 citations across docs/Disaggregated/*.md, 0 problems.
251 lines
20 KiB
Markdown
251 lines
20 KiB
Markdown
# S2 — textures and samplers under run-ahead (P5e scouting report)
|
|
|
|
Head `2fde7034`. Paths under `MobileGL/`. "The record arm" = `MOBILEGL_PIPE_PUSH` +
|
|
`TextureResourceSubsystemEnabled()` / `SamplerSubsystemEnabled()`.
|
|
**Headline.** The SAMPLER half is already run-ahead-clean on its record arm, and
|
|
`SamplerImpl::ResolveSamplerCsoTwin` (`Managers.cpp:13457-13486`) is the exact shape the TEXTURE
|
|
half needs: handle in, record first, `GetOrCreateByHandle`, serial-gated sync, no frontend touch,
|
|
no allocator probe. The texture half is one step behind — its three sync bodies already read the
|
|
record and the staged store, but every one re-enters through
|
|
`g_backendTextureObjects.HandleOf(frontendObject)` and the per-draw work list borrows frontend
|
|
binding slots. **No new record and no new wire field on the draw path**; one signature, four
|
|
line-level substitutions, one ruling.
|
|
|
|
## 1. The live reads at `2fde7034`
|
|
|
|
**live** = frontend dereference; **id** = `GetLifetimeId()` + client allocator probe; **mint** =
|
|
`Acquire`, a WRITE into it; **rec** = reads nothing frontend; **hit** = runs on every steady draw.
|
|
|
|
### 1.1 The per-draw keys — already server-owned, nothing to do
|
|
`CaptureDrawTextureSyncKeys` `DirectGLES.cpp:2188-2211` reads `GetTextureContextId` `:2189`,
|
|
`GetMaxTouchedTextureUnit` `:2203`, `GetSamplingResolutionGeneration` `:2204` — **rec, hit**: the
|
|
two generations are APPLIER_DERIVED (`FieldOwnership.def:126-131`), answered from
|
|
`MGPipeApplierTextureShutterSerial()`/`ContextSerial()` under a server stamp
|
|
(`PipeInputs.h:490-527`); the mark is RECORD_SUPPLIED via `set_context_values` (`Coverage.def:260`,
|
|
`MGPipeTypes.h:1694`). `CurrentUnitBindingsEpoch`'s record arm `:2044-2071` ->
|
|
`UnitBindingsEpochFromRecords` `:2003-2042` reads the two counts and the two serials — **rec, hit**.
|
|
|
|
### 1.2 `SyncNeccessaryTextures`, unit half (`:2321-2391`)
|
|
| site | read | kind |
|
|
|---|---|---|
|
|
| `:2346` `PairingsIntact(g_unitTextureSyncList)` | per entry `entry.slot->get()`, a `const SharedPtr<ITextureObject>*` borrowed INTO the frontend unit's slot (`:2127-2131`, borrowed at `:2381`) | **live, hit** |
|
|
| `:2356` `IsDrawSyncClean(entry.slot->get(),...)` -> `Managers.h:1641-1658` | `GetTextureParamsVersion`, `GetContentVersion`, `GetSamplerObject()->GetVersion()`, `GetStorageType()`; then `:2358-2361` hands `*entry.slot` to the three syncs | **live, hit** |
|
|
| `:2374-2382` memo MISS | `GetTextureUnitObject(index)`/unit, every `GetAllBindingSlots()` slot's `GetBoundObject()`, `IsUndefinedDefaultTexture`, `SyncTextureObjectToBackend(obj)` | live, id, mint |
|
|
|
|
### 1.3 `SyncTextureObjectToBackend` (`:1723-1806`) and the three sync bodies
|
|
| site | read | kind |
|
|
|---|---|---|
|
|
| `:1734` scope, `:1736` `Find(obj)`, `:1737` `GetOrCreate(obj)`, and the re-resolve `:1781`,`:1797` | `HandleOf` -> `GetLifetimeId` + `MGPipeSlots().FindByLifetimeId` (`SlotTables.h:430-450`); miss mints (`:244-250`) | id, **mint** |
|
|
| `:1757-1758` `RequireImageBindableStorage(obj)` -> `Managers.cpp:5816-5975` | `HandleOf` `:5884`, `GetTarget` `:5888`, `GetUploadTargets`/`GetMipmapTexelSize`/`GetMipmapByteSize`/**`MarkStorageDirty`** `:5931-5940` — the last is ALREADY `Fatal{RoleViolation,"texture-legacy-arm"}` from the apply thread (`MipmapStorage.cpp:39-51`) | id, live |
|
|
| `:1760` -> `SyncTextureParamsToBackend` `Managers.cpp:8803+` | prologue `ResolvePushedTextureParams` `:8712-8743` = scope `:8717` + `HandleOf` `:8719`; body `:8876-8877` `GetTarget()` **on both arms**; `:8841,:8874` `GetExternalIndex` (logs) | id, **live** |
|
|
| `:1761` -> `SyncBuiltinSamplerToBackend` `:8554+` | prologue `ResolvePushedBuiltinSampler` `:8472-8551` = scope `:8481` + `HandleOf` `:8483`; body `:8620-8621` `GetTarget()` on both arms | id, **live** |
|
|
| `:1762` -> `SyncMipmapsToBackend` `:7049+` | `:7060` `IsTextureView()` BEFORE the record is resolved; `:7087` scope + `:7089` `HandleOf`; `:8223-8231` the Buffer arm's `GetBufferBindingSlot().GetBoundObject()`; `GetExternalIndex` in ~14 log lines. Everything else on the staged arm is the record + `ServerStagedTexture()` (`:6902-6985`) | id, **live** (4 sites) |
|
|
|
|
### 1.4 `BindCurrentTextures` / `ResolveAndBindUnitTextures`
|
|
- `:5277-5284` memo key: `currentProgram->GetLifetimeId/GetBackendStateVersion/GetLinkStatus` —
|
|
**live, hit** (S4's rows; this memo is the consumer). `:5290`'s `memcmp` vs
|
|
`g_boundTexturesCache` is server memory — rec.
|
|
- `:4861-4948` `ResolveAndBindUnitTextures` (memo MISS) — **live, id**:
|
|
`GetTextureUnitObject(unit)` `:4860`, two passes over `GetAllBindingSlots()` `:4876`,
|
|
`GetBoundObject`, `IsUndefinedDefaultTexture` `:4884`, `GetExternalIndex` `:4886`, `GetTarget`
|
|
`:4890`, the alias arbiter `sampledTargetForUnit` `:4845-4857`
|
|
(`GetMaxUniformLocation`/`GetUniformSamplerOrImageUnitIndex`/`GetUniformType`), `GetSamplerObject`
|
|
`:4914-4916`, `SamplesAsIncompleteTexture` `:4918`, scope `:4926` + `Find(obj)` `:4928`, unbind
|
|
walk `:4945-4947` (`GetTarget` per slot).
|
|
|
|
### 1.5 The samplers
|
|
- `BindCurrentUnitSamplers` gate `:5051-5059` (keys + `g_boundSamplersCache`) and record arm
|
|
`:5106-5151` (`st.SamplerStateStart/Count/BoundSamplerStates[]`, `UnbindSampler`,
|
|
`ResolveSamplerCsoTwin`) — **rec, hit; already clean**.
|
|
- decline arm `:5152-5169`: `GetTextureUnitObject(unit).GetSamplerObject()` `:5157` ->
|
|
`ResolveUnitSamplerBackend` `:4988-5026` = scope `:4993` + `HandleOf` `:4999` — live, id.
|
|
- sampler pass in `BindCurrentProgramWithResources` `:5562-5596` — **live**:
|
|
`GetTextureUnitObject(unit)` `:5562`, `GetSamplerObject` `:5563`,
|
|
`GetBindingSlot(Texture2D).GetBoundObject()` `:5564-5565`, `samplerObject->GetLodBias()` `:5573`,
|
|
`boundTexture->GetSamplerObject()->GetLodBias()` `:5580`, `texture2D->GetSamplerObject()` `:5591`,
|
|
`texture2D->GetFormat()` `:5595`.
|
|
- `:5609-5620` CSO-twin arm — rec. `:5624-5632` else arm: `ResolveUnitSamplerBackend` (id) then
|
|
`g_backendSamplerObjects.GetOrCreate(samplerObject)` `:5626` — **mint**, the only one left here.
|
|
- **Off the steady draw path (waited ops under P5e-2):** `SyncTextureObjectToBackend` from
|
|
`CopyImageSubData` `:8294-8295`, `GenerateMipmap` `:9575,:9578`, the copy-endpoint resolve
|
|
`:9735`, the texture ops `:10046+`, readbacks `:11695,:11866`; `Find(texture.get())` at
|
|
`:8512,:8839,:9305,:9419,:11886`.
|
|
|
|
## 2. What the records and applier state ALREADY carry
|
|
|
|
| need | carrier | citation |
|
|
|---|---|---|
|
|
| which texture each unit samples, PROGRAM-RESOLVED, one per unit, no alias contest, with `IsUndefinedDefaultTexture` + `SamplesAsIncompleteTexture` already applied (entry -> null) | `st.BoundSamplerViews[unit]={View,Texture,Unit}`, `SamplerViewStart/Count/Serial` | `PipeApply.h:673-676`, `MGPipeTypes.h:856-862`, emitter `SamplerEmit.h:733-789`, the two drops `:760-765` |
|
|
| the frontend TARGET to bind, aliasing format, view restrictions, samples | `SamplerViewCsos[View].View.{Target,InternalFormat,MinLevel..NumLayers,Samples,FixedSampleLocations}` | `MGPipeTypes.h:524-535`, `SamplerEmit.h:899-916` |
|
|
| which sampler CSO each unit carries, and its 15 values (`lodBias`, filters, `mipmapMode`, `compareMode`, border) with a server-owned `Serial` | `st.BoundSamplerStates[]` + `SamplerCsos[h].Params` | `PipeApply.h:335-341`, `:678-681`, `MGPipeValueTypes.h:462-486` |
|
|
| a texture's params, built-in sampler CSO, the two resync bits; and its storage shape, target, format, levels, immutability, `ImageBindableHint`, `ViewOf`, texbuffer backing | `TextureResources[h].Params`+`ParamsSerial`, `.Desc` | `PipeApply.h:265-281`, `MGPipeTypes.h:295-356`, `:548-566` |
|
|
| "did storage/texels move", and the twin's own "what did I last sync" | `.Serial` + `PendingUploads` + `ServerStagedTexture()` defined/GPU-dirty; `m_syncedResourceSerial`, `m_syncedParamsSerial`, `m_syncedBuiltinSamplerSerial`+`m_syncedBuiltinSampler` | `PipeApply.h:240-318`, `Managers.cpp:6902-6985`, `Managers.h:1785-1812` |
|
|
| texture death by handle on the apply thread, no allocator; the handle-keyed adopt/recycle rule | `object_death` -> `ReleaseTwinsForWireObjectDeath` -> `ReleaseByHandle`; `GetOrCreate(MGPipeHandle)`/`FindByHandle` | `Managers.cpp:328-337`, `SlotTables.h:278-341`, `:420-425`, `:488-506` |
|
|
|
|
The brief's two questions: **yes**, `object_death` covers textures since P5c ct
|
|
(`Managers.cpp:331-332`); and the default texture (name 0) DOES have a record —
|
|
`TextureEmit.h:806-833` self-heals a create+respecify when its first `set_texture_params` is
|
|
refused, written for exactly that case.
|
|
|
|
## 3. The gap
|
|
|
|
- **G-S2-1 (a signature, not a field).** No `SyncTextureToBackendByHandle(MGPipeHandle)`; every
|
|
entry takes `const SharedPtr<ITextureObject>&` and re-derives the handle with `HandleOf`. Needed:
|
|
one handle-taking entry point + handle-taking prologues
|
|
(`ResolvePushedTextureParams(MGPipeHandle)`, `ResolvePushedBuiltinSampler(MGPipeHandle)`).
|
|
- **G-S2-2 (four live reads inside the handle arm, all with an existing carrier).**
|
|
`Managers.cpp:8876-8877` and `:8620-8621` `GetTarget()` -> `Desc.Target` (via
|
|
`StagedTextureTargetForPipeTarget`, `:6905`); `:7060` `IsTextureView()` -> `Desc.ViewOf`
|
|
(`MGPipeTypes.h:356`), record resolved first; `:8223-8231` -> `Desc.BufferForTexBuffer`
|
|
(already read at `:8240`). Plus **G-S2-4**: ~20 log lines print `GetExternalIndex()`;
|
|
`Desc.GlNameForDiag` (`MGPipeTypes.h:349`) is the declared diagnostics carrier. Mechanical.
|
|
- **G-S2-3 (no handle-arm clean gate).** `IsDrawSyncClean(const ITextureObject*,...)`
|
|
(`Managers.h:1641-1658`) has no record-keyed sibling, so the memo-HIT path is frontend-bound
|
|
every draw. Needs no new state — see §4.
|
|
- **G-S2-5 (RULING).** `RequireImageBindableStorage`'s re-dirty (`Managers.cpp:5930-5962`) reaches
|
|
back into the client's storage model and already aborts under split; `ImageBindableHint` is the
|
|
prevention and P9 owns the pull, so P5e should delete the frontend argument and leave the split
|
|
arm a NAMED refusal at the entry, not build half a terminator.
|
|
- **G-S2-6 (narrowing, needs the integrator's word).** Driving the unit list off
|
|
`BoundSamplerViews` syncs only the program-resolved texture per unit, where today the walk syncs
|
|
every slot of every touched unit. The union of (views + image units + the FBO attachment lists +
|
|
the waited texture ops) still covers every texture anything reads, so this narrows WORK, not
|
|
coverage — but it is a behaviour delta against the monolith arm and must be named under G1.
|
|
|
|
## 4. The retirement design
|
|
|
|
**Twin key.** `g_backendTextureObjects` stays one table; every draw-path resolution becomes
|
|
`GetOrCreateByHandle(view.Texture)` / `FindByHandle(view.Texture)`. `HandleOf`, `Find(StateObject*)`
|
|
and `GetOrCreate(const StatePtr&)` become unreachable from the apply thread, so the existing
|
|
`MGPipeRefuseAllocatorFromApplyThread` guards (`SlotTables.h:255-266`, `:436-441`) stop being
|
|
scope-exempted here, and this family's `MGPipeFrontendKeyedRegistryScope` sites —
|
|
`DirectGLES.cpp:1734`, `:4926`, `:4993`, `Managers.cpp:5882`, `:7087`, `:8481`, `:8717` — are
|
|
deleted, not moved. **Sync shape** (the `ResolveSamplerCsoTwin` template,
|
|
`Managers.cpp:13457-13486`):
|
|
```
|
|
BackendTextureObject* SyncTextureToBackendByHandle(MGPipeHandle res, Bool imageBindable) {
|
|
const auto* rec = PipeTextureRecordForHandle(res); // record FIRST; null -> named decline
|
|
auto* slot = rec ? g_backendTextureObjects.GetOrCreateByHandle(res) : nullptr; // adopt/recycle by Gen
|
|
if (!slot) return nullptr; // backward Gen -> named decline
|
|
if (!*slot) *slot = MakeShared<BackendTextureObject>();
|
|
(*slot)->SyncTextureParamsToBackend(res, *rec); (*slot)->SyncBuiltinSamplerToBackend(res, *rec);
|
|
(*slot)->SyncMipmapsToBackend(res, *rec);
|
|
if ((*slot)->NeedsParameterResync()) { /* params; builtin */ }
|
|
return slot->get();
|
|
}
|
|
```
|
|
The by-value twin copy + second `Find` (`:1745-1755`, `:1781-1805`) go with the map arm: a slot
|
|
entry is an array element, so the nested-`glTextureView` relocation hazard is answered by
|
|
re-indexing, not by a refcount.
|
|
**"Is it clean" from server-owned serials.** `IsDrawSyncCleanByRecord(res, rec)` is EXACTLY the
|
|
conjunction of the three handle-arm prologues' own early-outs — the relation
|
|
`Managers.h:1626-1640` already states for the frontend version:
|
|
```
|
|
m_isInitialized && m_syncedResourceSerial != 0 && m_syncedResourceSerial == rec->Serial // :7133-7139
|
|
&& rec->PendingUploads.empty()
|
|
&& m_syncedParamsSerial == rec->ParamsSerial && rec->Params.ForceResync == 0 && !m_forceTextureParamsResync
|
|
&& m_syncedBuiltinSampler == rec->Params.BuiltinSampler // :8735-8741
|
|
&& m_syncedBuiltinSamplerSerial == PipeSamplerCsoRecordForHandle(rec->Params.BuiltinSampler)->Serial
|
|
&& rec->Params.SamplerResync == 0 && !m_forceSamplerResync // :8539-8548
|
|
&& (TextureStorageType)rec->Desc.StorageKind == TextureStorageType::Mipmap
|
|
```
|
|
No new member, no new field. The `contextId`/`samplingGeneration` arguments disappear: the
|
|
applier's `ContextSerial` and `TextureShutterSerial` (`PipeApply.h:697-717`) are what the keys
|
|
already carry.
|
|
|
|
**The unit work list and the bind.** `UnitTextureSyncEntry` (`:2127-2132`) becomes
|
|
`{MGPipeHandle Res, BackendTextureObject* backend}`; the memo key becomes `(ContextSerial,
|
|
SamplerViewsSerial, SamplerViewStart, SamplerViewCount, g_backendContextGeneration)` —
|
|
`SamplerViewsSerial` moves iff the resolved set moved, which the emitter's content-hash suppressor
|
|
(`SamplerEmit.h:692-697`) makes sound — and **`PairingsIntact` is deleted**: no borrowed slot is
|
|
left to go stale. The rebuild walks `st.BoundSamplerViews[Start..Start+Count)` calling
|
|
`SyncTextureToBackendByHandle`. `ResolveAndBindUnitTextures` collapses to one pass over the same
|
|
window: `FindByHandle(entry.Texture)`, target from `SamplerViewCsos[entry.View].View.Target`, bind;
|
|
then unbind every backend target the window did not claim, driven by the fixed `TextureTarget` enum
|
|
plus `g_boundTexturesCache` (server memory) instead of `GetAllBindingSlots()`. The alias arbiter
|
|
`sampledTargetForUnit` `:4845-4857` DIES — the client already arbitrated (`SamplerEmit.h:751-757`).
|
|
|
|
**The sampler pass** `:5562-5596`. The unit's effective sampler becomes `st.BoundSamplerStates[unit]`
|
|
if non-null, else `TextureResources[view.Texture].Params.BuiltinSampler`; its values come from the
|
|
CSO record (`lodBias`, `minFilter`, `magFilter`, `mipmapMode`, `compareMode` all present,
|
|
`MGPipeValueTypes.h:462-486`), and `texture2D->GetFormat()` becomes
|
|
`SamplerViewCsos[view.View].View.InternalFormat`. The raw-depth-fetch substitution itself STAYS on
|
|
the server (`docs/Disaggregated/ARCHITECTURE.md` §5.5 assigns it there by name). `:5624-5632`'s
|
|
`GetOrCreate(samplerObject)` is deleted; the CSO-twin arm `:5609-5620` is the only arm left.
|
|
Finally the two decline arms — `BindCurrentUnitSamplers` `:5152-5169` and
|
|
`CurrentUnitBindingsEpoch` `:2073-2098` — become named refusals under a live wire instead of
|
|
falls-back to `GetTextureUnitObject`, and with them gone
|
|
`CaptureUnitBindings`/`UnitBindingsUnchanged`/`g_observedUnitBindings` (`:1867-1957`) are
|
|
monolith/legacy-only text.
|
|
|
|
## 5. Monolith / G1
|
|
|
|
Every edit sits inside `#if MOBILEGL_PIPE_PUSH` and, for the run-ahead arms, behind
|
|
`MG_Config::Transport != MG_Config::TransportMode::Monolith` — the idiom already at
|
|
`DirectGLES.cpp:3226`, `:4725`, `:6534`. The pull build keeps `:1936-1957`, `:2073-2098`,
|
|
`:2340-2391`, `:4861-4948`, `:5152-5169`, `:5624-5632` token for token, the D-P rule this family
|
|
already follows (`Managers.cpp:8613-8618`, `:8791-8800` spell the `#if/#else` arm split and why a
|
|
shared prologue is a G1 failure). Three obligations: (1) `BackendTextureObject`'s pull-build layout
|
|
must not move — every member the new gate needs is already inside `#if MOBILEGL_PIPE_PUSH`
|
|
(`Managers.h:1785-1812`), so the admitted-resize set stays empty; (2) `UnitTextureSyncEntry`'s
|
|
re-shape is push-only, two structs under one name selected by `#if`, which
|
|
`g_fboTextureSyncListRecordKeyed` (`:2157-2171`) already does; (3) the push build under
|
|
`Transport=monolith` must KEEP the frontend walk — no server to answer from — so the run-ahead arm
|
|
is a THIRD arm, like `MGB_STAGED_TEXTURE_LIVE` (`:6902-6903`). `MOBILEGL_PIPE_VERIFY` forces the
|
|
lockstep, so the comparator keeps seeing both.
|
|
|
|
## 6. Red-once
|
|
|
|
1. **Widen the pinned guard list.** `MG_Test/Wire/RemoteClientTest.cpp:1938-1941` deliberately
|
|
EXEMPTS the shape reads — "GetMipmapTexelSize / GetMipmapByteSize / GetMipmapLevelCount /
|
|
GetUploadTargets / GetTarget / IsComplete ... the per-draw binding walk reads them every draw".
|
|
P5e adds those six plus `GetSamplerObject`/`GetTextureParamsVersion`/`GetContentVersion` to
|
|
`RefuseLegacyTextureArmFromApplyThread` (`MipmapStorage.cpp:39-51`) and its
|
|
`MGL_TEXTURE_GUARD_TEST` rows `:1942-1978`. Revert the handle arm -> each aborts by name.
|
|
2. **`Fatal{UnmigratedPipeInput,"GetTextureUnitObject@DrawVbo"}`** under
|
|
`MOBILEGL_IPC_STRICT_ERRORS=1` (`PipeInputs.cpp:71-77`, `:191-224`), where the row is
|
|
BARRIER_PULLED and the read today only counts as `rsp`: revert `ResolveAndBindUnitTextures`'
|
|
window arm -> strict lane red at the named field+verb. **3.** And an integration assertion over
|
|
`PipeSlotPeek` (`MG_IntegrationTest/Harness/PipeSlotPeek.h`) that
|
|
`MGPipeFrontendKeyedRegistryScope` entries for this family are **0** over a frame; the mint is
|
|
already `Fatal{RoleViolation,"MGPipeSlots"}` (`SlotTables.h:255-266`).
|
|
4. **`DirectGLESTextureSync.UnitMemoRefusesToDriveATwinFromAnotherTexture`**
|
|
(`MG_Test/SanityTest.cpp:3075-3144`) is the `PairingsIntact` pin: keep it for monolith/pull,
|
|
and give it a handle-arm sibling whose hazard is ABA — recycle the slot to `{slot, gen+1}`
|
|
while the old entry is in the work list, assert the twin is re-minted
|
|
(`SlotTables.h:316-340`'s forward/backward rule answers it).
|
|
5. **`TextureParamsWithoutASamplerViewScenario`** stays green (the D10/G9 pin), i.e. the view
|
|
window must not become the ONLY path into `SyncTextureParamsToBackend`; and
|
|
**`SampledSetStalenessScenario`** — a texture that becomes complete with no rebind must
|
|
re-enter the sampled set, which under the new key is `SamplerViewsSerial` moving; revert
|
|
`Tracker.h:605-610`'s `textureParams` mix -> red.
|
|
|
|
## 7. Risks and what I could not settle
|
|
|
|
- **R1 — the window is not pinned (A8).** Everything in §4 reads
|
|
`[SamplerViewStart, +SamplerViewCount)`. `SamplerEmit.h:735-737` emits `Start=0,
|
|
Count=maxTouched+1`, but `PipeApply.h:666-669` says only "the last set as received" and does not
|
|
require coverage; under run-ahead a too-narrow window silently drops a sync, and a decline is
|
|
what run-ahead cannot take. **P5e needs a contract sentence**: the window MUST cover
|
|
`[0, MaxTouchedTextureUnit]`, narrower is `Fatal{ProtocolCorruption,"SetSamplerViews.Count"}` —
|
|
not a server-side re-derivation.
|
|
- **R2 — the program key (conflict with S4).** `BindCurrentTextures`' memo `:5277-5284` reads the
|
|
frontend `ProgramObject`; my design deletes the alias arbiter but not that key. **Ruling needed:**
|
|
key it on `st.DrawProgram` + `ProgramBindingSerial` (S4's rows), or on `SamplerViewsSerial` alone
|
|
— which already mixes the program-resolved opaque units (`Tracker.h:605-610`)? I lean to the
|
|
latter (one fewer cross-family key) but could not rule out that a relink with unchanged
|
|
resolution must still re-bind.
|
|
- **R3 — `RequireImageBindableStorage` under run-ahead.** §3 G-S2-5. It aborts today, but three
|
|
frames deep at a `MarkStorageDirty` guard rather than as a named refusal at the entry; run-ahead
|
|
turns a decline into a hard stop. How often `ImageBindableHint` fails to prevent it is unmeasured.
|
|
- **R4 — the twin's mutable flags.** `m_forceTextureParamsResync`/`m_forceSamplerResync` are
|
|
server-set and read-not-cleared from the wire (D-E2) — server memory, safe — but the new gate
|
|
reads BOTH them and the wire bits, so "neither side clears the other's" becomes load-bearing for
|
|
a gate, not just for a push. One contract sentence.
|
|
- **R5 — buffer textures.** `Managers.cpp:8223-8231` still hands the frontend `BufferObject` to
|
|
`EnsureBufferResourceForHandle` (D-A4's `frontend` argument). `Desc.BufferForTexBuffer` names the
|
|
buffer; whether `frontend` may be `nullptr` under split is **S1/S5's call** — the E note says the
|
|
transport arm reads nothing from the object (`Managers.cpp:3199+`), which suggests yes.
|
|
- **R6 — unmeasured.** This family's share of the apply thread at `2fde7034` is unknown; the E
|
|
note's 3.0% `HandleOf<ITextureObject>` is at `85362a85`, pre-round-3. Re-measure before sizing.
|