Commit Graph
6 Commits
Author SHA1 Message Date
swung0x48 8a445a3098 [docs] (P7): every cited feat/disaggregated commit is the rewritten one without the attribution trailer
- 144 commits from 785fed0b0 onward were rewritten to drop the Co-Authored-By trailer the
  project forbids; origin/feat/disaggregated moved from 1135c664 to 3c80cd62 (same trees)
- the old->new map is ~/w7/logs/sha-map-20260922.txt; every 7..40-hex citation in the
  Disaggregated docs and the MG_Remote contracts that matched an old SHA is replaced by the
  same-length prefix of its rewrite; no other content changes
2026-09-22 20:51:15 -04:00
swung0x48 074a072739 [docs] (P7): package C's note carries the gate matrix and the three things the integrator has to decide
The per-slice red-once records were written with each slice. This adds what only exists
once the four are together: the gate table (unit 2403, magma split/spawn/tcp 75/54/56 with
the two death-case skips now gone, integration-split 187, integration-spawn 103,
full-split 513 entries 0 red 55 skipped = 458 pass against the 453/57 bar, census
unchanged, parity green, @P7 15/4 -> 13/3, ratchet 186 monotone, G1 .text 0xa52203 with
every section +0 and the pull .so byte-identical), the ratchet bucket split with an honest
note that I did not re-measure the buckets at the branch point, and a numbered list of the
nine things this package changes that live outside its own files.

Three of those nine need an integrator decision rather than a note: §5.4's white-box case
is blocked by R-6 and not by this package; §5.3's g_programResourceCaches deletion is
achieved in the disaggregated build only, because the archive member has to be guarded for
G1; and buffer-window's family word is UnmigratedVerb where ProtocolCorruption is the
honest one, which costs a row in MG_Pipe and an adapter arm that §3.3 deliberately has not
spent.
2026-09-22 16:07:59 -04:00
swung0x48 0acfa9aab9 [MG_State, MG_Backend, MG_Test, docs] (P7): the reflection archive publishes the storage-block index space, and both magma consumers read it
CONTRACT-P7 §5.3, OQ-8. MagmaProgramSource::EnsureStorageBlocks re-ran SPIRV-Reflect over
every stage module of the program PER DRAW: the class is a borrowed view that
WireDraw.inc's WireProgramSource constructs afresh for each wire draw, so its `mutable`
memo was cold every time it was read. The list it rebuilt is a pure function of the linked
program, so it is now built once at link time and travels in the archive.

LinkArtifacts gains storageBlocks{name, binding, dataSize} with its own VisitFields table,
the codec version goes 2 -> 3, and the schema fingerprint and wireFingerprint move with
it - which is expected, and is what makes a mixed-version pair refuse at the handshake
instead of at the first program.

FILLED IN PHASE A, and that is not where it looks like it belongs. The only function that
sees both finished halves is ProgramSpirvTask's L1 cache insert, but its writes reach the
TRANSLATION CACHE only: phase A's artifacts have already been moved into the ProgramObject
by then. A field filled there would be present on a cache hit and absent on every cold
link. So the fill is glslang-derived, and the equivalence is MEASURED rather than assumed:
ProgramTest.TheArchivesStorageBlockOrderIsTheOneSpirvReflectProduces runs the old
consumer's own algorithm over the real modules and compares element for element, on a
multi-stage program with an arrayed SSBO and an atomic-counter block - the three cases
that could have diverged (the instance array collapses to one entry, the synthesized
counter block IS in the backend's space although GL's enumeration excludes it, and the
cross-stage dedupe walks stages in linked order).

MEASURED, same binary and same window (frames=1 draws=1 acc=18, identical bytes),
DirectVulkan x inproc over the SSBO scenarios: spvReflectCreateShaderModule on the wire
draw path 4 -> 0. The 0 is structural: the call site is gone and MagmaProgramSource.h no
longer includes spirv_reflect.h at all, which is the gate a future edit breaks on purpose.

