15 KiB
tx2 — textures and samplers by handle and window (P5e wave 2)
Branch p5e/tx2, head 1c872710, base f6cfcbd3 (landed wave 1). Tree ~/w7/p5e-tx2.
Five commits: 72e79020 (the family by handle), 85959090 (two the lane found), a08b3379 (tests),
99211a48 (the ABA case re-aimed), 1c872710 (a comment fix).
1 What changed, per file
Managers.h — BackendTextureObject gains m_pushedSyncHandle (§4.1's m_handle) +
NotePushedSyncHandle/PushedSyncHandle (:1940-1960, push-only, so the pull layout does not
move); IsDrawSyncCleanByRecord (:1740-1775); RequireImageBindableStorageByHandle
(:1675-1695); SyncTextureViewToBackendByRecord (:1645-1665); ResolveOwnRecord +
ResolvePushedBuiltinSampler's record parameter (:1895-1910).
Managers.cpp — ResolveOwnRecord (:8752-8772) is the whole of "the handle first, the
client allocator only failing that", and the two prologues lose their HandleOf probes; the three
sync bodies tolerate a null frontend object on the handle arm and answer GetTarget from
Desc.Target, the ~20 GetExternalIndex log reads from Desc.GlNameForDiag, the storage-kind
backstop from Desc.StorageKind (three macros beside the P4a/P5c ones);
SyncMipmapsToBackend's record resolution is hoisted to the top so the VIEW test can read
Desc.ViewOf (:7285-7310); the buffer arm reads Desc.BufferForTexBuffer / BufOffset / BufSize
and passes nullptr to EnsureBufferResourceForHandle (:8415-8600);
RequireImageBindableStorageByHandle (:5879-5930); SyncTextureViewToBackendByRecord
(:7015-7065); the two c0e seams bodied (:14100-14200).
DirectGLES.cpp — UnitTexturesByHandle() (:2170-2185) is the one arm selector
(Transport != Monolith && SamplerSubsystemEnabled() && TextureResourceSubsystemEnabled());
UnitTextureSyncByHandleEntry + its list and keys (:2186-2215); the unit half of
SyncNeccessaryTextures (:2420-2485); CurrentUnitBindingsEpoch's decline → refusal
(:2092-2112); ResolveAndBindUnitTextures' window arm (:4990-5065);
ResolveUnitSamplerBackend → refusal at the entry (:5205-5230); BindCurrentUnitSamplers'
decline → refusal (:5330-5350); BindCurrentTextures' ruling-6 key, entry selection included
(:5460-5600); the sampler pass by record (:5880-5960); NeedsRawDepthFetchSampler's
values-taking overload (:286-310); GenerateMipmapByRecord (:10062-10112) and
GenerateMipmap's VerbMipRes arm (:10120-10145); the two mip-shape HandleOf sites deleted
in favour of Generate{Depth,Color}Texture2DMipmapByRecord (:9660-9700);
ScopedDetachedTextureFramebufferAttachments' by-handle constructor over the applier's
framebuffer records (:9215-9290); both CopyTex destinations synced by handle (:9780, :9900).
MG_State/GLState/TextureState/MipmapStorage.cpp — the guard list gains the seven read-only
shape accessors through RefuseLegacyTextureShapeReadFromApplyThread, which is keyed on the
server backend being DirectGLES (ruling 12's shape). The mutator rows stay unconditional.
MG_Remote/Server/PipeApplier.cpp — CheckUnitWindows(st, verb) (:437-495) called from
OnDrawVbo (:515) and OnLaunchGrid (:738).
Tests — RemoteClientTest.cpp seven new MGL_TEXTURE_GUARD_TEST rows; SanityTest.cpp
ARecycledTextureSlotReMintsTheTwinOnTheHandleArm + its pull-build skip twin.
2 The kimi audit's texture/sampler rows (35-67)
RETIRED under a transport: 35, 36, 37 (the snapshot walk is now unreachable: the decline that
led to it is a named refusal) · 38, 39, 40, 42 (the unit list is st.BoundSamplerViews[],
the gate is IsDrawSyncCleanByRecord) · 47, 48, 49 on the by-handle entry (the frontend entry
survives as monolith glue and is still reached from fb's three attachment lists) · 50, 51, 52,
53 (ResolveAndBindUnitTextures is one pass over the window; the target is the view CSO's; the
unbind walks the fixed TextureTarget enum against g_boundTexturesCache) · 54, 55, 56, 57,
58 (the identity sampler family) · 59, 60, 62 (VerbMipRes + the descriptor) · 63 (the
detach sweep by handle over the framebuffer records) · 66 (the four HandleOf probes; they
survive only as the no-handle-noted fallback).
LEFT BARRIERED / trailing: 61 GenerateThreeChannelFloatMipmapOnCpu — named
Fatal{UnmigratedEmulation, "generate-mipmap-cpu-filter"} at the entry of the arm that would use
it; the pull is P8/P9's · 64 UpdateTextureBindingAtTarget's GetTextureUnitObject (CopyTex
is kWaitApplied) · 65 already monolith-only at the base.
NOT MINE (fb's rows, untouched): 41, 43, 44, 45, 46, 67. NOT FOUND: none — every row of 35-67 exists at this head.
3 Named behaviour deltas (G1 §)
- P5e-5, the narrowing. The unit list syncs the PROGRAM-RESOLVED texture per unit; the
frontend walk syncs every slot of every touched unit. What stops being synced as a side effect is
a texture bound to a touched unit that the program does not sample. Coverage is unchanged because
the union covers it — views ∪ image units ∪ attachment lists ∪ the waited texture ops — and the
lane proved the last term is load-bearing rather than rhetorical:
F1WireScenario.CopyTexSubImage2DPixelswent black, because a copy DESTINATION is bound to the active unit and sampled by nobody. Both CopyTex endpoints now sync themselves by handle — the only case the 111-entry lane found, and the shape any future "bound but not sampled" consumer has to copy. - Ruling 1 / G1. Every handle arm is selected by
Transport != MonolithAND the two family bits; the push-monolith build keeps the frontend view test,RequireImageBindableStorage, the unit walk and theGenerateMipmapbody token for token. The pull build compiles none of the new members, soBackendTextureObject's pull layout does not move and the admitted resize set stays empty. UnitTextureSyncEntryis NOT re-shaped in place. A second push-only struct (UnitTextureSyncByHandleEntry) and a second list are added beside it, because the same struct is also the draw-FBO and read-FBO attachment lists' — those are fb's, and one name carrying two shapes across two worktrees is the merge trap the contract package exists to avoid. Deviation from the brief's "re-shape, push-only"; the observable effect is identical.- Scout R4, made explicit in code and here.
IsDrawSyncCleanByRecordreads BOTHParams.ForceResync/Params.SamplerResync(the client's bits, read and never written back) ANDm_forceTextureParamsResync/m_forceSamplerResync(the server's, set byRecreateBackendTexture/ the image-bindable transition and cleared only by the prologue that consumed them). Neither side clears the other's. A gate that read one side would skip the sync the other is asking for, and for the sampler half that is not mis-filtering but an INCOMPLETE texture sampling (0,0,0,1). - Scout R5, resolved. The buffer-texture arm passes
nullptrtoEnsureBufferResourceForHandle: that function's three frontend reads are all inside its monolith arm (kimi row 29), sonullptris the whole of the split answer and is what §4.2's Buffer row prescribes. Whole-vs-range stops asking the buffer for its size —kMGPipeWholeBufferIS the question.
4 Red-once evidence (executed, quoted, reverted)
- Revert the handle arm (
UnitTexturesByHandle() → falseandMGB_STAGED_TEXTURE_LIVE → false),ctest -R DirectGLES.Split.TriangleScenario→ 0/2 passed:MGPipe: Fatal{RoleViolation, "texture-legacy-arm"} - the apply thread called TextureObjectMipmap::GetMipmapLevelCount on a frontend object. With an active transport the server reads the staged-texture store and the resource descriptor (CONTRACT-P5C §2, rule E); a frontend texture's level storage is client memory and this arm is monolith-only - Revert the unit work list's handle arm, full strict lane →
MGPipe: Fatal{UnmigratedPipeInput, "GetTextureUnitObject@Clear"} [BARRIER-PULLED, MOBILEGL_IPC_STRICT_ERRORS=1, retires in P5e (Espryt unbarriered), P7 (Magma)]on 9 entries — byte for byte the BEFORE table below. RevertingResolveAndBindUnitTextures' window arm ALONE changes nothing in the lane (48/14/13/6/3/2, identical to the after table): with fb and vi unlanded, no entry survives to a draw's unit walk, soGetTextureUnitObject@DrawVbocannot be any entry's FIRST pulled row. The brief's expected marker is therefore unreachable on this tree and the unit-list form above is the one that names the field. - ABA: drop the forward-Gen reset in
BackendSlotTable::GetOrCreate(handle)→ARecycledTextureSlotReMintsTheTwinOnTheHandleArmfails:Expected equality of these values: *secondSlot / Which is: (ptr = 0x592a99c35310, ...) / nullptrandValue of: MG_Pipe::MGPipeHandleIsNull((*secondSlot)->PushedSyncHandle()) / Actual: false / Expected: true. - Narrow
SamplerEmit.h'sCountby one → isplit 80% (22 of 111 red):MGPipe: Fatal{ProtocolCorruption, "SetSamplerViews.Count"} - draw_vbo applies with units 0..0 touched, so set_sampler_views must carry Start=0 and Count >= 1 (CONTRACT-P5E.md §5.3); the applied window is Start=0 Count=0, which drops the sync of at least one texture this draw samples— and the dispatch twin, verbatim, withlaunch_gridin place ofdraw_vbo. - Revert
GenerateMipmap'sVerbMipResarm, strict on the three split F1 GenerateMipmap entries →MGPipe: Fatal{UnmigratedPipeInput, "GetTextureUnitObject@GenerateMipmap"} [BARRIER-PULLED, ...]inp5b-f1-GenerateMipmapDepth.logandp5b-f1-GenerateMipmapPackedFloat.log; with the arm present those two abort on fb'sGetFramebufferBindingSlot@ReadPixelsinstead. Plain isplit also goes 2/3 red with the arm reverted.
5 Gate
| step | result |
|---|---|
| build | rc=0 |
| unit | 2214/2214 (2206 at the base + 8 new: 7 guard rows + the ABA case) |
integration-split |
111/111 |
| gens | all 7 rc=0; the one doc-citation line (CONTRACT-P5.md:524 Core.cpp:39 ambiguous) is pre-existing and not mine |
one |
242/242 on `SampledSetStalenessScenario |
| strict | 3 passed / 108 failed, unchanged from the base (the lane is red by design until fb, vi, pg and sb land) |
Strict markers, before and after, measured on THIS tree's own base (f6cfcbd3), 88 private logs:
| marker | before | after |
|---|---|---|
GetFramebufferBindingSlot@Clear (fb) |
39 | 48 |
GetBoundVertexArray@DrawArrays (vi) |
14 | 14 |
GetImageTextureBinding@BindImageTexture (fb) |
13 | 13 |
GetTextureUnitObject@Clear (tx2) |
9 | 0 |
GetTextureObject@CopyImageSubData (P5b debt) |
6 | 6 |
GetProgramForDispatch@DispatchCompute (pg) |
3 | 3 |
ValidateProgramName@ShaderStorageBlockBinding (pg) |
2 | 2 |
The only field that disappeared is mine; the only field that grew is fb's, by exactly the nine
entries that used to abort at mine first. GetTextureUnitObject is gone from the lane entirely.
6 Seams assumed, and what I coded against
SyncMipmapsToBackendByHandle(handle)is bodied as c0e declared it (handle only): it resolves the record itself and stampsm_pushedSyncHandle, so fb's attachment sync and image sweep can call it with nothing but aMGPSurface::Res/MGPImageView::Res.SyncTextureToBackendByHandlereturnsSharedPtr<...>&; a decline is a reference to a NULL twin, so callers must test it.ResolveTextureTwin(id's) is used unchanged and NOT edited - it does not stamp the handle; the two by-handle SYNC entries do.- fb's reverse index was not available, so
ScopedDetachedTextureFramebufferAttachments' handle arm walksMGPipeApplierState::FramebufferRecordFor()directly; if fb lands an index, that constructor is one call site to re-point. - pg's half of ruling 6: keyed on
{DrawProgram.{Slot,Gen}, ShaderCso.Serial, BindingsSerial}throughPipeShaderCsoRecordForHandle(st.DrawProgram); if pg movesBindingsSerial's writer the key follows with no edit here.BindCurrentTexturesstill RECEIVES pg'scurrentProgramand no longer reads it on the handle arm, entry selection included.
7 Rulings I need
- Texture VIEWS have no wire carrier for the view window.
Desc.ViewOfnames the storage owner, butminLevel/numLevels/minLayer/numLayersare on no record. The STEADY question is answered server-side (sync the storage twin by handle, comparem_viewSourceBackendTextureId, stamp the serial); the CREATION of the view still needs the frontend object and takes it when the monolith-glue note reaches one, with a namedMGLOG_E_ONCEwhen it does not.TextureViewScenariois not inintegration-split, so nothing goes red today. Ruling wanted: fourUint16s onMGPResourceDesc(it has no spare pad, so this grows it) in a later package, or the view arm stays barriered and trailing. GenerateMipmap'sWaitClassis NOT flipped, per ruling 14's escape. The unit read is gone, but the RGB16F/RGB32F CPU filter still reaches the client's level shadows (kimi 61), so the arm is not complete. Trailing item for tx2 or P8.CheckUnitWindowsadmits one silence: both counts still 0 means the client's sampler subsystem bit is clear and the backend runs its frontend walk, so there is no window to check. Narrowing carries a non-zero-but-too-small count and is refused. Confirm this is the intended reading of ID-95, or the check has to be armed off the caps/subsystem mask instead.- The widened
MipmapStoragerows are backend-kind-keyed. The unconditional widening aborted Magma'sBlitNamedFramebuffer→ResolveColorBlitBinding→IsComplete()(two isplit entries). Ruling 12's shape applied: the new READ rows abort on DirectGLES and are silent on DirectVulkan; the MUTATOR rows stay unconditional. Confirm, or Magma's blit path opensMGPipeTextureLegacyArmScopeinstead (VulkanRenderer.cpp is not in my scope).
8 What I did not do
- The
PipeSlotPeekzero-scope-entries-per-frame assertion.PipeSlotPeekreads the CLIENT allocator's occupancy; there is no per-frame counter ofMGPipeFrontendKeyedRegistryScopeentries and adding one would be hot-path instrumentation the roadmap forbids. The stronger observable already exists and is unconditional: once ra lands, ANY frontend-keyed probe from an unbarriered apply isFatal{RoleViolation, "MGPipeSlots"}. The family's remaining scope sites (DirectGLES.cpp:1745, :5137, :5223,Managers.cpp:5996, :8757) are all monolith-glue halves the transport arms return in front of; the draw path reaches none of them. - The CopyTex ENDPOINT resolve and
GetTexImage— barriered and trailing, as the brief scopes them.set_texture_params' reply and theresource_subdatatexture half — likewise untouched. - No measurement of this family's apply-thread share (scout R6): it belongs with the device exit.