mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 10:03:23 +09:00
64a2f4a30081d73c108ef4e064728fcd2b1745da
3569
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
64a2f4a300 | [MG_IntegrationTest, MG_Pipe, ci] (P7): every verify case runs on the split (inproc) arm of both backends under integration-verify-split, armed per entry, and the comparator's oracle for the pack half inside the server's read_pixels window is the ID-49 neutral pack | ||
|
|
e8678dfad9 | [MG_Test] (P7): the respecify-scope unit helpers are compiled only where the applier they read is, so the pull build builds again | ||
|
|
a1d17566f7 | [MG_Pipe, MG_Test] (P7): the respecify scope pin asks that a per-level producer cover the range it declares, so verify and split can be in the same build | ||
|
|
75a64ce0da |
[tools, docs] (P7): the parity script keeps one server-side-knob list after the B3 rework merge, and magma-b3.md names it
The B3 rework's parity hunk and B2's round-1 hunk described the same asymmetry
under two names; the merge kept B2's compare_arms(no_tcp=) and added .StaleSerial.
to MAGMA_SERVER_ENV_KNOB_NO_TCP. One line of the package tree's other mechanism
(`not_on_arm = not_on_arm or {}`) survived outside the conflict hunks and would
have been a NameError on the first run; it goes, and the note's two mentions of
MAGMA_NOT_OVER_TCP now name the list that exists.
|
||
|
|
3f92d0f109 |
[docs] (P7): magma-b3 - the review round: every decline row is sited, the floor has a lane, the stamp is a probe, and the tcp arm carries no knob it cannot see
Records review ID-P7-34's four should-fix items as landed: - §1.5: the .def audit (52 rows / 40 sited / 10 unlogged, rc 1 -> 53 / 53 / 0, rc 0), the per-function distribution, and the forced ShapeNoVkFormat red; §1.2's "32 exits" is corrected against the tree. - §3.2: the submission term is a probe and a defence, not the fix - the stamp can name S1 while the draw rides S2 through the preserve flush - and the :273 early return and :432 re-stamp. - §4.1: the MGWIRE-FLOOR red condition in run_trace_case.cmake, with the red (clamp deleted: 26 lines, ssim 1.0, FAIL on SPLIT and SPAWN) and the green. - §4.2: StaleSerial. on split and spawn only; MAGMA_NOT_OVER_TCP. - §5: the review-round gate sweep; integration-magma-tcp 71 -> 70. - §7.2 (for CONTRACT-P7 §12): the disaggregated monolith arm is now sounder than the pull build on mid-frame flushes (OnSubData reads the same floor via IsResourceBusy; the pull build keeps the latent bug under G1 / P13), and the stale comments at WaitForFrameSerial and CollectAllDeferredReleases; the reviewer's verdict on the clamp and on B4. |
||
|
|
80b91346d1 |
[tools] (P7): a split retrace reds on any MGWIRE-FLOOR unsound-serial-complete line, so the frame-serial floor clamp has a lane
Review ID-P7-34, item 2. The primary B3 fix - the clamp in
VulkanRenderer::OnSubmitsCompletedUpTo that raises the completed-frame-
serial floor only to a serial no in-flight submission still carries - had
nothing behind it: deleting the clamp loop left every lane green and the
OpenRA picture gold on lavapipe (the host's barriers hide the tear). Its
only observable was the per-event MGLOG_W "MGWIRE-FLOOR
unsound-serial-complete".
run_trace_case.cmake now reads that line out of both roles' logs on every
split run, exactly as it already reads Fatal{: the count is printed pass
or fail and any nonzero count is a FATAL_ERROR. The R-16 counter (26 -> 0
on the OpenRA retrace) is thereby a gate.
Red/green on MobileGLTraceReplay.OpenRA.DirectVulkan.SPLIT / .SPAWN:
clamp loop deleted -> both FAIL at ssim 1.000000 / 0 px:
MGPipe split: OpenRA DirectVulkan transport=inproc, MGWIRE-FLOOR
unsound-serial-complete lines: 26
[mgl-srv-apply/WARN]: MGWIRE-FLOOR unsound-serial-complete #1: advancing
the completed frame-serial floor to 3, which submission 3 (serial 3)
still carries
(spawn: identical, 26)
clamp restored -> both PASS, 0 lines.
|
||
|
|
cba0c3a110 |
[MG_Backend, MG_IntegrationTest] (P7): the busy predicate's comments name the floor as the guarantee and the submission term as a probe, and the term is consulted and re-stamped wherever the serial is
Review ID-P7-34, item 3. 02bb5789 presented the submission term as the fix and still carried the every-8th-drain mechanism that magma-b3.md §2.4 refutes (the probe saw one successful drain and zero boundary works across the OpenRA replay). The term is not sound alone: lastUseSubmitIndex is stamped at AcquireWireSlice, but a mid-draw flush (BindProgramUniformBuffers -> SyncWireTextureShape's preserve path -> FlushWirePendingCommandsFor- TextureUpdate) can submit the stamped index without the draw, so the stamp names S1 while the draw rides S2. The guarantee is the floor in OnSubmitsCompletedUpTo; the term is a defence and a device probe. - WriteWireBuffer's block comment, the WireBufferResource field comment, the AcquireWireSlice stamp comment, the StreamedBufferSubData CMake comment and the F1WireScenario case comment are rewritten on that footing; the drain story is gone. The drain probe's comment now says it refuted the drain as the mechanism. - WaitForWireBufferHostAccess's early return also requires the submission term complete, so a caller with the serial term idle cannot skip a wait the term demands. - ReadWireBuffer re-stamps lastUseSubmitIndex beside lastUseSerial after its wait, preserving the pending draw's reservation in both halves. All disaggregated-only code. OpenRA DirectVulkan SPLIT / SPAWN retraces ssim 1.000000, 0 px, zero MGWIRE-FLOOR lines; integration-magma-split 90/90, -spawn 69/69, -tcp 70/70. |
||
|
|
b0c6af3168 |
[MG_IntegrationTest, tools] (P7): the stale-serial red-once is registered on split and spawn only, and the parity gate names it with the other server-side knobs
MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL is read by the server. The tcp arm's server is the lane fixture (scripts/ci/tcp_server_fixture.py), started once from its own environment, so an entry-level ENVIRONMENT never reaches it: DirectVulkan.Tcp.StaleSerial.* ran the unforced case under a name that claimed the knob and could never red (review ID-P7-34, item 1). The entry is now registered only when the arm is Split or Spawn, and spawn_lane_parity.py grows a second named asymmetry beside MAGMA_INPROC_ONLY: MAGMA_NOT_OVER_TCP, key prefixes the reference arm has and the tcp arm does not by name. It comes off the reference for the tcp arm alone, so the same entry missing from spawn is still an error. B2 adds its own knob entries to the same tuple in its tree. integration-magma-tcp 71 -> 70 entries (68 cases + the two fixture entries); split 90, spawn 69 unchanged. spawn_lane_parity.py build-split rc 0; tcp_lane_tools_test.py 6/6. Integrator merge onto pipe: B2's round-1 mechanism (`mglItestServerEnvKnobArm` in CMake, `compare_arms(no_tcp=)` in the parity script) already covers this shape, so `.StaleSerial.` joins MAGMA_SERVER_ENV_KNOB_NO_TCP instead of the separate MAGMA_NOT_OVER_TCP the package tree introduced. |
||
|
|
b8d10d0730 |
[MG_Backend, tools] (P7): every WireDeclines.def row has a site and every site a warning-or-error line, and a tree-only audit fails the job when one does not
The B3 review (ID-P7-34) counted 12 of the 52 rows with no site at all - TexViewFormat, TexNoApplierRecord, TexRecordDeadOrStale and the nine Shape* rows were declared and never counted - and ten sites that counted with no (MGLOG_D included) line, so "a name, a tally and a decline line" did not describe the tree. - SyncWireTextureShape: all nine Shape* exits now count; the ViewOf exit and the preserve-flush exit were bare `return false` and are now MGL_WIRE_DECLINE_AT; the image-flags exit logged only MGLOG_D, which a Release build compiles away, and is promoted likewise. - The preserve-copy exit was the one Shape exit with no row: appended as ShapePreserveCopyFailed (rows are append-only), 53 rows. - SyncTextureResourceByHandle / UploadPendingWireLevels: the count-only sites without a log of their own are promoted to MGL_WIRE_DECLINE_AT; the ones already under a W/E _ONCE line keep that line and gain the count. - scripts/ci/wire_declines_audit.py: fails on a row with no site, a site naming no row, or a bare Count() with no MGLOG_W/E within 8 lines above it. WireDeclineTally.h (the macro's definition) is not a site. Wired into the job that runs the fatal census. Audit before: 52 rows, 40 with sites, 10 unlogged under the W/E rule (rc 1). After: 53 rows, 53 with sites, 0 unlogged (rc 0). Forced red (ShapeNoVkFormat made true for 1x1 textures, reverted): Split.Fm.F1WireScenario.VertexIdSampler... fails on pixels with ShapeNoVkFormat=2 / TexShapeSync=2 in the shutdown tally. |
||
|
|
613ed05b98 |
[docs] (P7): ID-P7-35 - the B2 rework's first round is sent back, because its new case also lands on the monolith and Espryt entries and its per-row copy-out needs an aligned stride
The status page and the ROADMAP P7 row now say what is in flight after the six packages were relaunched on claude-opus-5-5: B2 rework round 2, B3 rework, M2, V1, F and E1. pipe stays at 1b5d97bd and is not pushed until round 2 lands. |
||
|
|
cc3c18c578 |
[scripts, docs] (P7): magma-b2.md counts the baseline as 73 + 11 + 2 + 2, carries the review round's §12 lines and gates, and the ratchet baseline names the tree that measured 173
ID-P7-31 review, note 3 and nits.
* §0's preamble: the +4 over package B's 84/63/65 is not "package A landing after
B" - A landed BEFORE B and is +2 (magma-a.md:151-153); package C is the other +2
(magma-c.md:59-61). 73 + 11 (B) + 2 (A) + 2 (C) = 88/67/69.
* §2.3 / §2.5: MsResolve1 is split+spawn only; the day-of +3 on tcp is marked as
superseded.
* §2.7 (the server-side knob has no tcp arm, measured) and §2.8 (flip mirrored,
scale declined, X / cross-format mirror declined; three red-once lines).
* §6: the lines for CONTRACT-P7 §12 - the scaled second leg is unclipped
(VUID-vkCmdBlitImage-dstOffset-00248/00249, shared with the monolith);
MagmaWireFatal("multisample-resolve-region") for a source rect outside the read
buffer, where GL promises undefined values rather than an error; the 1->N
identical-rect decline declines a legal shape (18.3.1 sample replication) because
the monolith's own observable is a VU violation; the tcp lane cannot carry a
server-side knob; X and cross-format Y mirrors of a depth/stencil resolve decline.
* §7: the review round's gates - magma 94/73/70, full-split 525, unit 2423, parity
RC 0 naming the five MAGMA_SERVER_ENV_KNOB_NO_TCP entries, census 79, ratchet 173,
G1 .text 0xa52203 with 0/0 symbol drift, @P7 19 comment lines.
* link_ratchet_baseline.txt: `base commit` points at 6af422b3, the tree that
measured 173, not 4bee1313.
The "@P7 = 24 lines" nit needed no edit: the note already reads 19 at 6af422b3, which
is what the tree measures.
|
||
|
|
645dd96f69 |
[MG_Backend, MG_IntegrationTest] (P7): a flipped multisample depth or stencil resolve lands mirrored and a scaled one declines, and neither ends the session
ID-P7-31 review, should-fix 2.
ResolveWireDepthStencil required sx1 > sx0, sy1 > sy0 and identical signed spans, and
took the session with Magma:multisample-depth-resolve-region otherwise - so
glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, COLOR|DEPTH) out of a multisample framebuffer
resolved its colour correctly and then died on its depth. GL 4.6 core 18.3.1 asks for
identical DIMENSIONS, not identical corners.
* spans are signed; everything downstream (renderArea, the shader arm's rectangle, the
buffer copy offsets, BlitDepthAcrossFormats' corners) works off the min corner;
* a SCALE is INVALID_OPERATION in 18.3.1 and now declines by rule I (a) with the colour
arm's three lines (MGLOG_E_ONCE, RecordTextureCopyError, return);
* a same-format Y mirror is done in the copy-out: one VkBufferImageCopy per row,
buffer row r written to destination row dyMin + height - 1 - r;
* an X mirror (a region per texel is not a copy) and a Y mirror across two formats
(BlitDepthAcrossFormats, shared with the monolith, has no flip) decline by name.
The region Fatal stays for a rectangle outside either image.
Scenario DepthStencilReadbackMatrixScenario.AFlippedMultisampleResolveMirrorsTheBandsAnd-
AScaleDeclines, registered as MsFlip. on all three magma arms (no knob): unequal depth
bands, COLOR|DEPTH in one flipped call with colour and depth asserted the same way up,
then a scaled depth blit that must be INVALID_OPERATION and leave the destination alone.
Red once (R-16, executed and reverted, split and spawn each):
* the old guard restored -> both arms die by
Fatal{UnmigratedVerb, "Magma:multisample-depth-resolve-region"};
* the scale decline turned back into that Fatal -> the flip half passes, both arms die
at the scale;
* the per-row copy-out bypassed (if (!mirrorY) forced true) -> both arms live and fail
"flipped resolve: the destination's bottom band: 768 of 768 depth values differ from
0.75; first bad value 0.25" (and the top band the other way).
|
||
|
|
9fed478dfd |
[MG_IntegrationTest, scripts] (P7): a server-side magma test knob is registered on split and spawn only, and the parity gate names the five entries tcp cannot carry
ID-P7-31 review, should-fix 1. Every MGITEST_MAGMA_FORCE_* knob is read BY THE SERVER (the getenv readers in WireFramebuffer.inc run on the apply thread), and a ctest ENVIRONMENT property only reaches the process ctest starts - the client. Inproc runs the server in that process and ServerSpawn.cpp copies ::environ into the spawned child, so both arms see the knob; the tcp arm's server is the lane-wide TcpServer.Start fixture, started once from scripts/ci/tcp_server_fixture.py's own os.environ, and nothing a per-case property says reaches it. The tcp copy of each knob=1 entry ran the DEFAULT arm under a name claiming otherwise. Measured, not deduced: a temporary fatal in each of the three readers killed all five knob=1 entries on split and on spawn and left all five green on tcp. So ShaderMip1, ShaderMip2, DepthMip, DefaultBlitShape1 and MsResolve1 are registered on split+spawn only (the first four are package B's pre-existing vacuity of the same shape). The knob=0 twins DefaultBlitShape0 / MsResolve0 keep their tcp entries: zero is the default and means the same thing on every arm. spawn_lane_parity.py names the exception, following ID-P7-14's MAGMA_INPROC_ONLY: MAGMA_SERVER_ENV_KNOB_NO_TCP, applied through a new compare_arms(no_tcp=) that drops the keys from the tcp comparison ONLY - folding them into inproc_only would stop requiring them on spawn, which is where they do most of their work. |
||
|
|
3c80cd62fe |
[docs] (P7): ID-P7-34 - OpenRA passes 27/27 on the phone; CURRENT_STAGE_STATUS.md is the live stage page and the ROADMAP rows say where P7, Ph and P3b/P4b stand
p7w5 (B3 on top of B2 and D3) renders OpenRA to the golden on every arm the acceptance asked for - inproc and spawn, run-ahead and lockstep, cold and warm, FIF=8 and the dump-armed variant that failed 0/5 before - and the three regressions are bit-identical to p7w4. Gate 3's anchor case is closed; bsl-esc-menu (M2) and the three-repeat final form remain. docs/Disaggregated/CURRENT_STAGE_STATUS.md is new: the nine-item exit denominator with evidence, what landed, what is running, what is next. The ROADMAP's P7, Ph and P3b/P4b rows carry the wave-2 landing, the 6/9 checkpoint and the open items, and OQ-8/10/13 are marked answered. |
||
|
|
dbea871a06 | [docs] (P7): §12 - the one present per bsl-esc-menu replay is the trace's own two swaps and the harness's snapshot exit, so server reclaim must not assume a bounded frame | ||
|
|
713bea9a8b | [docs] (P7): ID-P7-33 - B3 landed: the OpenRA divergence was an unsound frame-serial floor, proven by counter and closed on both submissions | ||
|
|
9a494b6f01 |
[docs] (P7): magma-b3 - the wire arm's frame-serial floor was raised on a fence it had not waited
Mechanism with file:line and the submission structure measured rather than assumed, the confirmation tallies (zero unforced, which refutes the silent-draw-drop hypothesis the investigation ranked first, and which the judge refuted independently on the prefix-tear forensics), the provable floor, the fence-backed second term in WriteWireBuffer, the red-once in three forms (a deterministic counter 26/26/0 -> 0/0/0, a two-process lane case, and forced OpenRA retraces), the gate numbers, and the device acceptance with three predictions H1 must satisfy. Records honestly: an earlier draft of this note blamed TryDrainFrameTransients' every-8th-drain frame boundary, which this package's own probe refutes (one successful drain in the whole replay, zero frame-boundary ones, all 33 serial bumps from Present); the GPU-drag knob the judge suggested was not built, with the reason; the aggregate-wait secondary fix is left to a separate package with the lane evidence that nothing in this tree's coverage regressed without it; and M1's "present fires once" observation does not hold for OpenRA, whose pbuffer replay presents every frame. |
||
|
|
511c1f1641 |
[MG_Backend] (P7): the completed-frame-serial floor only advances to a serial nothing in flight still carries
THE OpenRA DEVICE DIVERGENCE. "Frame-serial completion piggybacks on submission completion" holds only while a frame serial has ONE submission. On the wire arm it has two, measured on this trace: 73 submissions over 32 serials on inproc and on spawn, 30 over 32 on monolith. S1 is the per-frame palette glTexImage2D, which reaches UploadPendingWireLevels -> FlushWirePendingCommandsForTextureUpdate -> FlushPendingCommands at the first palette-sampling draw and submits under a POOLED fence. S2 is Present, and it carries the frame's draws AND the barriered vkCmdCopyBuffer that StagedWireRangeCopy records for every streamed glBufferSubData. RegisterSubmit stamps both with the serial current at submit time, so they share it. S1 is tiny and signals almost immediately. RefreshCompletedSubmits retires it alone, and OnSubmitsCompletedUpTo called NotifyFrameSerialComplete per retired record - advancing the floor to N-1 while S2(N-1), the submission actually carrying frame N-1's buffer copies, was still executing. GetCompletedSerial then returned N-1, so frame N's first write to that buffer failed WriteWireBuffer's busy predicate and took the unordered host memcpy at :268 - and S2(N-1)'s queued copies landed on top of it afterwards. That is why the wrong pictures are a PREFIX TEAR of one draw's vertex range rather than a missing draw: 318 vertices / 6 = 53 quads at 11448/53 = 216 bytes each, and 6696 = exactly 31 of them. 6696 and 11448 are both real write sizes of that same buffer (26 and 5 occurrences in this replay), so the damage is the previous frame's write list replayed over the new bytes, and its length is the largest write in whatever suffix of that list had not executed yet. It also explains the device's FRAMESINFLIGHT=4/8 result (6/6 whole-write loss): more frames in flight puts the GPU further behind, so the pending suffix contains the larger writes. The floor now advances only to a serial NO remaining in-flight submission still carries. NotifyFrameSerialComplete is monotone and already refuses the still-recording serial, so this can only advance the floor later, never further; the disaggregated build's monolith arm is behaviour-identical (one submission per serial, and its counter reads zero either way). The #else branch is the pull build's statement verbatim, which is what keeps G1 byte-identical. The counter is the red-once's reading, per lens C: an advance naming a serial some remaining submission still carries. Base 26 on inproc, 26 on spawn, 0 on monolith; zero on all three after this commit. It is logged per event rather than dumped at teardown because this trace's renderer is never Shutdown() - the process exits - so a teardown dump reports the start-up context's zero. |
||
|
|
a2e244c036 |
[MG_IntegrationTest] (P7): the streamed subdata-then-draw pair is a case on all three Magma arms
F1WireScenario.StreamedBufferSubDataBeforeEachDrawIsOrdered is OpenRA's frame reduced to four quads: one GL_DYNAMIC_DRAW VBO that is never orphaned, four batches written over the SAME offset-0 range and each drawn immediately, each in its own two-pixel column and its own colour. The case asserts PIXELS, because this path has no GL error and no log line to assert - a draw that read another batch's bytes still executes and still reports success. Two entries per arm. The plain Fm. entry is a regression gate that runs on every driver. The StaleSerial. entry carries MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL=1 and is the rule-J red-once: on integration-magma-spawn, at the package base, batches 0..2 lose their own vertices and batch 3 - the last write - keeps them, which is the mechanism spelled out in pixels. Its own ENVIRONMENT rather than a lane-wide flip, for the reason the ShaderMip pair gives: the knob changes how every streamed write in the process is answered. |
||
|
|
c9164f25d3 |
[MG_Backend] (P7): a streamed buffer write waits for the submission that reads it, not for a frame count
WriteWireBuffer answers a resource_subdata either with an ordered vkCmdCopyBuffer or with an immediate host memcpy, and it chose on `lastUseSerial > GetCompletedSerial()` alone. GetCompletedSerial is max(m_frameSerial - frameCount, m_completedSerialFloor) and its first term is PURE COUNTING - it asserts that work from frameCount serials ago has finished with no fence behind it. On the wire arm m_frameSerial is advanced not only by Present but by TryDrainFrameTransients -> VkBufferManager::BeginFrame on every 8th drain, which happens MID-FRAME, and package B established that mid-frame pooled-fence submissions are not covered by frame.imageInFlightFence. So the predicate could answer "idle" about a buffer that a recorded-or-in-flight draw still reads; the write was then applied unsynchronised and the draw executed reading somebody else's vertices - drawing another batch's geometry, or nothing at all, with no log line and no GL error. That is OpenRA's frame: ~24 glBufferSubData -> glDrawArrays pairs over the SAME range of one GL_DYNAMIC_DRAW buffer that is never orphaned, and a picture missing exactly one batch's quads. The predicate now has a second, fence-backed term: WireBufferResource carries lastUseSubmitIndex, set at every draw bind and staged copy to GetWireNextSubmitIndex() (m_submitCounter + 1 - what RetireWireObjects already tags future objects with, and deliberately NOT GetSyncPointSubmitIndex, which answers m_submitCounter when nothing is recorded yet, exactly the hole a draw acquiring its vertex slices before BeginCommandRecording falls into), and IsSubmitIndexComplete reports an unsubmitted index as incomplete. The counting term is kept because it only ever over-reports busy; the two are OR'd, so the answer is monotonically safer. GetCompletedSerial itself is untouched - it also serves the monolith VkBufferResource path and changing it would move the pull build's .text. MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL forces the counting term to answer "idle" (all writes, or the Nth one alone), which is the state a mid-frame idle drain puts the device into and which no host lane reaches by itself. It forces only the lie, not a bypass of the ordered copy, so it stays a valid red-once across this fix. |
||
|
|
76bbb6c300 |
[MG_Backend] (P7): every silent exit on the Magma wire draw path has a name, a tally and a decline line
Rule I admits two shapes for a refusal on the wire arm, a decline and a named Fatal. The draw path had a third one the rule does not allow: roughly forty bare `return false` statements with no log, no counter and no census entry, so a dropped draw left no trace anywhere - which is how the OpenRA device divergence survived four device windows with client and server logs that were line-identical between a passing and a failing run. WireDeclines.def names every one of them; WireDeclineTally.h expands that into a counter table plus MGL_WIRE_DECLINE_AT (the tally always moves, the log is once per site), in the shape of PipeApplier.h's ServerVerbSink tallies and for the same reason (R-16: a probe may not arm against a stub). Covered: SetupWireDraw and DispatchWireCompute (25), the three exits of PrepareWireTextureResources, the four of SyncTextureResourceByHandle, and UploadPendingWireLevels' five false exits PLUS the two that only `continue` - those report SUCCESS while leaving the entry pending, i.e. a draw that samples a level which was never uploaded, so they are counted apart. Also the pending-upload gauges (entries, bytes, peak bytes), sampled at the funnel, because a refused upload does not consume its entry and the level shadow behind it stays alive. Shutdown dumps the tally and is silent when it is all zero: a green lane stays quiet and a lane that dropped a draw cannot. Plus the drain probe behind MOBILEGL_MAGMA_WIREBUF_PROBE, which is what measured that a host replay reaches the mid-frame frame-boundary drain zero times. |
||
|
|
b089e0de9b | [docs] (P7): ID-P7-31 carries B2's review verdict and the rework it sent back | ||
|
|
fe9105350c | [docs] (P7): ID-P7-32 - bsl-esc-menu is a dead-VkBuffer leak on the wire arm, and the 40 % checkpoint passed at 6/9 | ||
|
|
85ac7e7692 | [docs] (P7): ID-P7-31 - B2 landed: the six §3.2 retirements are complete, the ratchet re-baselines at 173, and the judge's Magma debts are recorded | ||
|
|
116dc48e80 |
[docs] (P7): W4 §3b - the judge's verdict: an unsound completed-frame-serial floor lets a streamed write take the unordered host path
Four lenses and an adversarial judge: the two wrong OpenRA pictures are prefix tears of one draw's vertex range, produced when frame N-1's first pooled-fence submission retires and raises the buffer manager's floor while the Present submission carrying the staged copies is still running, so frame N's first glBufferSubData takes WriteWireBuffer's host-memcpy path and the queued copies overwrite it. FIF=4/8 fail 6/6, as that predicts. The later device sessions' logs (spawn, texture dumps, bsl memory, FIF) join the evidence directory. |
||
|
|
3c2867d34d |
[MG_Backend, scripts, docs] (P7): in a disaggregated build the monolith arm blits and mips with the baked modules, and the ratchet's p7-magma bucket falls to 88
CONTRACT-P7 §5.2's (B'), which §4.2 needs.
WHAT MOVES. In a disaggregated build the monolith arm now drives the SAME baked
modules the wire arm does:
* InitializeBlitResources / InitializeDepthMipmapResources return true - there is
nothing to build on any transport;
* TryBlitToDefaultFramebufferWithShader turns its two BlitImageBindings into
WireImages and calls BlitWireColorToDefault (WireColorBlit.inc);
* GenerateDepthMipmapWithShader loops GenerateWireDepthMipLevel
(WireDepthMipmap.inc) and hands the image back in the finalLayout its caller
promised;
* GetOrCreateBlitPipeline, the three GLSL strings, the eight kHidden* ids and the
frontend members of BlitResources / DepthMipmapResources compile out.
The `#else` is the pull build's code, statement for statement.
WHY AN `#if` AND NOT A RUNTIME BRANCH - this is the whole of §4.2. P5f fv already
gave both initializers a non-monolith early return, and the ratchet counted the
symbols anyway, because a reference is a reference whether or not the branch runs.
And the MEMBER has to go with the construction: a SharedPtr member's destructor is
itself a reference to ~ProgramObject.
THE BUCKET TABLE (scripts/link_ratchet.py --bucket, build-split):
bucket before after a6
p6-core 11 11 6
p7-magma 101 88 101
p3b-p4b-espryt 13 18 14
both-backends 61 56 60
total 186 173 184
p3b-p4b-espryt's +5 is not a regression: those five MOVED out of both-backends
because DirectVulkan stopped referring to them and only DirectGLES still does.
Thirteen symbols went away outright, and they are exactly the three classes §4.2
names: ProgramObject::{AllocateLifetimeId, AttachShader, Link, ~ProgramObject},
SamplerObject::{SetLodRange, SetWrapR, SetWrapS, SetWrapT} and
ShaderObject::{Compile, DropCompileNode, JoinPendingCompile, ReleaseCompileNode,
SetShaderSource}. Re-baselined in this commit with --write-baseline; the 7 `# P13`
annotations carried over.
§4.2's "down to 0" DOES NOT HOLD, and the gap is not (B') left half-done - it is
that 88 of the 101 were never about the hidden programs. 62 come from
UniformManager.cpp.o and 14 more from VkSamplerManager.cpp.o: the MONOLITH
descriptor binder and sampler cache reading the application's own GL texture and
sampler objects (TextureObjectBase 35, TextureObjectWithOneMipmap 20 with its
vtable and typeinfo, SamplerObject's fourteen getters). Under a transport
SetupDraw branches to SetupWireDraw and not one of those lines runs - but that
branch is a RUNTIME one, which ID-P7-5 deliberately leaves to the optimisation
phase. notes/p7/magma-b2.md §4.3 names all eleven referring-object groups and what
each is.
NONE OF THEM IS ANNOTATED `# P13`, on purpose: that mark is for a symbol that
cannot fall without moving pull `.text`, and nothing above has shown that.
UniformManager's and VkSamplerManager's monolith arms are pull-build code, and
`#if`-ing them is the same operation this commit performed on VulkanRenderer.cpp.
They are wave 3's work, not P13's boundary problem, and marking them P13 early
would record an untried thing as a tried-and-impossible one.
Gates: integration-gpu 1705 (every monolith `DirectVulkan.` entry is in there),
integration-magma-split 93, -spawn 72, -tcp 74, integration-magma-full-split 524,
ctest -L unit 2423, all green; fatal_census 79 abort sites / 44 family words / 0
unmarked; spawn_lane_parity green; link_ratchet --assert-monotone unchanged at 173
against the re-baselined file, and --self-test OK.
RETRACE, which is this slice's load-bearing reading because the monolith arm
changed implementation: OpenRA.DirectVulkan (monolith) ssim 1.000000,
mismatchPixels 0, twice; OpenRA.DirectVulkan.SPLIT ssim 1.000000, 0. The whole
DirectVulkan matrix is 39/40 monolith and 38/39 split, and both reds are the SAME
case, minecraft-1.21.4-fabric-iris-iterationrp-in-world (ssim 0.027915), which is
PRE-EXISTING - it fails identically on ~/w7/p7-magma-b (this branch's parent),
because it needs CONTRACT-P7 §2.4's three iterationRP knobs and those are exported
by the CI job rather than by the ctest entry.
G1 pull .text 0xa52203, nm --defined-only identical to p7-before/pull-syms.txt
(30570 lines, 0 diffs).
Device debt: the monolith arm in the Android disaggregated package now runs the
baked blit, and its ROTATE_90/180/270 geometry has never executed - every surface
on this host is IDENTITY. notes/p7/magma-b2.md §5 lists it with the package's three
other device items.
|
||
|
|
a50d50df60 |
[MG_Backend, MG_Impl] (P7): the two Magma allocator debt scopes go, because the objects they were about are never built off the monolith arm
CONTRACT-P7 §5.2's "the two MagmaP7AllocatorDebtScope are deleted with it (prove
first, with a temporary assert, that they never arm under a non-monolith
transport)".
WHAT THE DEBT WAS. The hidden blit program, its two samplers and the hidden depth
-mipmap program are FRONTEND objects. Under an active transport the server backend
created them on the apply thread and destroyed them on it, where their destructors
run the client death helper and its lifetime-id probe - so P5c gave the two
teardowns a named exemption and P5e ruling 12 renamed it after the debt.
WHAT RETIRES IT IS NOT AN EXEMPTION BUT AN ABSENCE. P5f fv already gave
InitializeBlitResources and InitializeDepthMipmapResources an early return for
every non-monolith transport, so off the monolith arm neither resource ever holds
anything and `m_blitResources = {}` destroys nothing. The scopes have been
markers over a path that cannot run since that day.
PROVED, NOT ARGUED. A temporary probe in both teardowns failed the session by name
if either resource was non-null under a non-monolith transport. With it armed:
integration-magma-split 93, -spawn 72, -tcp 74, integration-magma-full-split 524,
-full-spawn 524, integration-split 187 and integration-magma-buffers 21 all green -
it never fired. The negative control is what makes that a measurement: dropping the
probe's transport test killed EVERY monolith `DirectVulkan.` entry at teardown
(8/8 aborted, after the case itself passed) while the split entries stayed green.
integration-magma-full-tcp's one red under the probe is the documented StreamLink x
Magma exposure texel (CONTRACT-P7 §2.5's named tcp entry,
IterationRPProgram203Scenario), not a probe death - it fails, it does not abort.
THE COUNT AGAINST P5e RULING 12. That ruling named FOUR Magma sites
(VulkanRenderer.cpp x3 and ResourceTracker.h x1). Two had already gone before P7
began - `git log -S` puts the ResourceTracker.h site's removal in P5f fv (
|
||
|
|
51fa513d73 |
[MG_Backend, MG_IntegrationTest, MG_Test] (P7): a multisample depth or stencil buffer resolves on a device with no resolve extension, and the sample-count shapes with no arm decline
CONTRACT-P7 §3.2's `multisample-blit-aspect@P7`, the last `@P7` refusal in the tree.
Two halves again, and neither is the other's fallback.
THE HALF WITH AN ARM. vkCmdResolveImage is COLOUR ONLY. The one way Vulkan
resolves a depth or stencil aspect without a shader is a render pass with a
depth/stencil resolve attachment, which needs VK_KHR_create_renderpass2 and
VK_KHR_depth_stencil_resolve - and a device with neither ended the session at
`Magma:multisample-depth-resolve-capability` on the first
glBlitFramebuffer(GL_DEPTH_BUFFER_BIT) out of a multisampled read framebuffer,
which is what every multisample depth resolve in GL is. §3.2 names the second arm
and this is it: WireMultisampleResolve.inc, three baked modules (one vertex stage,
one fragment stage per aspect), fetching SAMPLE ZERO - the same sample
VK_RESOLVE_MODE_SAMPLE_ZERO_BIT picks, so the two arms answer identically and the
lane can assert that.
The pass carries nothing: the scratch has the source's extent and coordinate
space, so the fragment stage indexes by gl_FragCoord and the rectangle is the
scissor. No push constants, no varyings, no frontend object. The stencil half
needs VK_EXT_shader_stencil_export to exist at all (a fragment shader cannot write
the stencil aspect otherwise); where it is absent the arm declines stencil rather
than leaving the aspect undefined, and the module is not even created, because
handing vkCreateShaderModule SPIR-V with an unsupported capability is undefined
rather than an error.
The two capability tests are deliberately not the same test: the subpass resolves
every aspect the FORMAT has and needs a mode for each, while the pass writes only
the aspect this blit asked for - which is safe because the copy-out reads exactly
that aspect.
THE HALF WITH NO ARM. Sample counts that differ with the DESTINATION multisampled:
one sample fanned out to N, or N reduced to M. vkCmdResolveImage only ever writes
a single-sample destination, vkCmdBlitImage refuses a multisampled side, and
vkCmdCopyImage needs the counts equal. Rule I (a): name both counts, record
INVALID_OPERATION, leave the destination alone.
Lanes. DepthStencilReadbackMatrixScenario.AResolvedMultisampleDepth… is PROMOTED
from the informational tier into the three gated Magma arms - it already owns the
observable (clear a 4x DEPTH24_STENCIL8, resolve with glBlitFramebuffer, read both
aspects back, check that a depth-only resolve left the destination's stencil alone
and vice versa), it just had no gated entry. Two entries over it per arm: plain,
and under MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE, which is the only way the new
arm is reachable here at all - lavapipe carries BOTH resolve extensions, so the
extension arm answers every resolve on this host. The new F1 case is the decline.
It does NOT skip on this host: the shader arm resolves depth and stencil, because
lavapipe also carries VK_EXT_shader_stencil_export.
Three rows join MOBILEGL_BAKED_INTERNAL_SHADERS (8 -> 11).
Red once (R-16, executed and reverted), three times:
* restore MagmaWireFatal("multisample-depth-resolve-capability") for the
non-extension arm -> DirectVulkan.Split.MsResolve1.… dies by that name while
MsResolve0 stays green, which is also the proof that the knob routes;
* restore MagmaWireFatal("multisample-blit-aspect@P7") ->
DirectVulkan.Split.MsBlit.…FromASingleSampleSourceDeclines… dies by that name;
* fetch sample 1 instead of 0 in WireMultisampleStencilResolve.frag (no rebuild -
the gate reads the source at run time) -> WireMultisampleStencilResolveFragment
reds at word 158, naming the symbol, the header and the regeneration command.
Reverted, 15/15 green on the three arms and 11/11 on the freshness gate.
`grep -rn "@P7" MobileGL/ --include=*.cpp --include=*.inc --include=*.h` now
returns COMMENTS ONLY - 19 lines, every one of them prose about a retirement or a
red-once. No refusal in the tree carries the mark any more.
Gates: integration-magma-split 93 (+3), -spawn 72 (+3), -tcp 74 (+3),
integration-magma-full-split 524 (+1), ctest -L unit 2423 (+3), all green;
bake_internal_shaders.py --check reports all five headers fresh; fatal_census 79
abort sites / 44 family words / 0 unmarked; link_ratchet --assert-monotone
unchanged at 186; G1 pull .text 0xa52203, nm --defined-only identical to
p7-before/pull-syms.txt (30570 lines, 0 diffs) - every line lives under
`#if MOBILEGL_BUILD_DISAGGREGATED` or in the test tree.
Device debt: the shader arm is the arm the PHONE takes wherever
VK_KHR_depth_stencil_resolve is missing, and this host can only reach it through
the knob. Its geometry needs one look on the Redmi.
|
||
|
|
452d33b578 |
[MG_Backend, MG_IntegrationTest] (P7): a scaled multisample colour blit resolves into a scratch and blits that, and a multisample destination declines
CONTRACT-P7 §3.2's `multisample-blit-shape@P7`. The name covered two halves that
are not the same question.
The half with an arm: a multisample colour blit whose destination rectangle is a
different size from its source. vkCmdResolveImage carries one extent and one
offset per side, so it can express neither the scale nor the flip - which is why
this arm already resolved into a single-sample scratch at raw offsets and blitted
THAT for the flip. The two `width != |dx1-dx0|` clauses were the only thing
keeping the scale out of the same route, and the monolith arm reaches it the same
way (VulkanRenderer.cpp's `regionWasTransformed` branch). They are gone; the
scratch is still sized by the SOURCE rect, so only the second leg sees the scale.
The filter only started mattering with that scale - at 1:1 LINEAR and NEAREST read
the same texel - so the second leg now asks whether the format can be filtered
before it passes VK_FILTER_LINEAR, which is undefined behaviour on a format whose
optimalTilingFeatures lack SAMPLED_IMAGE_FILTER_LINEAR. GL ignores filter for a
multisample resolve anyway, so the fallback is NEAREST and not a refusal.
The half with no arm: a MULTISAMPLE DESTINATION. vkCmdCopyImage is the only
command that writes one, it takes a single extent, and GL 4.6 core 18.3.1 makes a
blit whose rectangles differ in size INVALID_OPERATION when either framebuffer is
multisampled. There is no picture to get right, so rule I (a): MGLOG_E_ONCE with
both rectangles and both sample counts, the error GL names, the destination left
alone, the session kept.
Two entries on each of the three Magma arms (`MsBlit.`), split-only because the
monolith arm drops the scale (its vkCmdResolveImage lands 1:1 at the destination
offset), so an equality between the arms would assert that the wire arm is as
wrong. The scale and the flip share one case over one source: dropping the scale
lands an 8x4 band in a 4x2 attachment, dropping the flip returns the right two
colours in the wrong order, and the second blit's expectation is the first's with
the rows swapped.
Red once (R-16, executed and reverted), twice:
* restore the two size-equality clauses ->
DirectVulkan.Split.MsBlit.…ScalesAndFlipsThroughTheResolveScratch dies as
Fatal{UnmigratedVerb, "Magma:multisample-resolve-region"};
* restore MagmaWireFatal("multisample-blit-shape@P7") ->
DirectVulkan.Split.MsBlit.…DeclinesAndKeepsTheSession dies by that name.
Reverted, 6/6 green on the three arms.
Measured on the way in: the decline's GL error reaches the client with a LATER
reply, not with the blit call, so the case's glFinish is load-bearing - without it
the INVALID_OPERATION surfaced attached to the 1:1 resolve twenty lines down.
Gates: integration-magma-split 90 (+2), -spawn 69 (+2), -tcp 71 (+2),
integration-magma-full-split 523 (+2), ctest -L unit 2420, all green;
fatal_census 79 abort sites / 44 family words / 0 unmarked; link_ratchet
--assert-monotone unchanged at 186; G1 pull .text 0xa52203 with an nm
--defined-only list identical to p7-before/pull-syms.txt (30570 lines, 0 diffs) -
every line of this commit is inside WireFramebuffer.inc's
`#if MOBILEGL_BUILD_DISAGGREGATED` or in the test tree.
|
||
|
|
22761a692d |
[MG_Pipe, MG_Backend, MG_Remote, docs] (P7): ID-P7-30 - D3's two review fixes: the bit-8 and bit-13 rows are pinned, and deletion ordering is guaranteed by the Live/Gen test
The vertex-input and buffer-bindings rows of SubsystemDeps.def became live behaviour when every reader started reading the table; two static_asserts now pin them the way the texture and programs rows already were. The "safe by construction" story about destroy ordering was inverted for the case where a view holds its owner's last reference - the owner's destroy reaches the wire first - so the three places that told it now say that the walk's Live/Gen test is the guarantee. |
||
|
|
498eb66a14 | [docs] (P7): ID-P7-29 - D2's rework landed on top of D3 | ||
|
|
a2d7fbd7ca |
[MG_IntegrationTest, docs] (P7): the census note carries its own gate readings and the right counts
Rework round 4 of 4 after the D2 review (fable, ID-P7-8).
COUNTS. The note said 71 cases per arm where its own table sums to 72, and "+37 entries
per split arm" - a number that matched nothing. The +37 came from differencing against
~/w7/pipe/build-split, the integrator's LIVE build directory, which had already moved past
this package's base (7ed5da52 -> 8c5dd6fc). Measured against the pinned
~/w7/p7-before/ctest-names-split.txt baseline this package adds 76 DirectGLES.{Split,Spawn,Tcp}.
entries per arm: 72 census + 3 TextureViewAlias + 1 TextureUploadShape. The raw diff shows
77; the extra one is CtWireScenario's kCapResidentSubData case from b56d70177, one of the
five P7 commits between that baseline and this package's base, and no CtWire file is
touched here. Both numbers and their provenance are now in the note.
GATES. The note pointed at espryt-d2.md for readings espryt-d2.md did not carry. It now
has its own table the way espryt-d1.md does: four lane totals, G1 .text and nm, the G14
name delta, and the five CI gates.
CMAKE. Drops the MGL_SPLIT_D2_FILTER_<Scenario> indirection, which was copied from the d1
and i1 blocks but never defined for any scenario here - a branch no run takes. Every D2
scenario is registered whole because the census found no case in any of them that needs
excluding; the d1/i1 shape is what to reach for the day one does.
And records that the TcpDevice arm gets the texture-view knob on its CLIENT half only. The
loopback Tcp arm's server is started by the TcpServer.Start fixture, which this package
also gives the knob; the TcpDevice arm's server is a supervisor already running on a
device, started outside this build, whose environment nothing here can reach. If it was
started without the knob every texture-view case in that arm green-skips - exactly what
the loopback arm did before the fixture entry got it. The arm is unconfigured in this repo
(empty endpoint, so it is not created at all), so this is a note for whoever configures it.
|
||
|
|
394df89237 |
[scripts, ci] (P7): the memo purity gate asserts its own anchors and allow-list, and stops calling a policy exemption an absence
Rework round 3 of 4 after the D2 review (fable, ID-P7-8). Three defects, each of a kind the gate could not have reported about itself. (a) TWO STRUCTURAL SELF-CHECKS. family_spans() returned whatever matched and nothing ever asserted that each of the five FAMILIES anchors found its declaration, so a renamed struct would drop a whole family while every rule kept passing. And an allow-list entry no rule can consult documents a carve-out that is not happening - a claim about the tree that nothing verifies. main() now fails on either, naming the anchor or the entry and saying which of the two repairs is wanted. Both are exercised: renaming an anchor and adding a dead entry each red the gate. (b) THE DOCSTRING AND THE test.yml COMMENT WERE WRONG about what the guards mean. MOBILEGL_PIPE_LEGACY_MEMOS defaults ON (CMakeLists.txt:43) and no job here clears it, so CI split builds DO compile those arms - TwinLookupMemo (DirectGLES.cpp:114) sits inside one and is compiled into every lane this repo runs. The rule is "the legacy arm MAY KEEP pointer keys", a policy exemption; only !MOBILEGL_BUILD_DISAGGREGATED is code a split build genuinely never sees. Both now say so. (c) FRONTEND HAD NO LEADING WORD BOUNDARY, so BackendSamplerObject* matched SamplerObject and the gate reported the memos' backend VALUES as frontend keys - which the first version answered with two allow-list entries, i.e. it documented a false positive instead of fixing it. (?<!\w) added, with controls both ways: the backend twins must stay green and the qualified MG_State::GLState::ProgramObject* must still match. The allow list therefore goes from six entries to ONE. Four were dead on arrival - two false positives now fixed at the source, one naming a typedef with no frontend type in it, and const void* program / Uint64 programLifetimeId, which no rule could ever consult because void is not in FRONTEND and neither line calls GetLifetimeId(). The ResolvedTextureBindingMemo monolith key those last two described is still deliberate and still there; it simply never needed an exemption, and saying it did was misleading. What remains is the twin registry's UnorderedMap<StateObject*, Entry>, which really is suppressed and really is the pull build's only arm. |
||
|
|
0f3b82725d |
[MG_IntegrationTest, docs] (P7): the upload-shape gate was measuring its own bounding box; inset the scatter so the box/rect decision is reachable
Rework round 2 of 4 after the D2 review (fable, ID-P7-8), which found that this gate's
numbers were right and its SUBJECT was wrong.
The scatter wrote 40 2x2 rects at x=((i*7)%32)*2, y=((i*5)%32)*2 into a 64-px atlas.
Both strides are surjective onto 0..31 over 40 iterations - rect 9 lands at x=62, rect 19
at y=62 - so the rects' union box covered the WHOLE LEVEL, and the server's subRectEligible
(Managers.cpp:8486-8491) requires !dirtyRegion.CoversWholeLevel, a BOUNDING-BOX test
(MipmapStorage.h:30-33). Both scatter textures were rect-INELIGIBLE on every arm before
:8649's unpack-ring policy was ever consulted. The box-versus-rect decision the scenario
exists to pin was never reached for the two textures it scatters into, and the only
texture that could move under any red-once was the contiguous control band - which is
exactly what the old substitute red-once's box=6 rect=3 jobs=12 was.
kScatterMargin insets the scatter by one rect: same 40 writes, same coarse stride, union
box bounded at (2,2)..(62,54). The gold row is UNCHANGED at emit=9 box=9 rect=0 jobs=9 on
all four arms - but it now means what it says.
THE RED-ONCE IS NOW ZERO-PATCH, which is stronger than the throwaway source edit it
replaces: MOBILEGL_ESPRYT_DISABLE_UNPACK_RING=1 alone gives box=3 rect=6 jobs=183 with
bytes/f[tex] falling from 104448 to 9024, while all 26 pixel cases stay green. BOTH
SCATTER TEXTURES moved - box=3 is the contiguous band alone, rect=6 is the plain atlas
AND the atlas written through the glTextureView, and jobs=183 = 3 + 6x30 confirms thirty
rects per scatter emission. The same knob was green before the inset, which is the
evidence that CoversWholeLevel was short-circuiting the decision.
The three prose sites are rewritten accordingly: the scenario's gold-table rationale, the
MEASUREMENTS.md 13.1 reading and the package note's red-once section now explain
attempts 1-3 as mutations of a decision the client already makes correctly, and attempt 4
by CoversWholeLevel rather than by the ring.
Also PipeStatsWindow gains LastFrom{Client,Server}LogSince, and the gate reads its two
role windows since a mark taken before the counted workload. The server writes an EMPTY
teardown window after the counted one, so "the last line in the file" is one shutdown
away from reporting four zeroes as the workload's shape. Moving to a marked read exposed
a second latent defect in the same assertion: ASSERT_TRUE(clientWindow.found) over the
whole file was satisfied by the "counters ON" BANNER in all three split arms, claiming a
window had been read when none had. The assertion is now on the window that actually
carries the tex[] bracket.
|
||
|
|
b3334cf336 |
[MG_Test] (P7): SubsystemDepsTest skips its two resolver cases in the pull build, and says what keeps the sweep alive
Rework round 1 of 4 after the D2 review (fable, ID-P7-8). Mirrors the integrator's 6da19f71 so that later commits from this worktree apply cleanly, and takes the two review notes attached to the same file. THE GUARD. The four Resolve<Family>SubsystemArm() declarations live inside did not compile in the pull build (ID-P7-11). Both now GTEST_SKIP under !MOBILEGL_PIPE_PUSH the way the client-side case already did. Verified by re-running the file's own compile command with -DMOBILEGL_PIPE_PUSH=0 and MOBILEGL_BUILD_DISAGGREGATED undefined: -fsyntax-only rc 0. WHAT KEPT THE MASK SWEEP ALIVE, now asserted instead of assumed: every resolver ends in ClassifyPipeSubsystemArm, and a NoArm verdict calls StopOnArmlessPipeSubsystem (Managers.cpp:2928-2938), which ABORTS. The sweep deliberately drives masks that refuse a family's handle arm, so it survives only because MOBILEGL_PIPE_LEGACY_MEMOS defaults ON (Config.h:399) and leaves a legacy arm standing. ASSERT_TRUE on that, with the reason - the day the default flips, this file would have aborted with no explanation. THE FRAMEBUFFER RESOLVER IS RECORDED, NOT ASSERTED, and the asymmetry is the finding: ResolveFramebufferSubsystemArm folds D-C3's wire-caps refusal in beside the dependency rule (Managers.cpp:4323-4325), and that half asks the server's published caps, which a bare unit binary with no session cannot answer in the affirmative. So a false says nothing about D-K2 and asserting true would pin whatever the binary happens to have linked. The sweep still covers it in the direction that matters. Also adds the 0x5ff refusal lane beside 0x7ff. |
||
|
|
310d4e90d1 | [docs] (P7): ID-P7-28 - package D3 landed; the texture-view exclusion is retired | ||
|
|
00d0239696 |
[docs] (P7): package D3's note, and the census row its fix falsified
P3b/P4b wave 2-D package D3, slice 3. docs/Disaggregated/notes/p34b/espryt-d3.md, in espryt-d1.md's shape: the mechanism end to end, the decision between resolving the predicate and indexing the reverse edge with the argument that decided it (deletion ordering), the red-once evidence with the exact ctest invocations and the red and green lines per arm, the gate numbers, and six things that remain. The decision, stated once here because the note argues it at length: the gate resolves through Desc.ViewOf to the storage record; the reverse index was rejected because it needs pruning on VIEW death or an owner upload bumps a recycled slot's Serial, because it makes ApplyTextureUpload write a record other than the one the call names, and because VkTextureManager::ResolveWireTextureStorage already resolves the same way on the Magma side - an index would have given the two backends two answers to one question. notes/p34b/split-scenario-census.md is updated where the fix falsified it - the summary row, the texture-family row and the exclusion section - and NOT rewritten anywhere else. D2's text stands and D3's resolution sits above it in a quoted block, because a package note is a record of what that package did rather than a live statement of the tree. Two citation corrections taken while reading the device-window baseline: the CTS block is KHR-GL46 and not KHR-GL43, and texture_view is 1/7 fail there with the failing case view_sampling, NOT coherency - coherency reads Pass, which is what D2 claimed and is now checked per case against report-texture.json rather than against a summary line. espryt-d2.md itself is left alone and the note says why it is left alone. Gates on this head, all measured rather than carried over: G1 .text 0xa52203, nm --defined-only 30570 symbols 0 added / 0 removed, -D 0/0, ninja -C build-linux rc 0. fatal_census rc 0 (79 abort sites, 0 unmarked - unchanged, rule I). link_ratchet --assert-monotone rc 0 (unchanged at 186). spawn_lane_parity rc 0. Lanes: unit 2418/2418, integration-split 264/264, integration-spawn 180/180, integration-tcp 183/183, integration-magma-split 75/75, all 100%. Name sets against a real ctest -N at a7c06f4f: +1 on each of split/spawn/tcp (the un-excluded case), 0 elsewhere, 0 removed anywhere. |
||
|
|
1c36987e84 |
[MG_Backend, MG_Pipe, MG_Impl] (P7): D-K2's dependency rule has one statement, and every reader reads it
P3b/P4b wave 2-D package D3, slice 2 - D2's two loose ends, now in-partition because D1 has
landed on feat/disaggregated and MG_Backend/DirectGLES/ is free.
THE STALE PROSE, in the header of the file that implements the refusal.
MG_Backend/DirectGLES/Managers.h's resolver block said "THREE OF THEM CARRY A DEPENDENCY"
(there are six rows; bits 8 and 13 were the two it did not know about) and listed
"10 without 11" among the mirror pairs that are FINE - when 10-without-11 is precisely D-K2's
fourth row (ID-14/ID-15), refused twenty lines below by ResolveTextureResourceSubsystemArm and
withheld by the client. MGPipe.h lost the identical pair of defects with R-5; this copy was
left behind because the file belonged to a package in flight. It does not restate the rows
again: the file that states them is the file the code reads.
BOTH READERS NOW READ MG_Pipe/SubsystemDeps.def. More than the two one-line changes D2
estimated, because the rule had six statements and the estimate counted two:
PipeFill.cpp P4aFamilyDependencyBits its own four-row kMGPipeP4aFamilyDependencies[]
-> MGPipeSubsystemRequires(); table deleted
PipeFill.cpp P5eFamilyIsLive hand-coded (pushMask & bit 7) == 0
-> MGPipeSubsystemDependenciesAreSet(bit 13, mask)
Managers.cpp PipeSubsystemDependencyMissing took a literal dependency BIT per call site
-> takes the FAMILY and asks the table
Managers.cpp the four resolvers five calls, five hand-written sentences
-> four calls, one per family, naming only the family
Managers.cpp ResolveVertexInputSubsystemArm hand-rolled bitSet && !resourcesBitSet
-> the table
DirectGLES.cpp ResolveBufferBindingSubsystemArm the same hand-rolled pair -> the table
MGPipe.h gains one accessor, MGPipeSubsystemDependencyWhy(), so a reader that refuses prints
the ROW'S OWN sentence instead of a copy of it. The .def has carried a Why column since R-5
and nothing read it; its "WHO READS IT" section is rewritten because "THEY ARE NOT SWITCHED
OVER IN THIS COMMIT" is no longer true of anything.
THE CLIENT'S ARGUMENT IS MASKED TO kMGPipeP4aFamilySubsystems, and that mask is the whole
difference between a rewrite and a behaviour change. The .def carries SIX rows; the table
deleted from PipeFill.cpp carried FOUR, and that predicate is wants()'s fourth conjunct for
P4a's families only. Reading all six unmasked makes the CLIENT withhold bit 8's vertex-input
emissions at a mask with bit 7 clear, which is P3a's own rule and not this gate's - caught,
not reasoned about, by TextureEmitTest's
EveryDKTwoDependencyRowGatesItsOwnFamilyAndTheMirrorPairsStayLive going red on exactly that
assertion ("bit 8 alone, with bit 7 clear: P3a's own rule, which this table must not touch").
Bit 13 is not narrowed there either; it asks the table for itself in P5eFamilyIsLive, because
bit 13's conjunct is bit 13's own. The ROWS come from one place; WHO each gate speaks for is
still each gate's.
ONE BEHAVIOUR IMPROVEMENT FALLS OUT rather than being designed in: the texture family is the
only row with two required bits and used to be two guarded calls, so a mask missing bit 11 but
carrying bit 7 was reported with the bit-7 sentence. One call now computes required & ~mask
from the row, so the refusal names whichever bit is actually missing.
WHAT THIS COSTS, said out loud. SubsystemDepsTest used to compare two COPIES of the rule; it
now compares two READERS of one table and cannot catch a typo in a row. It is kept and the
.def says why: both sides still fold in reasons of their own - the server's own family bit and
D-C3's wire-caps refusal, the client's consumer and wired conjuncts - and those can still
disagree at a mask. The compile-time half of D2's red-once (drop the fourth row from the .def
-> MGPipe.h:225/:230 fail) is untouched and is now the load-bearing one.
SubsystemDepsTest 5/5, TextureEmit's D-K2 case green, unit lane 2418/2418.
G1: .text 0xa52203, nm --defined-only 30570 symbols, 0 added / 0 removed, -D 0/0. Every line
is inside #if MOBILEGL_PIPE_PUSH or #if MOBILEGL_BUILD_DISAGGREGATED, and MGPipe.h's new
accessor is inline constexpr and unreferenced in the pull build.
|
||
|
|
1e1f4bad27 |
[MG_Backend, MG_IntegrationTest, MG_Remote, docs] (P7): an owner-side upload shows through a sampled texture view, because the split clean gate resolves to the storage record
P3b/P4b wave 2-D package D3, slice 1. The defect package D2 found with its new
TextureViewAliasScenario gate and excluded by name because the fix is outside D2's footprint.
THE HOLE. Once a glTextureView had been SAMPLED, a later glTexSubImage through the OWNER's
own name never became visible through the view, on inproc, spawn and tcp, green under
monolith. The client half was never at fault: the case's own emit-counter assertions pass on
the red run, so the records were emitted and the applier accepted them. A view owns no texels
and the client keeps ONE emission cursor per storage - an upload through a view's name is
remapped onto its storage owner before it is emitted (MG_Impl/Pipe/TextureEmit.h) - so every
resource_subdata for either name is keyed on the OWNER and ApplyTextureUpload moves the
OWNER's Serial and PendingUploads alone. BackendTextureObject::IsDrawSyncCleanByRecord read
the VIEW's Serial and PendingUploads, which nothing an upload does can move, so the gate
answered CLEAN for every owner write after the view's first sample and the sync that would
have drained the owner's pending uploads never ran.
THE FIX, AND WHY THIS ONE. The gate's two STORAGE clauses are asked of the STORAGE record -
this record for a texture that owns its texels, the record Desc.ViewOf names for a view -
through the new PipeTextureStorageRecordForRecord. The three PARAMETER clauses stay the
view's own record's, because a view has its own texture parameters and its own built-in
sampler, which is the whole reason the second name exists. SyncTextureViewToBackendByRecord
stamps that same storage serial at both its arms, so the stamp and the gate name one
quantity. This is the split equivalent of the monolith gate's GetContentVersion(), which
TextureObjectView forwards to its owner (TextureObjectView.cpp:100-102).
THE ALTERNATIVE WAS REJECTED. A reverse index owner->views, so an owner-side resource_subdata
bumps every viewing record's Serial, is the other shape D2 named. It is wrong here on three
counts: it puts new mutable state in MG_Pipe's applier, which both backends read, to answer a
question one backend's gate asks; it makes ApplyTextureUpload write a record other than the
one the call names, which breaks the applier's own serial discipline; and its index has to be
pruned on view death or an owner upload bumps a recycled slot's Serial - a silent
cross-texture hazard with no test that would catch it. The resolve direction needs no state,
no pruning, and is checked at every use: PipeTextureRecordForHandle tests Live and Gen.
DELETION ORDERING, WHICH DECIDED IT. A view holds a STRONG SharedPtr to its storage owner
(TextureObjectView::m_storageOwner) and the client emits resource_destroy from the DESTRUCTOR,
not from glDeleteTextures - "the last SharedPtr to this object dropping, not the glDelete*
that only marks the name and leaves a still-bound object very much alive"
(TextureObject.cpp:63). So an owner's record outlives every record that views it whatever
order the application deletes the two names in, and the forward edge cannot dangle. The walk
checks anyway, and a null answer is NOT clean - the direction that re-syncs.
VIEWS OF VIEWS. ONE hop always reaches storage: glTextureView composes a view-of-a-view onto
the ROOT at creation (the spec's additive min-level rule), the client's emitter says so and
TextureObjectView's invariant is that its owner is never a view. The walk is transitive
anyway and BOUNDED at four hops, because this side may not depend on a client invariant to
terminate; a cyclic chain the wire could forge ends as a null answer, which is "not clean",
not a refusal. No new abort site and no new Fatal (rule I): fatal_census abort_sites stays 79.
RED-ONCE (rule J), the case D2 excluded, with the exclusion lifted and nothing else changed,
at D2's head a7c06f4f:
ctest -R 'DirectGLES\.(Split|Spawn|Tcp)\.TextureViewAliasScenario' -j 3
-> 79% tests passed, 3 tests failed out of 14
4042 - DirectGLES.Split.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed)
4046 - DirectGLES.Spawn.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed)
4050 - DirectGLES.Tcp.TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary (Failed)
the first owner write, through the view: 11408 of 11408 pixels disagree;
first at (2, 2) is rgba(50,160,30,255), expected rgba(0,0,255,255) +/- 2
the second owner write, through the view: 11408 of 11408 pixels disagree;
first at (2, 2) is rgba(50,160,30,255), expected rgba(255,255,0,255) +/- 2
Only the PIXEL channel is red; the drain's emit counters pass, which is what places the
defect on the server. The monolith control DirectGLES.TextureViewAliasScenario.* is 4/4 in
the same run. With the fix: 14/14, 100%.
CONTRACT-P5E.md 5.2's clean gate is amended to state the rule the code now implements, and
says out loud that the rec->Serial form it carried through P5e was wrong rather than
restating it. The CMake exclusion is lifted; the scenario registers all four cases on all
three arms again (G14: the name never left any lane).
G1: .text 0xa52203, nm --defined-only 30570 symbols, 0 added / 0 removed, -D 0/0. Every line
touched in Managers.cpp is inside #if MOBILEGL_PIPE_PUSH (the gate and the resolver) or
#if MOBILEGL_BUILD_DISAGGREGATED (the view sync), and Managers.h's declaration is inside the
PIPE_PUSH block, so the pull build's preprocessed text is unchanged.
|
||
|
|
550f81d5f8 |
[docs] (P7): W4 §3b - the OpenRA hole is one draw (call 30376) reading vertex bytes other than call 30366's
Lens D placed 100 % of the wrong pixels inside the screen-space union of a single glDrawArrays whose vertex data was the frame's first glBufferSubData into the streaming buffer; the palette respecify is not the mechanism. The candidates are WriteWireBuffer's serial-gated branch and the mid-frame drain that bumps the frame serial without a fence. |
||
|
|
ebd73da06c |
[docs] (P7): the W4 evidence files are plain files, not executables
Copied off a Windows mount, they came in as 100755; nothing in them runs. |
||
|
|
770f1a0b3a |
[docs] (P7): ID-P7-26/27 - D2 lands with a rework round, and bsl-esc-menu is a memory defect, not an exclusion
D2's fable review says land with fixes: the TUS gate's scatter workload has a union box that covers the whole level (rect=0 is geometry, not the unpack-ring policy), the memo purity script fails open on a renamed family, and the census numbers were not reproducible - all sent back to D2 as one rework round; the excluded TextureViewAlias case gets its §12 row (owner D3). bsl-esc-menu-854 on the spawn arm: monolith passes at 807 MiB peak RSS, the server process dies at ~1.2 GiB in scudo's secondary allocator with 8 GB of system memory free, inproc dies at 1.6 GiB. That is the wire arm holding about twice the bytes (or the mappings) of the monolith, a disaggregation defect under ID-P7-12's rule, so it stays in the gate-3 denominator; M1 attributes it. |
||
|
|
dd6c541af7 |
[docs] (P7): ID-P7-25 - W4 on p7w4: 34/36 match monolith, and OpenRA is a silent draw drop, not a cold cache
Device window 1 W4 (APK p7w4 = 8c5dd6fc): iterationt x2 pass, the 39-case inproc matrix has 34/36 of the denominator within 0.0005 of the monolith reading, bsl-esc-menu still OOMs under inproc (spawn arm pending). ID-P7-19's cold-driver-cache reading of OpenRA is withdrawn: 26 runs show a ~50 % per-run coin flip that ignores cache temperature, IPC_AUDIT and FIF=1, reproduces on the two-process spawn arm, and only ever yields three pictures (golden / 9836 px / 14658 px). The monolith snapshot at the previous swap is the golden and the palette texture is byte-correct at the snapshot, so the wrong pictures are frames with a bounded run of draws silently skipped (nine sprite blobs absent over intact terrain). Gate 3's acceptance for OpenRA is now six run-ahead and six lockstep runs all equal to the golden; the fix is package B3. |
||
|
|
c2cc3a9673 |
[MG_Test] (P7): the subsystem-deps server-gate cases compile in the pull build too
D2's SubsystemDepsTest called the four Resolve*SubsystemArm resolvers, which Managers.h declares only under MOBILEGL_PIPE_PUSH (:664), so build-linux (the pull flavour, ID-P7-11) stopped compiling while the stale libMobileGL.so kept G1 looking green. Cases 3 and 4 now skip in the pull flavour the way case 2 already did; the unit name set is the same in both flavours. Pull build rc 0, .text 0xa52203, symbols 0 added / 0 removed; push flavour 5/5. |
||
|
|
519445f946 |
[MG_Pipe, MG_Impl, MG_Test, docs] (P7): D-K2's dependency rule in one table, with the case that fails when the two readers disagree
P3b/P4b R-5 (and R-3's cheap half), landing under the P7 program (PLAN-PH-P34B-P7.md
1.2, wave 2-D package D2).
The rule had SIX statements and nothing compared them, and two of the four prose ones
were wrong in the same way: MG_Pipe/MGPipe.h and MG_Backend/DirectGLES/Managers.h both
said "THREE OF THEM HAVE A DEPENDENCY" (there are six rows) and both said "the mirror
pairs (10 without 11, ...) are all fine" - when 10-without-11 is precisely D-K2's FOURTH
row (ID-14/ID-15), refused by the server and withheld by the client, with PipeFill.cpp
saying so out loud: "The brief's original 'bit 10 without 11 is fine' is WITHDRAWN for
P4a as built." Neither wrong comment could fail anything; Managers.h's copy sits in the
header of the file that implements the refusal.
The rows, once, in MG_Pipe/SubsystemDeps.def (X-macro, FatalFamilies.def's convention),
expanded by MGPipe.h into kMGPipeSubsystemDependencies[] / MGPipeSubsystemRequires() /
MGPipeSubsystemDependenciesAreSet() with four static_asserts. Six rows: 8->7, 9->10,
10->{7,11}, 11->10, 12->none (a ROW, not an absence), 13->7. Bits 8 and 13 are the two
the old comment did not know about; bit 13's row lived fifteen lines further down in the
same header, which is how "THREE OF THEM" survived two phases.
THE TWO READERS DO NOT YET READ IT, deliberately: MG_Impl/Pipe/PipeFill.cpp is the
contract package's file for the whole phase (TextureEmit.h states that rule) and
MG_Backend/DirectGLES/Managers.cpp belongs to wave 2-D package D1 while it is in flight.
Switching them is two one-line changes for the integrator. The anti-drift property does
not wait: MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp is the first thing in the tree
that calls BOTH readers at the same mask - sweeping the phase constants, the two
documented refusal lanes and one mask per row - and compares each against the .def. It
lives in that binary because that binary links both sides.
Both comparisons are one-directional, each for a measured reason. The server resolvers
also fold in the family's own bit and D-C3's wire-caps refusal, so a resolver may say NO
for its own reasons but never YES where the table refuses. MGPipeP4aFamilyEmits is a
QUADRUPLE and the first version of this case asserted equality and reddened at 0x1fff on
the sampler and program families because a bare unit binary registers no consumer - the
assertion being wrong, not the product, and recorded in the note because the temptation
to assert equality here is strong.
Red-once (R-16), twice: dropping the fourth row from the .def fails at COMPILE time
(MGPipe.h's static_asserts); making the server's ResolveSamplerSubsystemArm stop checking
bit 10 (throwaway, reverted) reds the runtime case and names the mask - 0x9ff, which is
exactly the lane CMakeLists.txt already pins for G12.
R-3's cheap half: CONTRACT-P5.md claimed the image-access, sampler-view-target and
draw-buffer encodings as contract by pointing at package-header LINE RANGES, and all
three had drifted (ImageEmit.h:146-159 no longer holds the encoding at all). All three
rows now state the encoding by enumerator and function name, and the two confusable
siblings are named. The remaining half - MGPSamplerView::Target still has no Count bound,
no ...IsValid and no Fatal for an out-of-range value - is stated in the row rather than
closed, being an MG_Pipe change outside this package's footprint.
Managers.h:690-695's copy of the wrong prose is NOT corrected here: it is package D1's
file, and its two defects are named in notes/p34b/espryt-d2.md so the integrator can take
them in one line.
G1 after this change: pull .text 10822147 = 0xa52203, nm --defined-only identical to
~/w7/p7-before/pull-syms.txt (30570 symbols) - the new inline constexpr table does not
reach the pull build.
|
||
|
|
779ff21b3e |
[MG_Test] (P7): the raw-depth-fetch sampler case runs both arms; the deletion half is P13
P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, "raw-depth-fetch sampler 的 monolith 清理,步骤 1+2", wave 2-D package D2). STEP 1 DONE. ContextEpochTest gains a case that drives GetRawDepthFetchSampler() on BOTH arms in one process and asserts they are two different BackendSamplerObjects, which is the observable form of the claim DirectGLES.cpp:334-336 makes in prose - "the legacy pair is not constructed or consulted by the server". A server that had fallen through to g_rawDepthFetchSamplerBackend would hand back the same pointer under both transports. It also asserts the transport arm's cached native sampler survives a round trip through the monolith arm, so neither arm is rebuilding state the other owns. STEP 2 NOT DONE, AND THE PACKAGE'S OWN CONDITION IS WHY. The instruction was to delete what the transport arm makes unreachable "ONLY if it keeps the pull build's .text identical". It does not. Every candidate is UNCONDITIONAL code - the two file-static SharedPtrs (DirectGLES.cpp:82-83), the monolith arm (:361-371), NeedsRawDepthFetchSampler (:393-399) and the pre-handle sampler-pass branch (:8015-8024). None sits behind #if !MOBILEGL_BUILD_DISAGGREGATED; the pull build configures DISAGGREGATED=OFF and PIPE_PUSH=OFF and links all of it, and the monolith arm is the ENTIRE body GetRawDepthFetchSampler has there. Deleting any of it moves pull .text and fails G1's 0/0/0/0 - the rule ARCHITECTURE.md:340 states for this exact class of retired-but-compiled code. Recorded as P13, beside the existing S7 entry in notes/p5f/f0-statics.md, rather than attempted and reverted. G1 on this head: .text 10822147 = 0xa52203, nm --defined-only identical to ~/w7/p7-before/pull-syms.txt (30570 symbols). |
||
|
|
9a69e08365 |
[MG_IntegrationTest, docs] (P7): twelve texture and program scenarios join the split arms, with the census that put them there
P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, "门:纹理 /
program 场景 split 覆盖", wave 2-D package D2). Each candidate was run once under
MOBILEGL_TRANSPORT=inproc on build-split and its first blocker recorded; the row per
scenario is in notes/p34b/split-scenario-census.md.
Registered (all green on inproc, spawn and tcp): TextureView,
TextureParamsWithoutASamplerView, SampledSetStaleness, ImageSizeAfterRespec,
ImageTargetKind, IntegerBorderColor, SwizzleAccessRoutine, PostLinkAttach,
RelinkStageSet, UniformInitializer, Glsl420Declaration, IoBlockNameCollision. 71 cases
per arm, 213 new gating entries; the recorded split-arm registration count the tier-2
Magma replay walks goes 33 -> 46.
TextureParamsWithoutASamplerView settles the debt table's 待核 row: all four G9 cases
pass under all three transports, so the P6 inspection-forwarder debt is closed for this
half - and it is now re-taken on every CI run rather than by inspection.
ProgramPipelineScenario beyond *StorageBlock* is NOT registered, and that is the rule
working rather than a blocker to retire: the other nine cases are pure name/state cases
that draw nothing, and an armed DirectGLES.Split. case whose workload produced no record
is red by design (ScenarioFixture.h:84-97 - the client encoder's record ordinal must
move). Registering them would assert "records crossed" about cases with no records to
send.
DirectVulkan arms default to none, deliberately, and the note says why: the
informational tier-2 block already replays every recorded registration on DirectVulkan
under integration-magma-all-{split,spawn,tcp}, so these scenarios do get a Magma x
three-transport reading - just not a gating one. Gating them would assert P7 wave 2's
exit gate 1 from inside a P3b/P4b package, on a backend whose own @P7 refusals are still
being retired in waves A/B/C.
D1 owns PixelStoreSweep, DepthStencilReadbackMatrix, PackedWordReadback and
LayeredTextureReadback; they are not in this census.
|
||
|
|
6567bc1e16 |
[scripts, ci] (P7): a purity gate for Espryt's re-keyed memo families
P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, wave 2-D package D2): "一条纯度 grep 门:split 构建下这些 memo 键里不得出现前端指针类型;接 CI". scripts/ci/espryt_memo_purity.py, a sibling of link_seam_purity.py in the same style: a hard-coded source list, a code_only() comment strip, (pattern, message) rules, and a --self-test that runs the negative controls and then the real scan in one invocation - which is what lets test.yml pass only --self-test and still get the gate. Wired in next to link_seam_purity.py. It scopes the rules to the BRACES of the families the plan names - ResolvedTextureBindingMemo, SamplerPassMemo, UnitSamplerLookupMemo, TwinLookupMemo, StateBackendObjectRegistry (the program registry and its five siblings) - plus the image sweep, which is seven file statics rather than a struct and is matched by name. Scoping matters: these two files pass frontend pointers around legitimately in hundreds of places, and a file-wide grep would be a list of exceptions rather than a gate. Guard-awareness is a small conditional walker, not a preprocessor: it recognises #if MOBILEGL_PIPE_LEGACY_MEMOS, #if !MOBILEGL_BUILD_DISAGGREGATED and the #else of #if MOBILEGL_BUILD_DISAGGREGATED, which is every spelling these files use, and says so in the docstring. Six allow-list entries, each carrying its one-line reason. The two that matter: StateBackendObjectRegistry's UnorderedMap<StateObject*, Entry> and ResolvedTextureBindingMemo's type-erased `const void* program` are the PULL build's only arms - deleting them moves pull .text and fails G1's 0/0/0/0, so they retire with the pull path (P13), not here. The other four are memo VALUES rather than keys. Seven negative controls turn red; four positive controls stay green, including a LEGACY_MEMOS arm, the #else of a DISAGGREGATED arm, the allow-listed type-erased key and a frontend pointer outside every memo family. Verified once more by injecting a fresh unguarded ProgramObject* field into the real ResolvedTextureBindingMemo: the gate reddens and names it. |
||
|
|
5617c5c3b3 |
[MG_IntegrationTest, docs] (P7): the texture upload shape becomes a gate, with the view remap inside the workload
P3b/P4b R-11 / D-D4, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, wave 2-D
package D2). P4a recorded the emission shape rather than gating it because the
per-storage-owner cursor with view/owner remapping was the next phase's and gating an
unfinished shape pins a non-answer. That work landed, so the RecordProperty block is
now EXPECT_EQ against a gold row MEASURED on this cursor, and the workload carries a
third texture written through a glTextureView so the remap is inside the counted
window.
The gold row, identical on monolith / inproc / spawn / tcp:
emit=9 box=9 rect=0 jobs=9, client emitter 9
keyed on the workload constants by static_assert. P4a's emit=6 box=6 rect=0 jobs=6
was a two-texture workload with no client emitter and is not comparable.
The client half is read from MGPipeTextureEmitter::SubDataCount() rather than from
ctu=, and that is a correction: under spawn and tcp the two roles are two processes
whose PipeStats windows close on different Present cadences (measured ctu=13 against
emit=9, and usually not yet written when the case reads), so ctu == emit is not a
well-posed comparison there. The log field is kept as a record and asserted only
where the transport says the two are window-aligned - asking the NUMBER was the first
mistake, because the server publishes a readable ctu=0 under spawn and the comparison
silently became 0 == 9. PipeStatsWindow gains LastFromClientLog/LastFromServerLog.
Split/spawn/tcp arms added as explicit per-arm blocks rather than through
mgl_itest_register_split_arms: the macro hands every arm the shared environment, and
this case needs a lane marker, PipeStats period 1, a push mask and above all a
MOBILEGL_LOG_FILE_PATH private to the arm - the library opens the log "w", so two
entries sharing a path truncate each other and the failure looks exactly like "the
counter was never emitted".
Red-once (R-16): the prescribed flip of summedArea*4 >= unionArea*3 leaves the gate
GREEN, and that is a finding. Two gates downstream dominate it - the server needs
dirtyRectCount >= 2, and UnpackRingAvailable() zeroes the rect list by design ("one
box, one job", the existing Mali-cliff mitigation). So rect=0 is the policy's
intended output, not an accident of the scatter pattern. The red-once that bites
splits the union box in two AND disables the unpack ring: box=6 rect=3 jobs=12
against the gold, while 26 pixel cases stay green. Four attempts and their reasons
are in the note.
The Mali frame-time delta D-D4 asks for beside the gold is NOT schedulable - one
Redmi, an Adreno, no Mali part - and is recorded as a declared deviation in the
scenario header and MEASUREMENTS.md 13.3 rather than modelled.
Also corrects the three places that said the client emitter had not landed: the
scenario header, the CMake probe's comment, and gates-v1.md's re-run table.
TextureEmit.h's EmitOneLevel has been incrementing it.
|
||
|
|
da30c1301e |
[MG_IntegrationTest, docs] (P7): the owner-keyed emission cursor gets the scenario that can see it
P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, wave 2-D
package D2). The code half of "按存储属主键控的发射游标与 view 索引重映射" landed in
P4a/P5e; this is the verification half it never had.
TextureViewAliasScenario, four cases: an upload through a layer-restricted view
sampled through the owner and the reverse, each once and again across draw
boundaries so the drain runs three times. Each case asserts on TWO channels at
once - sampled texels AND MGPipeTextureEmitter's SubDataCount / RefusedSubDataCount
/ DrainListSize, read through the new Harness/TextureEmitPeek. The counters are the
load-bearing half: a level that never made it onto the drain list is still uploaded
by the next whole-level respecify, by a glGenerateMipmap or by the monolith sync
path, so the picture comes out right one frame late and a pixel-only case goes green
over the regression on most trees.
Registered in the three GLES split arms, and MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1
added to MGL_ITEST_GLES_{SPLIT,SPAWN,TCP,TCPDEVICE}_ENVIRONMENT - views are Espryt's
opt-in and without it every case green-skips. The Tcp arm needed the knob on the
TcpServer.Start fixture as well: that lane's server is pre-started rather than
spawned from the client, so it withheld GL_ARB_texture_view and all four cases
SKIPPED while the identical Split and Spawn arms ran.
Red-once (R-16): TextureObjectView::MarkStorageDirtyRegion made to call
PipeNoteLevelDirty on ITSELF instead of forwarding to the storage owner - the
two-cursor shape. TheViewUploadDrainRunsAgainAfterADrawBoundary goes red on both
channels simultaneously (stale owner texels AND SubDataDelta() == 0). The plan
predicted case (a); it is (c) that reds, because the first drain of a texture's life
carries the whole level anyway - recorded in the note.
TheOwnerUploadDrainRunsAgainAfterADrawBoundary is EXCLUDED BY NAME from the split
arms: it is red on all three transports and green under monolith, because an
owner-side resource_subdata moves only the owner's record.Serial and nothing
propagates that to the records viewing it. Cause and the two candidate fix sites are
named in the CMake comment and in notes/p34b/espryt-d2.md. The name stays in every
lane (G14).
|