THE MONOLITH CONSUMER IS SWITCHED TOO, under #if symmetry, so the disaggregated build
retires g_programResourceCaches, ProgramResourceCache, StorageBlockResource,
BufferVariableResource, AddBufferVariablesRecursive, NormalizeDescriptorName,
GetProgramResourceCache and the rehash hazard - the open-addressed-map dangling reference
that was a reproducible segfault in ProgramPipelineScenario's two storage-block cases.
Nothing outside DirectVulkan.cpp read any of it (measured; GL_BUFFER_VARIABLE and
GL_ACTIVE_VARIABLES are answered by ProgramInterface.cpp out of a different index space),
so the two arms differ in exactly the two functions their callers use.

THE PULL BUILD KEEPS ALL OF IT, and the integrator should see why: the archive member is
MOBILEGL_BUILD_DISAGGREGATED-only because one more Vector in LinkArtifacts changes its
size, its implicit destructor and its move constructor, and G1 pins the pull build's .text
byte for byte. So §5.3's deletion is achieved in the disaggregated build and not in the
pull one; retiring the pull half is a one-line change the day that pin is retired or the
member moves. Filed as P13 in notes/p7/magma-c.md.

One improvement rides along: the monolith binding getter now asks the program for a
rebind on every read, over an immutable list, where it used to read a binding patched into
a mutable cache - so a rebind can no longer be lost to a cache rebuild that raced a
state-version bump.

G1: .text 0xa52203 unchanged, 27837 -> 27837 defined symbols, 0 added / 0 removed / 0
resized / 0 renamed, file byte-identical. An unguarded call site caught the guard rule
once mid-slice by failing the pull compile, which is the loud version.

RED-ONCE: publishing nothing reds the order-equivalence case (with the reference list
printed) and 25 of 60 storage-block scenarios - the MONOLITH DirectVulkan arm beside all
three transports, which is the evidence that the monolith consumer really was switched.
Restored: 61/61.
2026-09-22 16:07:59 -04:00
swung0x48 f1b04edfc6 [MG_Backend, MG_IntegrationTest, docs] (P7): the magma vertex-layout refusal splits into one protocol fatal and seven masked attributes
CONTRACT-P7 §3.2's `vertex-layout` and `vertex-format-conversion` rows.
BuildWireVertexInput answered eight different conditions with one `false`, and the single
caller answered that with a P7-marked MagmaWireFatal. So a Magma split session that met a
GL_FIXED array, a dvec on a device with native fp64, or any format without
VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT did not decline the draw: it killed the process. The
monolith arm on the same device has always masked the attribute out and then declined the
draw loudly and once.

The split is by what the reason is ABOUT, not by severity. `buffer-window` is a statement
about the RECORD - an enabled attribute the program reads whose slot lies outside the
window set_vertex_buffers published - so it stays a named Fatal through the hook; it is
what caught the Redmi VAO hash collision fixed in 376c04be. Every other reason is a
statement about what Vulkan can express on this device, and those now set
unsupportedAttribMask and continue, with the monolith arm's own pre-flight in WireDraw.inc
declining the draw when a masked bit is one the program actually reads.

The contract says "the other six"; there are seven. `offset-overflow` post-dates the
audit's count and is an arithmetic guard rather than a shape one. It is masked with the
rest: an attribute whose base offsets cannot be added is one Vulkan cannot fetch, the
monolith arm never computes that sum at all, and masking is strictly safer than a Fatal
for a number no application can reach on purpose.

unsupportedAttribMask now enters the wire layout hash, for the reason the monolith entry's
hash already carries it: two VAOs can otherwise agree on every binding, attribute and
divisor and differ only in which enabled attribute was masked, and a blind hash would hand
one of them the other's pipeline. Omitting it was safe only while the mask was always zero.

vertex-format-conversion becomes a decline for a narrower reason: the converter is only
ever asked for a conversion BuildWireVertexInput already chose, so a refusal means the two
disagree - a defect on this side, not a peer's malformed record.

