mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 10:03:23 +09:00
db2196fb08d8d8554cb781ee49bee5b093a4d56e
3139
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
db2196fb08 |
Merge branch 'p5e/tx2' into feat/disaggregated (P5e tx2)
# Conflicts: # MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp |
||
|
|
30e385812d |
Merge branch 'p5e/pg' into feat/disaggregated (P5e pg)
# Conflicts: # MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp # MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp |
||
|
|
5b226f16ae |
Merge branch 'p5e/sb' into feat/disaggregated (P5e sb)
# Conflicts: # MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp |
||
|
|
e0f69e8791 | Merge branch 'p5e/vi' into feat/disaggregated (P5e vi) | ||
|
|
4d1499ef7e |
[MG_Test] (Disaggregated): P5e pg - four cases for the bindings record, the failed relink and the framed archive
- AUniformBlockBindingAfterTheLinkTravelsOnItsOwnRecord: the create unlatches the bindings and the first emission after it always goes out (the ordering the applier depends on), an unchanged binding set emits nothing, and a post-link unit assignment moves the latch. This is the case the package's first red-once is built on: the integration-split lane has no scenario with a named uniform block bound to a non-zero point, so emptying the tail there is invisible and the statement has to be made here. - TheThreeBindingTailsAreWholeSetsAndAReIssuedCreateDropsThem: whole-set replacement in all three tails, the override NAME copied rather than pointed at (rule C), BindingsSerial advancing, and the re-issued create dropping every tail because they index into the archive it just replaced. - AFailedRelinkReIssuesWithLinkStatusZeroAndNeverAnObjectDeath: ID-88's "iff the frontend reports it unlinked" is asserted against the frontend rather than assumed, so the day Link()'s prologue stops withdrawing LINK_STATUS this case says the ruling has to be re-decided instead of the server silently drawing a dead executable. - TheFramedArchiveRoundTripsWithTheStageOfEveryModule: two modules of the SAME stage - the shape MGPProgramDesc::StageMask cannot describe - survive the frame, the skipped member comes back null, and a truncated frame is refused with both outputs defined. |
||
|
|
1c8727102c |
[MG_Backend] (Disaggregated): P5e tx2 - name the two entries that actually stamp the sync handle
- ResolveTextureTwin is the lookup WITHOUT the sync and does not stamp it; the comment said it did. |
||
|
|
b004e5dcbb |
[MG_Backend] (Disaggregated): P5e sb - Espryt's four binding-point walks read the record
- SyncBufferBindingPointsByRecord(class, glTarget), file-local beside the walk it replaces: the window is the applier's ShaderBufferStart/Count, each entry resolves through EnsureBufferResourceForHandle(nullptr, Res), and whole-vs-range is `Offset == 0 && Size == kMGPipeWholeBuffer` - so obj->GetSize() leaves the function and the extent of a base binding is re-resolved HERE, against this server's own storage, which is what makes a glBufferData between the emission and the apply bind the new extent as GL does. The ES clamp stays exactly where it was: the device ceiling is a server question. - The arm is transport + bit 13, with bit 13 requiring bit 7 refused by name rather than half-run - ResolveVertexInputSubsystemArm's shape, and for its reason: without bit 7 every point would log once and `continue` WITHOUT unbinding. - SyncAtomicCounterBuffers reads the applier's window instead of GetBufferBindingPointCount's sticky forward; glBindings stays the backend program's own list. A binding outside the window takes the UNBIND arm rather than being skipped, because skipping would leave whatever the driver last had at that ESSL point. - The UBO loop's POINT half reads BoundShaderBuffers[Uniform][binding] in the same index space, with IsBufferDrawCleanByHandle / FindBufferResourceForHandle in place of the frontend probes. GetUniformBlockBinding above it is untouched - that line is package pg's. - MarkShaderStorageBuffersGpuWritten and SyncAtomicCounterBuffers' MarkBufferGpuWritten are DELETED under a transport. They walked client memory and wrote into a client object, which is the one thing that cannot survive run-ahead, and the client's own MarkGpuWritesForDraw has covered the same set since P5d. Withholding the client's two rows turns the atomic scenarios red (5 vs 13, 100 vs 116), which is what says the duplicate really is gone. - Every frontend arm is kept token for token under Transport=monolith (G1, ruling 1), as the `if (…) else` the indirect buffer already uses. |
||
|
|
99211a4807 |
[MG_Test] (Disaggregated): P5e tx2 - the ABA case asks the twin table, not the record
- MGPipeApplyResourceCreate declines a TEXTURE create on a process with no P4a consumer (NoP4aConsumer), which is every unit-lane process, so the record-driven shape of this case skipped instead of running. The ABA answer is the twin TABLE's - a forward generation resets the entry - so the case now drives g_backendTextureObjects directly and gates on EsprytSlotTablesEnabled() rather than on the family bit. - And it does NOT compare the successor's twin ADDRESS against the predecessor's: the reset released the predecessor, so the allocator hands the successor the same heap address, which is precisely why an address is never an identity here. "The slot came back empty" is the assertion. |
||
|
|
c5491ca675 |
[MG_Backend] (Disaggregated): P5e pg - the program twin is keyed by the ShaderCso handle
- BackendProgramObjectImpl::SyncToBackendByHandle is real. It and the frontend overload
feed ONE body (SyncToBackendFromSource) through ProgramArchiveSource, a view whose
accessors are ProgramObject's names one for one - so the body is written once and the
PULL build compiles the same text against a ProgramObject. In a pull build
ProgramBuildSource IS ProgramObject, the function keeps its own name and its null
guard, and G1's byte identity survives a rename and nothing else.
- The view answers the three POST-LINK MUTABLE reflection fields from the record's
set_program_bindings tails and everything else from the record's archive. The tails are
a whole-set replacement, so a location the sampler tail does not name has NO unit - not
whatever the link-time snapshot said - and "has a bindings record been applied at all"
is BindingsSerial != 0 rather than a non-empty tail.
- The nine-clause clean condition keeps its clause count and moves its inputs (D-H5):
record.Serial vs the m_syncedShaderCsoSerial stamp P4a landed and nothing has read
until now, BindingsSerial vs a new m_syncedBindingsSerial (a glUniform1i on an IMAGE
uniform is baked into the ESSL, so the record that carries it must force a rebuild),
record.Signature, Desc.LinkStatus and Desc.SpirvStatus.
- The signature has ONE authority per arm: the handle arm stamps and compares the
CLIENT's number verbatim, so the two commutative hashes never have to stay
bit-identical for a program with an override to stop rebuilding every draw.
- DirectGLES: SyncCurrentProgramByHandle, the stash re-keyed on the handle,
PrepareForDraw/PrepareForCompute reading MGPipeApplier().DrawProgram/DispatchProgram,
BindCurrentProgramWithResources and GetCurrentBackendProgram on the handle arm, the
block binding and the sampler unit from the record's tails, and the sampler-pass memo
on BindingsSerial instead of the frontend's backend-state version.
- MapUBO() has no run-ahead answer and now says so: every decline of
ResolveGlobalConstantsRecord under a transport is Fatal{UnmigratedVerb,
"set_global_constants"} rather than a torn read of the client's live globalUboScratch.
- The fragColor broadcast count takes a POLICY, because a dispatch is a third case: it
has no draw framebuffer and no fragment stage, PrepareForCompute runs no SyncCurrentFBO,
so it may neither fall back to a client row nor abort when the records are untrusted.
- Three of the family's five named frontend-keyed scope sites are now unreachable under a
transport (ResolveGlobalConstantsRecord, SyncCurrentProgram,
BindCurrentProgramWithResources). The other two are kept BY CONTRACT (§5.5):
GetBackendProgramId is a GL-thread entry point and ShaderStorageBlockBinding is reached
from the barriered set_storage_block_binding, which is pg's trailing item.
|
||
|
|
112c1d8dfc |
[MG_Test] (Disaggregated): P5e vi - the two source decisions, the window rule and the client-array lane
- SanityTest's DirectGLESVertexInputDraw pair drives the PRODUCTION decisions (ResolveDrawVertexBuffersFromRecord / ResolveDrawIndexBufferFromRecord) with the frontend VAO deliberately pointing at a buffer the record does not name - the state a run-ahead client makes ordinary and one process cannot otherwise produce. Both functions take the applier state and nothing else, so the only revert is a frontend read inside them and the cases then go red naming the field (ID-102's rule about what a red-once may test). G2/G14 skip twins in the pull arm. - VertexInputEmit pins ID-95 / ruling 19 on the producer side: set_vertex_buffers' window must cover every attribute create_vertex_elements declares ENABLED, with a sparse configuration so "covers the enabled set" is not "is as long as the array". The sink half is tx2's CheckUnitWindows. - ClientVertexArrayScenario is BRIEF-P5E's open item (a), answered: NO existing scenario exercises a client-memory vertex array under split (DoublePrecisionScenario uses the binding-model calls against real buffers), so the lane had no entry that could reach the refusal at all. Registered in the split lane with a private log path, and it is also the positive control for keeping the upload arm alive under lockstep. |
||
|
|
4fc93c1ab9 |
[MG_Remote] (Disaggregated): P5e vi - kDrawClientArrays on the wire, and the run-ahead refusal
- ReadDrawBindings answers ClientVertexArrays in the SAME single read of the bindings the
rest of the draw plan is made from: an enabled attribute with no buffer behind it, which is
exactly what EmitVertexBuffers publishes as Res == kMGPipeNullHandle.
- PlanDrawInfo sets kDrawClientArrays for every draw shape, not only the array ones - a
glDrawElements can fetch its VERTICES from client memory too - because MGPipeBarriered is
computed from the record on both sides and a null Res inside the window is also what a
disabled attribute publishes.
- EmitDrawRecord and the reduced DrawArrays path refuse such a draw under run-ahead with
Fatal{UnmigratedVerb, "DrawArrays+CLIENT_ARRAYS"} on the GL thread, before the hooks
(ID-82 / ruling 2). LOCKSTEP IS UNCHANGED: the client is parked in WaitForApplied for that
record, so the server's upload reads memory that is not moving (ruling 4). Staging the
bytes as a per-attribute {BindingIndex, MGHostSpan} tail is P8's.
- The armed predicate is spelled here from the three inputs MGPipeTypes.h names for
RunAheadArmed() rather than called, because ClientSession::RunAheadArmed is package ra's;
it is inert until the integration commit publishes the caps bit, and ra collapses this
body into that latch.
|
||
|
|
a04cf05c93 |
[MG_Backend] (Disaggregated): P5e vi - the VAO, its buffers and its index buffer come from the records
- ResolveVaoTwin takes st.BoundVertexElements under a transport (id's by-handle body); the
frontend overload survives as monolith glue and its MGPipeFrontendKeyedRegistryScope is
DELETED, which is what makes a revert of the twin key abort instead of being exempted
(CONTRACT-P5E §4.1, §4.4, §5.8). Two of this family's three scope sites go with it.
- SyncVaoAttributeBuffersByRecord beside SyncVaoAttributeBuffersByHandle: the walk is over
st.VertexBuffers[Start..+Count).Res, deduped on {slot, gen}, ensured with
EnsureBufferResourceForHandle(nullptr, Res) and probed with a null frontend. The
push-monolith arm keeps its frontend walk token for token (ruling 1 / ID-81).
- The IBO arm reads st.IndexBuffer.Res with st.IndexBufferSerial, and the serial JOINS the
identity compare because this arm has no live element slot to re-read: a re-emitted
set_index_buffer on the same handle would otherwise read clean. ResolvedDrawBuffers gains
iboSerial; Entry::frontend stays declared for the legacy arm and is never written here.
- PrepareForDraw stops reading GetBoundVertexArray and GetConfigVersion under a transport;
SyncCurrentVertexAttributeValues keys on {elementsHandle, ContentSerial, activeMask} and
reads rec->Attributes[i].Enabled. The two program reads there are pg's and stay.
- The DrawArrays / MultiDrawArrays client-array arms resolve the twin by handle and take the
frontend VAO only when the RECORD says an enabled attribute is client-sourced, which is
what retires GetBoundVertexArray@DrawArrays for every ordinary draw.
- The two source decisions are named functions over the applier state alone
(ResolveDrawVertexBuffersFromRecord / ResolveDrawIndexBufferFromRecord) so a unit case can
drive the production decision rather than a copy of it.
- BumpBufferMutationEpoch pins BRIEF-P5E's open question 2: a bump off the apply thread while
one is running is counted and Fatal under the strict lane. The measured answer is that the
only non-apply-thread bump in the tree is BackendObject_DirectGLES::Initialize's
RegisterBufferBackendOps, before the apply thread exists.
- The restart helpers refuse a frontend element-slot read under a transport by name; the
substitution's own body already resolved from the applier since P5c.
|
||
|
|
1ebe6abeb2 |
[MG_Pipe, MG_Impl, MG_State, MG_Remote, MG_Backend, MG_Test] (Disaggregated): P5e sb - set_shader_buffers is emitted, routed and applied
- MGPShaderBuffers::WritableMask is Uint32[3] and the POD grows 32 -> 40 (ID-104). One Uint32 could describe only the first 32 of an 84-point window, so a storage buffer bound at point 32 or above read as unwritable with nothing able to see it; the ruling widens the field rather than narrowing the window, which would change what an application may bind. MGPipeShaderBufferMaskHas / ...Set are the one spelling of the mask, so the emitter, the applier and the four backend sites cannot disagree about which word a point lives in. - MGPipeApplySetShaderBuffers has its body: per-class window, Start/Count validated against the capacity, the mask copied by word, ONE ShaderBuffersSerial advanced on every applied record and ADVANCED - never zeroed - by both resets, which also clear the three windows. - Route rows for opcode 38 on both arms (Mono_ and Wire_) and the server sink in the wire codec's decode switch, which is where a kCtxState row's sink lives - PipeApplier.cpp's ServerVerbSink has no method for it and the brief's "OnSetShaderBuffers" names no code. The codec also bounds Class and Start+Count where Count becomes a byte length. - New MG_Impl/Pipe/ShaderBufferEmit.h: one record per class, window = the touched high-water mark clamped to 84, zero early-out before any hash, a BASE binding travelling as kMGPipeWholeBuffer so the server re-resolves the extent at use, three suppressor slots (ruling 11), and the writable mask that replaces the backend's GPU-write walk. - BufferState gains a per-target bind-point generation (push-only, G1) and dirty bits 15/16/17 shutter on it instead of the buffer CONTENT aggregate. That aggregate answered the wrong question in both directions: any glBufferSubData fired all three, and glBindBufferBase fired none of them, because it mutates a binding point through a returned reference. Same defect class as P4a's glBindSampler hole. - Init.cpp publishes consumer bit 13 for DirectGLES and not for Magma (ID-106), in the same commit as the wired constant, and PipeFill's liveness gate asks R-8 for bit 13 in particular plus bit 13-requires-bit-7. - `Touch` joins the dirty-surface scanner's mutator prefixes; TouchBufferBindingPoint gets its row and SetNamedTransformFeedbackBinding's is rewritten now that bit 17 reads a generation a binding moves. Negative control 6 is re-pointed: the pair it used to refute is a live answer, and a control that has quietly become positive is what the self-test is for. |
||
|
|
a08b337975 |
[MG_Test] (Disaggregated): P5e tx2 - the seven shape reads become pinned guard rows, and ABA gets its own case
- RemoteClientTest's MGL_TEXTURE_GUARD_TEST block gains the seven MipmapStorage shape
reads P5c deliberately exempted, with the sentence that exempted them ("the per-draw
binding walk reads them every draw") replaced by the reason it is no longer true.
- SanityTest gains ARecycledTextureSlotReMintsTheTwinOnTheHandleArm beside
UnitMemoRefusesToDriveATwinFromAnotherTexture: the borrowed-slot list needs a pointer
compare because its key is derived state; the by-handle list needs none, because a
recycled slot arrives as {s, g+1} and the forward-Gen reset gives the successor a fresh
twin while the predecessor's handle stops resolving. G2/G14 skip twin included.
|
||
|
|
859590901a |
[MG_Backend, MG_State] (Disaggregated): P5e tx2 - the two the lane found: Magma's blit read and the copy endpoint's own sync
- The widened MipmapStorage rows are backend-kind-keyed (ruling 12's shape): Magma is lockstep through P7 and its named blit still asks a frontend texture IsComplete() (VulkanRenderer's ResolveColorBlitBinding), which the unconditional widening aborted. The MUTATOR rows stay unconditional - no backend may write a frontend texture's storage from the apply thread, and none does. - CopyTexImage2D / CopyTexSubImage2D sync their DESTINATION by handle instead of merely looking its twin up. A copy destination is not sampled by the draw program, so the sampler-view window never brings it across; the pre-P5e frontend walk over every slot of every touched unit happened to sync it as a side effect. This is the "waited texture ops" term of the named narrowing (P5e-5) being made real rather than assumed. |
||
|
|
72e7902080 |
[MG_Backend, MG_State, MG_Remote] (Disaggregated): P5e tx2 - the texture family by handle, the unit window, and the guard that notices
- SyncTextureToBackendByHandle and SyncMipmapsToBackendByHandle get their bodies
(the c0e seams): record first, twin by GetOrCreateByHandle, three syncs from the
record, no frontend touch and no allocator probe on the path.
- BackendTextureObject carries m_pushedSyncHandle (CONTRACT-P5E §4.1's m_handle), which
is what the three sync prologues read instead of probing the client allocator with
HandleOf, and what selects the by-handle arm inside them.
- IsDrawSyncCleanByRecord replaces IsDrawSyncClean(frontend) on the memo-hit path: the
same conjunction over the record's serials and the twin's own, with BOTH halves of each
resync pair read and neither clearing the other's (D-E2, scout R4).
- The unit work list is built from st.BoundSamplerViews[] and keyed on
(ContextSerial, SamplerViewsSerial, window, backend context generation); PairingsIntact
is not carried on it, because a {slot, gen} has no stale-pairing hazard to catch.
- ResolveAndBindUnitTextures is one pass over the window with the target from the view
CSO, then an unbind driven by g_boundTexturesCache; the alias arbiter dies (the client
arbitrated, SamplerEmit.h).
- BindCurrentTextures' memo key is ruling 6's both halves, entry selection included.
- The sampler pass reads BoundSamplerStates / the built-in sampler CSO / the view's
InternalFormat; the apply-thread mint and ResolveUnitSamplerBackend become a named
refusal under a transport (§4.2).
- GenerateMipmap resolves VerbMipRes and never the active unit; the detach sweep is keyed
by the texture handle over the applier's framebuffer records. The row is NOT flipped to
kWaitNone: the RGB16F/RGB32F CPU filter still reaches the client's level shadows, so
ruling 14's escape applies and the flip is trailing.
- RequireImageBindableStorage gets a by-handle entry whose re-dirty is
Fatal{UnmigratedEmulation, "image-bindable-redirty"} at the entry rather than three
frames deep at a MarkStorageDirty guard.
- The buffer-texture arm resolves scout R5 with Desc.BufferForTexBuffer / BufOffset /
BufSize and EnsureBufferResourceForHandle(nullptr, h) - that function is client-free
under an active transport (kimi audit row 29).
- CheckUnitWindows(st) at draw and dispatch makes the §5.3 window promise checkable and
checked: narrower than [0, MaxTouchedTextureUnit] is
Fatal{ProtocolCorruption, "SetSamplerViews.Count"} / "BindSamplerStates.Count".
- MipmapStorage's guard list gains the read-only shape accessors P5c deliberately
exempted, now that nothing on the draw path reads them.
|
||
|
|
39d0677616 |
[MG_Pipe, MG_Impl, MG_Remote, MG_State, MG_Test] (Disaggregated): P5e pg - the archive becomes server-owned and the bindings get a record
- MGPipeShaderCsoRecord gains Archive, a SharedPtr<const ProgramArchive> the create
ADOPTS under a transport. Before this the applier stored the descriptor and the two
companion pointers named the frontend's own LinkArtifacts/SpirvArtifacts, which
ProgramObject::Link() replaces in place - so every reflection read on the apply thread
was torn or stale by construction the moment the client runs ahead (gap G-A).
- MGPipeApplyCreateShaderState takes the archive as a fourth argument, undefaulted for
PipeRoute.h's stated reason: a caller that has one and forgets it would compile, and
the failure would be silent. Null on the monolith arm, which keeps its frontend arms
token for token (ruling 1 / ID-81).
- ProgramArtifactsCodec gains ProgramArchive and the FRAME. SpirvArtifacts carries no
stage list and MGPProgramDesc::StageMask cannot stand in for one: it is a bit set, and
GL lets two shader objects share a stage, so a list rebuilt from it can be shorter than
generatedSpirv - which the backend pairs with it by one running index.
- Codec completeness, as CONTRACT-P5E §5.5 asks: the skipped member is named
(LinkArtifacts::program, the live glslang TProgram) and proven unread by either backend
twin; the libc++ caveat at the size echo is read as what it is - a cross-toolchain
check, exact for an in-process split - and both verdicts are written where they were
asked for.
- set_program_bindings (opcode 80) lands end to end: EmitProgramBindings on the client,
the FIFTH ROUTE ESCAPE (three tails in three index spaces plus a parallel name array -
no generated row can express it, so op 80's gMGPipeContext slot stays null as
PipeCatalogueTest pins), the wire emitter, the decoder arm that resolves and
NUL-checks every name span, and the applier body that copies the names into the record
(rule C) and advances BindingsSerial.
- The record is emitted AFTER create_shader_state, not before as the draft note said: a
re-issued create clears all three tails because they index into the archive it just
replaced, so bindings published ahead of it are wiped by the create that follows.
- MGPProgramDesc::LinkStatus is filled, and ID-88 is VERIFIED rather than assumed:
ProgramObject::Link()'s prologue bumps m_linkVersion and assigns m_artifacts = {} -
"the complete not-linked state" - before the body runs, and every ProgramLinkTask
failure arm leaves linkStatus false. A failed relink therefore reports unlinked, the
re-issue carries LinkStatus = 0, and nothing needs an object_death.
- ID-87's measurement gets its instrument: the archive's byte count is added to
PipeStats' CsoBlobBytes where the bytes actually exist, one sample per link.
|
||
|
|
f6cfcbd36b |
[MG_Pipe, MG_Backend, MG_Remote, MG_Test] (Disaggregated): P5e wave 1 integration - one body per seam, and the stamp waits for ra
- c0e and id were implemented in parallel and each declared the two shared seams, so the merge produced five duplicate definitions the text could not collide: MGPipeBarriered, MGPipeApplierCurrentRecordIsBarriered and the three by-handle twin resolvers. Resolved per ID-99 and ID-103. - MGPipeBarriered keeps c0e's real body (the static wait-class column, the XFB escalation and the client-array escalation); id's constant-true placeholder goes. - The current-record flag keeps c0e's thread_local storage and setter and loses id's MGPipeApplierState member: it describes which record THIS THREAD is inside, not per-context state the applier owns, and the allocator guard that reads it would otherwise have to find the right context's applier first. id's test hook posts through the setter. - The three resolvers keep id's real bodies beside each registry; c0e's asserting stubs for them go. The seam stubs no package has bodied yet stay. - ApplyOne stamps `true` while kMGPipeP5eClientWaitRuleLanded is false. The predicate says what the client WILL do; until ra changes EmitAndWaitTails the client still blocks after every record, so a `false` stamp would withdraw the §4.4 exemption from a probe the client's own wait still makes safe. The predicate is computed on every record regardless, so it is exercised for the whole phase instead of first running on the day it starts deciding. - Gates on the merged tree: unit 2206/2206, integration-split 111/111, both generators --check/--self-test green, include closure 0 problems, dirty surface rc 0, doc citations one pre-existing CONTRACT-P5.md line (c0e retired another). |
||
|
|
367e473416 | Merge branch 'p5e/id' into feat/disaggregated (P5e id: handle-keyed twins, the barriered exemption, the scope rename) | ||
|
|
11cbf4b688 | Merge branch 'p5e/c0e' into feat/disaggregated (P5e c0e: the contract, the wait-class column, opcode 80, the knobs and the cross-package seams) | ||
|
|
a513c53ee3 |
[Docs] (Disaggregated): P5e c0e - fix the one citation the draft got wrong
- SlotAllocator.cpp:410-419 named lines that do not exist; the Gen-on-reuse rule is at :176-189 for the ordinary table and :240-258 for the composite band. The doc-citation lint now reports the same four pre-existing problems it reports at the base and no new one. |
||
|
|
b4cf9b0527 |
[Docs, MG_Remote] (Disaggregated): P5e c0e - the contract lands, and the roadmap row
- MG_Remote/CONTRACT-P5E.md: the draft edited into its landed form. The nineteen rulings are as the integrator decided them (ID-80..98) and are restated here rather than referenced, because a package reads this file and not the brief. The "draft" wording is gone and every file:line was re-resolved at this head. - FOUR PLACES WHERE THE PLAN WAS WRONG AND THE CODE IS RIGHT, each argued where it sits: the descriptor has no spare byte so MGPProgramDesc grew 192 -> 200; the applier's per-class windows are ShaderBufferStart/Count/WritableMask, not bare Start/Count/WritableMask; the three suppressor slots are named per Class; and the wire codec's layout carries three tails now, because set_program_bindings has three and the third one's offset is derived from the first two. - One finding the contract now carries rather than leaves for sb to discover: MGPShaderBuffers' WritableMask is a Uint32 and the window is 84, so the mask can only describe the first 32 points of a class. sb asks for the ruling; it is a wire field and not a package's to pick. - A new section 10 lists, by name, every symbol c0e put in the tree and what each package compiles against - plus the three red-once evidence lines. - ROADMAP.md gains the P5e row after P5d (status, the eight packages in dependency order, the integration gate and the device exit) and the two lines that said P6 was next now say P5e is. CURRENT_STAGE_PROGRESS.md section 1 gains its row and section 6 its next-step entry. |
||
|
|
c06878ef73 |
[MG_Pipe, MG_Impl, MG_Backend, MG_Test] (Disaggregated): P5e c0e - the cross-package seams
- MGPipeBarriered(op, payload, applierState), IMPLEMENTED, not stubbed: the static wait-class column plus the two payload-derived escalations the contract names (an open XFB span, a draw carrying kDrawClientArrays). One function and two callers is the point - the emit table and the sink must reach the same answer or the client runs on while the server reads a value that has already moved. set_context_values now mirrors IsTransformFeedbackActive into the applier state as well, because a predicate that read it out of gPipeInputs would be reading the very block run-ahead stops filling. - MGPipeApplierCurrentRecordIsBarriered() with the writer beside it. It answers true by default and that IS the landed lockstep answer, not a stub: on a server without kCapRunAheadApply every record is barriered and CONTRACT-P5C's two exemption scopes keep working unchanged. - The sb applier fields (BoundShaderBuffers[3][84], the three windows, the writable masks and ShaderBuffersSerial) and the pg record fields (the three binding tails, Signature, BindingsSerial) with the two entry points MGPipeApplySetShaderBuffers / MGPipeApplySetProgramBindings declared and ABORTING BY NAME. - The by-handle backend seams in Managers.h with aborting bodies in one block: ResolveVaoTwin, ResolveTextureTwin, ResolveProgramTwin, SyncTextureToBackendByHandle, SyncMipmapsToBackendByHandle, and the FBO / RBO / program SyncToBackendByHandle overloads. Five packages sit on opposite sides of these calls - tx2 writes what fb calls, fb writes what tx2 needs, id rekeys the registries all three read - so the signature is fixed once here and each family replaces a body. Abort and not null: a resolver that answered null renders a blank draw and a sync that did nothing renders stale pixels, and both are green lanes. - Coverage.def's GetBufferBindingPoint -> SetShaderBuffers row with BOTH of its PipeFill.cpp switch arms and the pairing asserts, shape-only and inert. It lands with the contract package because PipeFill.cpp belongs to the contract package for the whole phase - an emitter enumerator whose dispatch arm lived in the family's worktree is the merge trap that file's own comment was written about. - FieldOwnership.def re-annotates the six object-class rows plus GetProgramForDispatch to "P5e (Espryt unbarriered), P7 (Magma)", and the strict-abort case follows the string, which IS the debt entry rather than decoration. kMGPipeMaxBufferBindingPoints is pinned against BufferState.h's 84 where both are visible. gen_pipe_field_ownership's refusal count is 8. |
||
|
|
0117d15725 |
[MG_Test] (Disaggregated): P5e id - the band case, and the exemption scope stops exempting an unbarriered apply
- New DirectGLESSlotTable.ACompositeHandleDoesNotGrowTheOrdinaryTable (with its G2/G14 skip twin) pins the band: a composite handle grows m_band by four entries and the ORDINARY table by none, the lookup finds it, an ordinary slot beside it disturbs neither space, ForEachLive reports the composite at the slot THE CLIENT MINTED rather than at its band index, and §4.3's recycle answer holds inside the band. It asserts on the two spaces' CAPACITIES, not on liveness: the table holds one live entry either way, so LiveCount could not see the growth this case exists to catch. - RemoteGuards.AnAllocatorProbeInsideAnExemptionScopeOnTheApplyThreadIsAllowed is DELETED. It asserted that a named scope exempts unconditionally, which is the rule CONTRACT-P5E §4.4 retires. Its replacement, ...FromTheApplyThreadIsFatalEvenAtTheOldDebtSites, opens the same scope with the applier's CurrentRecordBarriered forced false and expects HandleOf to abort. The hook is the production field ApplyOne stamps, not a test-only branch beside it; the texture and the table are built on the CLIENT thread, because a TextureObject2D's constructor mints and building it on the apply thread would abort at the mint with the same diagnostic - a case passing for the wrong reason. - The green half of the deleted case needs no replacement: every Espryt integration-split entry runs the frontend-keyed scope's surviving sites on the apply thread behind barriered records, so a guard that stopped exempting would take the whole lane down. - Unit 2203 -> 2204 (the new name only adds); integration-split unchanged at 111. |
||
|
|
287bade924 |
[MG_Backend] (Disaggregated): P5e id - the NoSession mailbox hop deleted, the twin death moment and the ABA answer written down
- OnFrontendStateObjectDestroyed's split arm loses the mailbox hop
(CONTRACT-P5E §4.4). It existed for the ONE shape the object_death record
cannot carry - a transport with no client session at all, i.e. a ServerLoop
fixture driving a server role with no client, never a real split - and it
posted a stack struct to the apply thread, which re-entered this function and
ran DestroyByLifetimeId: a probe AND a Free in the CLIENT'S allocator from the
apply thread. That is not a read a barrier could ever make safe, because under
run-ahead there is no wait behind which the allocator stands still. Such a
fixture's twins die with the backend at Stop, which is what already happened
for every death raised past Running() == false.
- The frontend-keyed scope this function opened goes with it: the one arm that
needed it was the hop. Falling through under a transport now means the death
was raised ON the apply thread - the server backend destroying a frontend
object it created itself - and those sites carry their own named scope.
- ID-96, ANSWERED BY MEASUREMENT rather than by reading: a probe that aborted in
exactly the deleted branch (NoSession with a RUNNING server loop) was run over
the whole unit lane (2204 entries) and the whole integration-split lane (111)
and NEVER FIRED. The only fixture family that could reach it is
ServerLoopTest.cpp's ServerFixture / EglServerFixture - the tree's only server
role with no client session - and its one case that lets a re-keyed frontend
object die off the apply thread
(ServerLoopEglTest.FrontendFramebufferDeathDeletesOnTheContextOwner) is already
refused at its FIRST step by P5c's allocator guard. So the set of fixtures that
lose death delivery is empty: none rewritten, none deleted.
- ReleaseTwinsForWireObjectDeath gains §4.2's death moment and §4.3's ABA answer
in its own voice: the ordering is the argument (every record naming {s,g} is
applied before object_death{s,g}, which is applied before create{s,g+1}) and
the Gen compare is the proof (forward re-mints, a stale handle resolves to
null, a backward generation is refused) - so a skipped death is answered by the
forward-Gen reset alone and no wait is added at any delete.
|
||
|
|
0d54de62e2 |
[MG_Backend] (Disaggregated): P5e id - ResolveVaoTwin / ResolveTextureTwin / ResolveProgramTwin by handle
- The three by-handle resolvers the per-family packages call, in the shape SamplerImpl::ResolveSamplerCsoTwin already runs (CONTRACT-P5E §4.1/§4.2): handle in, THE RECORD FIRST, then AdoptTwinByHandle, then a twin if the slot is empty. A handle with no applier record is a seam defect and adopting a slot for it would leave a twin nothing can sync, so it is a loud null rather than an empty twin; a generation behind the live entry's is refused by PipeTwinHandleIsAdoptable rather than dropping the incumbent's driver object. - WHAT THEY DO NOT DO is the deliverable: no frontend object is touched and the client's slot allocator is never probed. They also do not SYNC - which serials gate a VAO / texture / program sync, and what the sync reads, belongs to vi, tx2 and pg, and a resolver that synced would have to know. - ResolveProgramTwin resolves through the band-aware PipeShaderCsoRecordForHandle and adopts into SlotTables.h's m_band, which is why the band landed in the same package: after the rekey a program-pipeline composite's bind is the ordinary path through this function. - Declared beside each family's registry global rather than in the registry class region BRIEF-P5E names, so that the three read exactly like the sampler resolver they copy. Reported to the integrator as a range widening. |
||
|
|
69a278549b |
[MG_Backend] (Disaggregated): P5e id - the composite band, ForEachLive by handle, the frontend-keyed half as named monolith glue
- BackendSlotTable gains m_band, the ShaderCso composite space indexed by (slot - kMGPipeShaderCsoCompositeSlotBase), beside the vector the ordinary slots live in - the shape MGPipeSlotAllocator::KindState and the applier's CompositeShaderCsos already use. EntryAt used to index m_slots by slot and resize to it, so ONE program pipeline grew g_backendProgramObjects to ~983k entries (~40 MB). That was reachable only through GetOrCreate(StatePtr) for a composite program; after id's rekey the by-handle resolution IS the ordinary path, which is why the band is a P5e prerequisite and not a follow-up. EntryOrNull / EntryAt / IndexOfSlot are the one place either space is chosen. - ForEachLive is re-typed fn(MGPipeHandle, const BackendPtr&) (§4.1): a walk that handed a frontend SharedPtr out of server memory on every step was the last place the server could hold one across records. Its single caller, ScopedDetachedTextureFramebufferAttachments, asks StateForHandle for the object instead - one named read inside the scope that owns the debt. The set of framebuffers walked is unchanged: an entry the old walk skipped because its stateRef would not lock is one StateForHandle answers null for. StateBackendObjectRegistry::ForEachLive is now handle-arm-only; the legacy map has no handle to hand over and its one caller has always had its own begin()/end() walk beside the call. - The frontend-keyed half is KEPT, not deleted (§5.8, ruling 1): the push build under Transport=monolith keeps its frontend arms token for token, which the PIPE_VERIFY comparator needs and which is what makes RUN_AHEAD=0 a pure wait-rule A/B on identical server code. Every one of the six surfaces is a named Fatal from an unbarriered apply - the allocator guard for the three that call the allocator, MGPipeRefuseFrontendKeyedRegistryFromUnbarrieredApply for NoteStateForHandle / StateForHandle. No silent path. - NoteStateForHandle / StateForHandle move from MOBILEGL_BUILD_DISAGGREGATED to MOBILEGL_PIPE_PUSH, because the re-typed walk's caller needs them in the push-monolith build too. |
||
|
|
f40a57cc96 |
[MG_Pipe, MG_Impl, MG_Remote, MG_Backend] (Disaggregated): P5e id - the barriered seam, the allocator guard and the two scopes
- CONTRACT-P5E §2.1's predicate gets its two names in MG_Pipe/PipeApply.h: MGPipeBarriered(op, payload, st) and MGPipeApplierCurrentRecordIsBarriered(), with MGPipeApplierState::CurrentRecordBarriered as the per-record flag that PipeApplier::ApplyOne stamps before every decode. The body answers TRUE for every record until ra lands the wait rule, so lockstep is unchanged and this package alters no behaviour; ra rebases onto that line rather than adding it. Package c0e owns the final declaration of both names - the overlap is one hunk. - §4.4: MGPipeRefuseAllocatorFromApplyThread now exempts a probe only inside a named scope AND while the record being applied is barriered. The client's wait is the whole of what makes an apply-thread frontend probe safe; behind an unbarriered record the allocator's free list and lifetimeId -> slot map are moving under the read, so the value is wrong by construction - there is no "count it" arm and MOBILEGL_IPC_STRICT_ERRORS is not consulted. - MGPipeApplierIsUnbarrieredApply() and MGPipeRefuseFrontendKeyedRegistryFromUnbarrieredApply() are the non-allocator half of the same rule, for the surfaces that answer from a frontend SharedPtr without calling the allocator (SlotTables.h's state note and its reader). - Ruling 12: MGPipeReverseAnnouncementScope -> MagmaP7AllocatorDebtScope, keyed on MG_Config::ActiveBackendType == DirectVulkan. Magma's four apply-thread allocator debts move onto it (VulkanRenderer's two hidden-resource shutdowns and the named-blit endpoint resolve, ResourceTracker's GPU-write announcement); an Espryt probe can no longer borrow Magma's exemption by constructing its scope. - BufferImpl::HandleOfBuffer is Espryt's debt, not Magma's, so it moves to MGPipeFrontendKeyedRegistryScope - which the Magma-keyed scope would not have exempted at all. It retires when vi/sb carry the handle into EnsureBufferResourceForHandle / IsBufferDrawCleanByHandle. |
||
|
|
5ef4701294 |
[Config, MG_Backend, MG_Test] (Disaggregated): P5e c0e - the two knobs and the caps arm
- IpcTable::RunAhead (MOBILEGL_IPC_RUN_AHEAD, default 1, forced 0 under PipeVerify beside BatchWaits) and IpcTable::PresentCredit (MOBILEGL_IPC_PRESENT_CREDIT, default 1, range 1..8). Both parsed unconditionally like every other IPC knob and both in the IPC log line, because a knob that silently means nothing on one arm of an A/B is how an A/B stops being one. - RUN_AHEAD=0 is an A/B CONTROL and not a negative one: identical server code, identical records, identical fill decision, and only the client's wait differs. VERB_BARRIER=0 keeps its own meaning as the lockstep arm's negative control. - MG_Backend/Init.cpp: kMGPipeP5eRunAheadReady = false, and the caps arm goes through MGPipeRunAheadCapBitsFor so the "DirectGLES only, and only once the integration commit flips the constant" decision has one spelling. A constant and not a knob: an operator must not be able to turn a half-migrated server into a run-ahead one, because the failure mode is a torn read that renders wrong rather than aborting. - MagmaPipeIdentityTest pins both halves - no bit 10 for DirectVulkan whatever the integration constant says, bit 10 for DirectGLES only when it is true, and that one bit and nothing else. - The push default becomes kMGPipeSubsystemsMigratedAtP5e (0x3fff). Inert: bit 13 is not in kMGPipeWiredSubsystems, so no emission gate opens on it; 0x1fff survives as P5e's "everything P4a had and nothing of mine" control. |
||
|
|
e99796d6ec |
[MG_Pipe, MG_Remote, MG_Test] (Disaggregated): P5e c0e - the wait-class column and opcode 80
- PipeCalls.def gains a FIFTH COLUMN, WaitClass, on every row, and gen_pipe.py generates MGPipeWaitClassFor(op) beside kMGPipeCallFlags. It is a VALUE and not a new op: opcode order and the flag column are untouched, and the point of generating it is that the emit table and the sink compute the barriered predicate's static half from ONE table instead of two copies that agree until they do not. - Two new generator gates, each with its own --self-test negative control: a token that is not an MGPipeWaitClass enumerator, and - both ways - a kReplySlot row that does not wait for its reply or a kWaitReply row that owns no slot. The first would be a waiter that hangs, the second a block on an answer nobody posts. Twelve controls trip now, up from nine. - set_program_bindings appended as opcode 80 (kCtxState, kVarTail|kHostSpan): the three POST-LINK mutable reflection fields, which live inside the LinkArtifacts the archive snapshots and all move after the link, so no existing row can carry them. It lands with a NULL ROUTE and a sink arm that validates and declines, exactly as set_shader_buffers has sat catalogued-and-dead since P4a. - The codec's record layout grows to THREE tails for it, with each declared count refused against its bound rather than truncated, and the third tail's name spans walked through CheckHostSpanIsHonest in the decode arm - they are members of a 40-byte element, so the encoder's blanket second-tail pass would read one span and a quarter of garbage. - PipeCatalogueTest: the new sizes (MGPProgramDesc 200), the opcode-80 and null-route pins, the draw flag, and a wait-class case that re-states CONTRACT-P5E section 2.2's table BY NAME rather than reading the def - every other statement about the column is derived from the def and moves with it, so this is the second place a demoted row has to be argued. The ABI fingerprint moves with MGPWireOp::kOpCount, which the handshake case already pins. |
||
|
|
7568161eb4 |
[MG_Pipe, MG_Impl, MG_Test] (Disaggregated): P5e c0e - the types, the subsystem bit and the image-access table
- kCapRunAheadApply (bit 10) and MGPipeRunAheadCapBitsFor(backend, ready): the arm is a pure function so "Magma never publishes it" is a unit case rather than a line only a live split session reaches. Espryt's half is gated on the integration constant. - MGPProgramBindings (opcode 80's head) plus its two tail element types, the three declared bounds, and MGPProgramDesc::LinkStatus. The descriptor grows 192 -> 200: its four trailing Uint8s end exactly at offset 24 and MGPBlobRef is 8-aligned, so the draft's "in the descriptor's existing pad" was wrong and there is no spare byte. The payload is instantiated only under MOBILEGL_PIPE_PUSH, so G1 does not see it. - kDrawClientArrays (bit 6) and kMGPipeMaxBufferBindingPoints (84). The draw flag is what makes a client-memory vertex array visible on the wire; it is refused under run-ahead by vi, staged by P8, and the lockstep arm is unchanged. - MGPipeImageAccess + MGPipeDecodeImageAccess in MGPipeValueTypes.h, and the client encode in ImageEmit.h moved onto those enumerators instead of literal 0/1/2. One table, both roles: the server's open-coded reverse mapping and its "the encoding does not exist" comment were the drift this closes. The encode is now a free function so the unit case can reach both halves. - MGPipeWaitClass, the enum PipeCalls.def's fifth column spells; kMGPipeSubsystemBufferBindings (bit 13) with kMGPipeSubsystemsMigratedAtP5e = 0x3fff; the three suppressor slots for set_shader_buffers, one per Class, so an emission of one class cannot cancel another's. - Tracker.h maps dirty bits 15/16/17 onto bit 13 - inert, because the emission gate also tests kMGPipeWiredSubsystems and the family's wired constant is still 0 - and TrackerTest follows the phase constant, which is now the whole bit set. |
||
|
|
2fde70341d |
[Docs] (Disaggregated): P5d round 3 close-out - the report, the measurements section and the roadmap row
- P5D-INPROC-PERFORMANCE.md: the round-2 diagnosis is corrected against the
symbolized call graph (the apply thread's mutex time was the idle poll, not
the backend pendingMutex), the four round-3 packages and the two race fixes are
described, the numbers table carries the two device caveats (monolith is
120 Hz vsync-capped in most runs; the kernel ignores thread affinity, so the
client thread runs on a mid core), and the lockstep-feasibility research says
why the deferred draw barrier waits for P3b/P4b and P11.
- MEASUREMENTS.md section 9: the per-arm table with per-thread CPU ms/frame as
the primary metric, the interleaved session and the wait/park counters.
- ROADMAP.md: the P5d row is the three-round shape; P11 gains the gPipeInputs
versioning item the research points at.
- CURRENT_STAGE_PROGRESS.md, README.md, ARCHITECTURE.md (env table: the
generate_mipmap exception to batched waits, the calibrated spin, the affinity
readback): head
|
||
|
|
1f8de61be1 |
[MG_Remote, MG_Pipe, MG_Impl, MG_State, MG_Backend, MG_Test, MG_IntegrationTest] (Disaggregated): P5d round 3 - the profile-directed cuts on both roles
- The round-2 report guessed the apply thread's ~48% mutex time was the backend
pendingMutex; the symbolized call graph at
|
||
|
|
85362a856d |
[Docs] (Disaggregated): P5d close-out - the inproc performance report and its roadmap row
P5D-INPROC-PERFORMANCE.md states what the phase set out to do (inproc frame rate comparable to monolith at VD12 without touching wire semantics or the correctness gates), what the two landed commits did ( |
||
|
|
56a77348f6 |
[MG_Remote, MG_State] (Disaggregated): inproc performance, round 2 - every persistent map is tracked, and the consumer walk goes away in steady state
Follow-up to the performance package (
|
||
|
|
cb06538c06 |
[MG_Remote, MG_Pipe, MG_Impl, MG_Test, MG_IntegrationTest, Docs] (Disaggregated): inproc performance package - dirty-driven persistent-map push, batched barrier waits, spin-clock batching
VD12 Minecraft on the Redmi (FCL, DirectGLES): the split's in-world frame rate
13 -> 60-66 fps against monolith's 110-114, and persistent-map wire bytes
25 MB/frame -> ~0.23 MB/frame. The residual split-specific costs are named at
the end, not hidden: the R-1 serialization (WaitForApplied ~12%, P11's
versioned-inputs design) and a split-only mutex complex still under
investigation.
Persistent-map push, three arms picked per buffer at map time:
- mprotect dirty tracker: the mapped range's page-aligned interior is
protected PROT_READ; the app's next write faults, the SIGSEGV handler marks
the page in the slot's bitmap and unprotects, and the push ships one 64 KB
block per block containing a faulted page. Ownership is three tests -
SEGV_ACCERR only (a userspace raise and an unmapped page chain verbatim),
inside a live tracked range, and not a refault on a still-set bit (a write
we unprotected succeeds, so that is a non-write access and it crashes
honestly). The alignment is INWARD: an outward-aligned edge page holds
foreign bytes, and a signal-blocking worker thread faulting on one is a
process kill - that was the ctest-only SmallRing segfault. Edge spans
(at most two per map) are hashed per push and ship their containing block
only on change (unconditional edges measured 112 MB/frame). Re-arm is one
mprotect per contiguous run. The first push ships everything once.
- hash-suppress arm (MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS, default 1):
per-block XXH3 against the last push's hashes; untracked buffers only.
- PushDrawConsumers: only the buffers the upcoming draw/dispatch can read
(VAO attribs/element, indexed binding points, indirect/parameter slots,
TexBuffer backing - the last also retires the per-frame-cadence cloud
twitch), plus the fault-epoch skip: an unmoved epoch proves no interior
byte changed, tracked edges are hashed in place, and any hash-arm member
vetoes. The membership map caches the tracker slot pointer (a 64-slot
rescan per buffer per draw was measured and removed).
MOBILEGL_IPC_BATCH_WAITS (default 1; MOBILEGL_PIPE_VERIFY forces 0): a
value-class record (kCtxState/kCtxCso/kCtxObject with no reply slot) is
published without waiting for its own apply; the barrier is taken at the next
pull-reading verb, the only place BARRIER-PULLED fields are read, so the R-1
fence posts are untouched and only the round trips between them change. Two
consequences are pinned rather than argued: kCtxObject verbs the tests read
synchronously get explicit fences (GenerateMipmapFieldsCross,
FramebufferDeathCrosses), and a frontend object whose last SharedPtr drops on
the apply thread - impossible before batching - now enqueues its
(kind, lifetimeId) on the deferred destroy queue and the GL thread replays
the DestroyAndFree helper at the verb hooks (CopyImageLayeredScenario aborted
Fatal{RoleViolation, MGPipeSlots} without it).
Doorbell::Wait's spin reads the clock once per 64 yields: on the workload
device a steady_clock read is a real syscall (no vDSO) and the per-iteration
reads were ~20% of the whole process at ~1000 waits/frame.
Gates: gen_pipe --check/--self-test green; unit 2188/2188;
integration-split 110/111, the one red being GenerateMipmapDepthPixels whose
DirectGLES and DirectVulkan MONOLITH siblings flake identically with every
code path of this package provably inert (PushIsArmed false, no ClientSession,
deferral's monolith early-out).
|
||
|
|
7cdc8d775e |
[Docs] (Disaggregated): refresh the P5c close-out status lines - README and ARCHITECTURE section 17.6 were still describing P5c as planned, and the code head is the triage head b88e8487 everywhere
|
||
|
|
36176b9dbc |
[Docs, MG_Remote] (Disaggregated): close out P5c - the inproc split's direct cross-role access is zeroed
ROADMAP marks P5c closed at the triage head and P6 next; CURRENT_STAGE_PROGRESS carries the current-head gate table (unit 2187/2187, integration-split 111/111, the census classification with every newly-red entry evidenced by its Fatal name, the three named G1 resizes, the 0xDD audit, the per-frame rsp measurements, and the two items deliberately not done locally: the Redmi retest and the 79-trace census); MEASUREMENTS gains section 8 with the per-gate evidence. CONTRACT-P5C takes the amendments ratified at gt's landing and at the regression triage: per-level extent is retired at the sites rather than guarded on the accessor, the strict CI lane is two-sided (unit green gate plus expected-red scenario lane with the marker asserted), the drain points are two classes (the EGL RPC returns beside EmitAndWait), and oversized writebacks are client-sliced at a quarter of the event ring. |
||
|
|
b88e848761 |
[MG_Remote, MG_State, MG_Impl, MG_Backend, MG_IntegrationTest] (Disaggregated): P5c census triage - the three real regressions the merge owed
The broad inproc census against a same-machine
|
||
|
|
39d1a5d38c | Merge branch 'p5c-gt' into feat/disaggregated (P5c gt: role guards, InBarrierWait wired, rsp measured) | ||
|
|
ab9250281b | [Docs, MG_Backend] (Disaggregated): P5c housekeeping - the death-switch scope comment describes the landed ct shape (the NoSession arm only), and the README counts 79 calls after ct/rv | ||
|
|
a0865b00f4 |
[MG_State, MG_Backend, MG_Remote, MG_Impl, CI] (Disaggregated): P5c gt - the role guards close the phase
Layer 1 arms the texture object surfaces at MipmapStorage (the one point every concrete
texture class and view forwards through): AllocateStorage, TruncateMipmapLevels,
UpdateMipmapSubData, MapMipmapData, MarkStorageDirty(Region), IsStorageDirty,
GetStorageDirtyRegion(s) take Fatal{RoleViolation, texture-legacy-arm} from the apply
thread with an active transport. What the lane then exposed is fixed, not exempted: the
completeness gate answers from the staged store's defined-ness, the two logging reads go
through the descriptor macro, and the remint replay loop keeps its named
Fatal{UnmigratedEmulation} ahead of the guard. Magma's texture sync read path is the one
named exemption (MGPipeTextureLegacyArmScope, P7). Layer 2 wires InBarrierWait as the
client half of the gPipeInputs single-writer rule (RefusePipeInputsTouchWhileApplierOwnsIt:
applier owns it AND this thread not in a barrier wait => Fatal{RoleViolation,
gPipeInputs}; the barrier-off negative control is deferred to its own Fatal), and stale
reads of RECORD-SUPPLIED / APPLIER-DERIVED fields under a server stamp now report
RoleViolation with the field named. The RemoteGuards suite pins all nine texture surfaces
plus HasDefinedContent by name, and a negative control for the fill window. CI gains the
integration-split-strict job: unit lane as the hard gate under MOBILEGL_IPC_STRICT_ERRORS=1,
the scenario lane expected-red with the marker asserted (rewritable to plain green once P7
retires the object-class rows). rsp is per-frame in the stats line and measured on the
locally available traces (bsl in-world 948.5/frame avg over 123 frames, complementary
1591.9, iterationrp 286 until its named remint-pull Fatal); value-class pulls are zero by
rv's pinned list, what remains is the object-class fifteen.
Evidence: unit 2187/2187 (also under STRICT_ERRORS=1); integration-split 111/111; red-once
per layer (the texture guard and the gPipeInputs guard each turned their named death test
red and restored green). CONTRACT-P5C sections 5.4, 6.
|
||
|
|
c74de6b506 | Merge branch 'p5c-rv' into feat/disaggregated (P5c rv: residual-value record, value-class pulls retired) | ||
|
|
82b1f743a7 |
[MG_Pipe, MG_Impl, MG_Remote, MG_Backend] (Disaggregated): P5c rv - set_context_values retires the value-class BARRIER_PULLED rows
set_context_values (opcode 79, MGPContextValues 96B, kCtxState) carries the active texture unit, the max touched unit, the fifteen touched-binding-point counts and the five value-class XFB rows, emitted at validate under the subsystem bit and hash-suppressed as a whole; the emit gate and the residual-skip gate read the same answer so they can never disagree. MGPipeApplySetContextValues writes gPipeInputs (the PackState shape). MGPAttribValue grows 24->56B to carry the frontend's converted three views, and MGPipeApplySetVertexAttribDefaults finally writes them (the 'ignores MGPAttribValue::ValueClass' warning dies), so GetCurrentVertexAttribute leaves the refusal set. The three texture shutters answer the applier's own serials under a server-stamped verb (APPLIER_DERIVED), storage answer kept verbatim elsewhere. FieldOwnership.def: nine value-class rows become derived RECORD_SUPPLIED, the three shutters APPLIER_DERIVED, the nine object-class rows keep their phases; FieldOwnershipTest pins that the remaining pulls are exactly the object-class list. gen_pipe.py gains SCAN_EXEMPT_ACCESSORS with per-name reasons and retiring phases (it repairs the --check gate the hd merge's two G6 probes had left red). Evidence: unit 2175/2175; integration-split 111/111; both generators' --check and --self-test green; rsp on the Xfb capture scenario 36 -> 22; red-once - gating the emission off turns seven named scenarios red, restoring returns 111/111. CONTRACT-P5C section 5.3. |
||
|
|
04650ca35e |
Merge branch 'p5c-ct' into feat/disaggregated (P5c ct: applier_reset / object_death control records)
# Conflicts: # MobileGL/MG_Backend/DirectGLES/Managers.h |
||
|
|
63f8bb1f8f |
[Docs, MG_Pipe] (Disaggregated): CONTRACT-P5C amendments ratified at the tx/ev/hd landing
Table 0 gains the MGPSurfaceInfo zero-extent semantics row (ev). section 2.1 is amended to the handle-keyed store with whole-run coverage and defined-ness tracking (tx's three in-field rulings: a twin-address key would force glGenTextures at adopt time; region- precise coverage false-Fatals the legal texStorage-then-small-box flow; Levels=N says nothing about a sparse chain). section 2.3 records Espryt's driver-side mip generation as a final shape beside Magma's store marking. section 3.1 gains the two named scoped exemptions (the un-emitted binding records family, P4b/P7; the G6 frontend-keyed registry family, P3b/P4b) and section 3.3/3.6 take hd's in-field shapes (the verb-handle workspace with the state note; HasDefinedContent OR staged coverage, because the streaming idiom defines content through subdata with no new descriptor). section 5.2 takes ct's documented NoSession server-only-fixture arm. FieldOwnership.def moves InvalidateCompileEnv (field and forward rows) to FATAL with the deletion as mechanism (P5c ev), regenerated .inc checked in; --check and --self-test green. |
||
|
|
b45bf68101 |
Merge branch 'p5c-hd' into feat/disaggregated (P5c hd: handle-keyed resolution)
Conflict: VulkanRenderer.cpp's disaggregated include block took both halves.
Merge coordination (integrator, with the evidence inline):
- hd's Fatal{RoleViolation, MGPipeSlots} guard as landed was kind-blind: it fired on the
G6 frontend-keyed twin registry (texture/VAO/program/sampler resolver probes - P3b/P4b's
to rekey) and on the families whose handle-carrying records the client does not emit
until P4b (the buffer binding-point ensures, the GPU-written announcement). Integration-
split went 104/107 red at the first Clear. Two NAMED, scoped exemptions keep the guard's
teeth for every other caller (SlotAllocator.{h,cpp}): MGPipeReverseAnnouncementScope
(buffer ensure + announcement family, P4b/P7) and MGPipeFrontendKeyedRegistryScope
(the G6 registry family, P3b/P4b; also the mailbox death switch until ct's object_death
record retires it). ~30 resolver sites wrapped, each naming its debt in the comment.
- ScopedRestartIndexSubstitution needed NO exemption: the EBO resolves from the record's
IndexBuffer.Res and the bytes read from the server staged shadow - CONTRACT-P5B d1's
own sentence, implemented.
- Magma's named blit takes a G6 consume arm (frontend FBOs resolved by lifetime id inside
the scope, VerbBlitNamedConsumed set, loud refusal kept for a failed resolution), so the
two DirectVulkan.Split.NamedBlit correctness cases stay green; Magma's hidden blit and
depth-mipmap resources' teardown probes are wrapped and named (P7: give them non-frontend
storage).
- MG_State gains GLContext::FindFramebufferObjectByLifetimeId (behaviour-neutral accessor
for the arm above).
Gates on the merged tree: unit 2166/2166; integration-split 107/107 (2 design skips);
hd's RemoteGuards death tests still abort the unwrapped paths by name; PrimitiveRestart
7/7; the two Magma named-blit cases render. CONTRACT-P5C sections 3, 5.4.
|
||
|
|
a7e55ee62a |
[MG_Pipe, MG_Remote, MG_Backend, MG_Impl, MG_IntegrationTest] (Disaggregated): P5c ct - the applier_reset and object_death control records
Two appended wire records replace the two cross-role control bypasses:
applier_reset (opcode 77, MGPApplierReset{Uint64 ContextSerial}, kScreen) is emitted by
the GL thread at the FreshlyPrimed make-current edge, before the client-side resets, so
the record's barrier orders the server's MGPipeApplierReset against every verb that
follows; a direct MGPipeApplierReset() from a non-apply thread with a live session is
Fatal{RoleViolation, "g_applier"} (MGPipeApply.cpp carries the layer-2 guard; the
apply-thread and no-session bring-up shapes keep the direct call verbatim).
object_death (opcode 78, reuses MGPipeHandleOnly, kCtxObject) is the framebuffer
family's first wire delete opcode: the client thread resolves the dying object's handle
in its OWN allocator, emits nothing for a handle the server never saw, and EmitAndWaits
otherwise - the wait preserving the death's ordering against in-flight records that
name the handle, the only property the blocking mailbox hop provided. The sink releases
per-kind twins through a handle-keyed ReleaseTwinByHandle (seven kinds, SamplerViewCso's
idempotent second path kept); a null arriving handle is
Fatal{ProtocolCorruption, "ObjectDeath.Handle"}. A documented NoSession fallback arm
delivers a death to a server-only fixture's loop; monolith keeps the mailbox hop and
the FreshlyPrimed direct call character for character.
Evidence: gen_pipe --check/--self-test and gen_pipe_field_ownership --check/--self-test
green; unit 2155/2155; integration-split 111/111 (107 plus four new CtWireScenario
entries, all genuinely run, each with its own log path and an EXPECT_EXIT death case);
red-once - shorting the emission to the direct call turns the four Ct cases red with
Fatal{RoleViolation, "g_applier"} by name, then restores green verbatim.
CONTRACT-P5C sections 1, 5.1-5.2, 7.
|
||
|
|
7f5bdd3aa5 |
[MG_Backend, MG_Remote, MG_Impl, MG_State] (Disaggregated): P5c hd - sinks and twins resolve by the handle the record carried
A split-only verb-handle workspace in MGPipeApplierState (written by the sinks before
dispatch, read by the backend within the same verb) carries the record's handles to the
backend entries whose shared function-table signatures cannot grow them without moving
G1. OnBlit resolves ReadFbo/DrawFbo through the FBO twin table by handle (the named arm
of BlitFramebuffer, a loud refusal when the backend does not consume it) and the split
path's ScopedBlitBindings rebinding is deleted; CopyTex resolves MGPCopyFromFramebuffer::Dst;
the mip descriptor check resolves MGPMipPlan::Res; the indirect families resolve their
buffer handles from the records and read the bytes from the server staged shadow with
RequireStagedCoverage. EnsureBufferResourceForHandle answers HasDefinedContent from
Desc.HasDefinedContent OR the staged coverage set (the streaming idiom defines content
through subdata with no new descriptor). The minting GetOrCreate(StatePtr), HandleOf and
the death switch's lifetime-id arms take Fatal{RoleViolation, MGPipeSlots} from the apply
thread, as do the three MGPipeSlots() entry points; the frontend BufferObject legacy
accessors take Fatal{RoleViolation, buffer-legacy-arm}; Magma's four caps reads go to the
server's own backend and the client-mirror fallback arm is a named refusal.
Evidence: unit 2156/2156 (incl. 9 new RemoteF1 + 10 new RemoteGuards death tests pinning
the four Fatal names); monolith smoke green; six production mutations each turned their
named test red and were restored; c1f_redcheck M5 RED then RESTORED GREEN. The mip
descriptor check overlaps tx and is coordinated at the merge (tx's sync rekey wins the
sync body, this handle resolution wins the identity check). CONTRACT-P5C section 3.
|
||
|
|
1eeb4740ca | Merge branch 'p5c-ev' into feat/disaggregated (P5c ev: SEG_EVENT reverse channel) |