@P7 census: 15 sites / 4 files -> 13 / 3. Renderer/WireDraw.inc leaves the list entirely.
fatal_census.py unchanged at 79 abort sites / 43 family words / 0 unmarked, as expected:
wave 0 already funnelled these, so retiring a MagmaWireFatal CALL moves no abort count.

New MagmaVertexLayoutScenario, DirectVulkan only (Espryt hands GL_FIXED to a driver that
supports it, so the same name would assert a different fact there). DataType::Fixed32 has
no arm in ToVkVertexFormat at all, which makes it the one unmappable shape reachable on
host lavapipe - §2.5 records that no other P7-marked refusal is. One case has the program
READ the array and asserts the draw declines; the other leaves it enabled but unread and
asserts the draw lands, which is what stops the first being satisfied by "decline every
draw that mentions GL_FIXED". Registered on all three transports and picked up by the
ambient monolith DirectVulkan discovery, so the A/B is direct.

RED-ONCE: `format-map` put back on the protocol verdict reds the three split arms with
`Subprocess aborted` / `Fatal{UnmigratedVerb, "Magma:vertex-layout-buffer-window"}` while
the monolith control stays green - exactly the divergence this closes. Restored: 10/10.

The gating Magma lanes grow with the new entries: split 73 -> 75, spawn 52 -> 54, tcp
54 -> 56. Growth only.

Open for the integrator: the honest family word for buffer-window is ProtocolCorruption,
and MGPipeFatalFamily carries only UnmigratedVerb and RoleViolation. Adding a third costs
a row there plus an adapter arm, and §3.3 keeps the three Magma funnels on UnmigratedVerb
deliberately so the refusal census stays comparable to P5b. Flagged, not decided.
2026-09-22 16:07:59 -04:00
swung0x48 1255caa2fb [MG_Backend, MG_Impl, MG_Util, MG_Test, MG_IntegrationTest, docs] (P7): the server publishes kCapResidentSubData off its own wire resource table
CONTRACT-P7 §5.4, OQ-10. InitServerRoleCommon computes the whole capability mask and
never ORed this bit, so MGPipeResourceOpsHaveSubDataResident answered false under every
transport and BOTH backends were pinned to the ordered in-place host memcpy - which made
Magma's SubDataResident arm (VkBufferManager.cpp's g_vulkanWireResourceOps) dead code on
the wire even though the arm has been there since P5f.

The bit is derived from g_resourceOpsAtStep2->SubDataResident, i.e. from the pointer this
function already pinned at step 2 and that step 5 already refuses to see swapped - never
from ActiveBackendType. That is ID-39's lesson and not a style preference: a mask is a
statement about THIS backend's registered table, and a bit derived from the enum would
keep claiming the capability for a build, a flavour or a future backend whose table does
not carry the arm.

`rsd=` joins the emit[] bracket on the PipeStats summary line, counted at the emitter once
per buffer_subdata_resident record rather than once per call, because a write past the
content chunk cap is cut into several records. It is the only observable that separates
the resident arm from the memcpy beside it: the bytes in the buffer are identical either
way, which is exactly how the capability stayed unpublished for a phase with every lane
green.

WHAT THIS DOES NOT YET PROVE, and R-6 is the reason rather than an omission. §5.4 asks for
a white-box case showing opcode 49 on the wire. None can exist at this tree: the resident
arm is reached only from a GPU-RESIDENT store, residency comes only from
AdoptPersistentMap, and every persistent-map acquisition declines under split by R-6
(PipeApply.cpp:2331 "A SPLIT BUILD RUNS AT TIER T2 AND DECLINES EVERY ACQUISITION,
ALWAYS"; T0/T1 are P11's and AdoptTierIsEmulate is a named Fatal for them). So the
capability is wired AHEAD of its consumer, deliberately, and `rsd=` is what will show the
records the day P11 lands a tier that adopts. Filed for the integrator in
notes/p7/magma-c.md.

What IS proved is both halves of the bit itself. RemoteClientTest's Magma bootstrap case
now asserts the published bit EQUALS `ops->SubDataResident != nullptr` - the two compared
to each other rather than both to true, so the case also covers a backend without the arm
on the day one exists - and a new CtWireScenario case reads the bit out of the client's
own caps mirror, through the same accessor the frontend reads, on both backends and all
three transports.

RED-ONCE, both levels. Deleting the OR reds
CapsMirrorTest.MagmaTransportPublishesRealBufferConsumersWithoutRunAhead
(RemoteClientTest.cpp:692, "Which is: false / Which is: true") and all SIX arms of
DirectGLES/DirectVulkan x {Split,Spawn,Tcp} Ct.TheServerPublishesTheResidentSubData
CapabilityFromItsOwnTable ("the client's caps mirror did not receive
kCapResidentSubData"). Restored: green.

Also carries the P4a death-helper comment from the previous commit's sweep: it no longer
says Magma installs no death table, because it now does and still frees no slot.
2026-09-22 16:07:58 -04:00
swung0x48 dce9953d36 [MG_Backend, MG_State, MG_Pipe, MG_Remote, MG_Impl, MG_IntegrationTest, docs] (P7): magma installs a state-object death table, and the inproc arm stops losing every object_death
CONTRACT-P7 §5.5. DirectVulkan had no StateObjectDeathOps at all, so under a Magma
inproc session NotifyStateObjectDestroyed reached nobody and the server was never told
that a frontend object had died. Package L measured the shape: with the WireTables
install condition made backend-agnostic, CtWireScenario's two death cases PASS on Magma
spawn and tcp - the remote client has no local backend, so the client-side emitter
installed there answers the notice - and FAIL on inproc, where the install condition
deliberately stands aside for "the backend's own dispatcher" and Magma had none.

g_magmaStateObjectDeathOps is that dispatcher. It mirrors g_glesStateObjectDeathOps
(DirectGLES/Managers.cpp:335) with ONE arm rather than two: Espryt's other arm destroys
a backend twin keyed by lifetime id, and Magma keeps no such twin - its two
client-minted kinds are keyed on {slot, gen} by MagmaPipeIdentityTables and the other
six are still reached from their frontend objects - so what is left is exactly the emit
of object_death off the apply thread. Installed from
BackendObject_DirectVulkan::Initialize(), i.e. ServerLoop::CreateBackend, step 1 of
InitServerRoleCommon: the one place BOTH Magma server roles pass through, and before any
client session exists. #if MOBILEGL_BUILD_DISAGGREGATED && MOBILEGL_PIPE_PUSH, so the
pull build compiles nothing new.

The two skip guards in CtWireScenario go with it. Every other "Magma installs none" site
the audit found is comment text whose ARGUMENT survives, and each is reworded rather than
deleted: the table emits the wire record and frees no client slot, so P4a's
backend-neutral NotifyAndFree is still the only thing that returns one, HandleRecycle's
C-1 case still measures the only protection the allocator has, and MagmaPipeArms' age
sweep is still the only thing that retires an identity slot.

The framebuffer death case now reads the client's allocator beside the server's tally.
That correction matters: the plan called this a slot leak provable with PipeSlotPeek, and
it is not - it has been backend-neutral since P4a. What leaked was the SERVER's twin, and
a framebuffer has no wire delete opcode at all, so object_death is its only delivery.

Two installers cannot race although the global is last-writer-wins with no stacking:
Magma's runs only in a process that owns a DirectVulkan backend, and
InstallClientWireTables' arm runs only under Transport == Spawn, which is by construction
the process that owns none.

RED-ONCE: `if (false) InstallStateObjectDeathOps();` reds the two Split cases alone
(`Expected: (afterCounters.deaths) > (deathsBefore), actual: 0 vs 0`, CtWireScenario.cpp:264)
and leaves spawn and tcp green - the exact split of responsibility the comment claims.
Restored: 8/8. Recorded in docs/Disaggregated/notes/p7/magma-c.md.
2026-09-22 16:07:13 -04:00