Commit Graph
23 Commits
Author SHA1 Message Date
swung0x48 f4994ee36e [Chore] (MG_Backend, MG_Backend/DirectGLES, MG_Backend/DirectVulkan, MG_Backend/MGPipe, MG_Backend/Record, MG_Benchmark/Buffer, MG_Benchmark/Container, MG_Benchmark/Driver, MG_Benchmark/Program, MG_Benchmark/ShaderCache, MG_Benchmark/Transpile, MG_Gbm, MG_Impl, MG_Impl/CGLImpl, MG_Impl/DyldInterpose, MG_Impl/EGLImpl, MG_Impl/GLImpl, MG_Impl/GLXImpl, MG_Impl/NSOpenGLImpl, MG_Impl/Pipe, MG_Impl/WGLImpl, MG_IntegrationTest, MG_IntegrationTest/Harness, MG_IntegrationTest/Scenarios, MG_Pipe, MG_Remote, MG_Remote/Client, MG_Remote/Protocol, MG_Remote/Server, MG_Remote/Transport, MG_Remote/Wire, MG_State/EGLState, MG_State/GLState, MG_Test, MG_Test/Backend, MG_Test/BackendLoader, MG_Test/Buffer, MG_Test/EGLState, MG_Test/Framebuffer, MG_Test/Gbm, MG_Test/Pipe, MG_Test/Pipeline, MG_Test/Program, MG_Test/Query, MG_Test/SelfTest, MG_Test/ShaderTranspiler, MG_Test/State, MG_Test/Swapchain, MG_Test/Texture, MG_Test/Util, MG_Test/VertexArray, MG_Test/Wire, MG_Util/Async, MG_Util/BackendLoaders, MG_Util/Converters, MG_Util/Damage, MG_Util/Debug, MG_Util/Math, MG_Util/Metrics, MG_Util/SelfTest, MG_Util/ShaderTranspiler, MG_Util/Texture, MG_Util/X11, MobileGL, scripts/data, tools/cts, tools/device_bench, tools/spikes, tools/trace_replay, tools/wgl-smoke): clang-format every C and C++ source
- Layout only: token streams match up to split literals, continuations and using order
- The size totals fall, so the structure baseline is lowered
2026-10-16 06:30:38 -04:00
swung0x48 5370d917d0 [Docs] (.github/workflows, MG_Backend/DirectGLES, MG_Backend/DirectVulkan, MG_Benchmark/Driver, MG_Impl/EGLImpl, MG_Impl/Pipe, MG_IntegrationTest, MG_IntegrationTest/Harness, MG_IntegrationTest/Scenarios, MG_Pipe, MG_State/GLState, MG_Test, MG_Test/Pipe, MG_Test/Program, MG_Test/SelfTest, MG_Test/ShaderTranspiler, MG_Test/Swapchain, MG_Test/Wire, MG_Util/Async, MG_Util/BackendLoaders, MG_Util/SelfTest, MG_Util/ShaderTranspiler, MobileGL, scripts/ci, tools/spikes, tools/trace_replay): name drivers and techniques instead of external projects 2026-10-15 10:15:37 -04:00
swung0x48 575be3532d [Perf] (TLS): pGLContext and gPipeInputs become pointer slots 2026-10-10 04:14:09 -04:00
swung0x48 8abae647d0 [Refactor] (P13 W6d): Espryt's family arm predicates fold to the record arm, checked once at capability bring-up, and the frontend-arm walks they selected go. 2026-10-06 18:08:33 -04:00
swung0x48 e0113503af [Refactor] (P13 W6b): the frontend-arm code after each record-arm return goes, and the transform-feedback state keeps one role. 2026-10-06 16:46:09 -04:00
swung0x48 742d43aeb4 [Refactor] (P13 W6b): the data-arm predicate folds out of every backend branch; frontend-arm unit cases go, three adapted, and two GL sampling rules move to an integration scenario. 2026-10-06 16:39:52 -04:00
swung0x48 7fb18840dc [Refactor] (P13 W5 S8): MOBILEGL_BUILD_RECORD_ARM is folded away - the record arm is unconditional - and retired_switches keeps it from coming back. 2026-10-06 15:03:11 -04:00
swung0x48 8a2ddc8150 [Refactor] (P13 W5 S3): Magma's funnels, the texture ops and the staged-texture macros follow the record-arm guard; shared images stay transport. 2026-10-06 11:53:24 -04:00
swung0x48 036d1ac36e [Refactor] (P13 W5 S2): MG_Backend/DirectGLES's record-arm guards name MOBILEGL_BUILD_RECORD_ARM. 2026-10-06 10:51:25 -04:00
swung0x48 af84eac8ee [Feat] (P13 W4a): Espryt monolith takes the record arm for buffers, indirect, client arrays, binding points and fp64 through an in-process verb port 2026-10-06 08:14:37 -04:00
swung0x48 a0bff7cee1 [Refactor] (P13 W3b): backends read MG_Pipe::gPipeInputs directly, MGB_CTX and its switch header are gone 2026-10-06 04:04:46 -04:00
swung0x48 e52a997f34 [Fix] (Espryt, P8-C): the split server refreshes its staged copy of a buffer a shader wrote before a CPU reader consumes it - storage/atomic/buffer-image writes mark the server twin, XFB captures land in the copy, the restart rewrite, multi-draw rebase, *IndirectCount, CPU-fed indirect fields, XFB scatter and fp64 narrowing read through SplitHostBytesForCpuRead; GpuWrittenDrawInputScenario (12 cases) on the split arms 2026-09-29 22:38:33 -04:00
swung0x48 2a69f61c88 [Feat] (Espryt, P11 B2): import a T0 store with glBufferStorageExternalEXT as the adopted twin - no staged copy, server writes queued GPU-ordered, CPU readers on the import's coherent map, fence-gated release, re-import after a context loss, and the sustained-lock POST in a throwaway context 2026-09-29 17:50:50 -04:00
swung0x48 efe58eac14 [MG_Backend, MG_Pipe, MG_Impl, Docs] (Disaggregated): P5e ra2 ID-136 - retire the indirect-binding pull instead of escalating for it, and withdraw escalation (iii)
- TOUCHING mv's FILE UNDER ID-136, deliberately and by ruling: MG_Backend/DirectGLES/
  MultiDraw.cpp is mv's per ID-113, and the integrator overrode that boundary for this one
  change because the two halves must not exist apart on any head. The boundary has not drifted.
- BoundDrawIndirectBufferId (MultiDraw.cpp) gets the handle arm its neighbour
  ResolveBoundIndexBuffer already had, in mv's own idiom rather than a second one beside it:
  the arm is `MG_Config::Transport != Monolith`, STATED (ID-81) and never inferred from a null
  handle (ID-110); a null handle is "this verb bound no indirect buffer", the same 0 the
  monolith arm returns for an empty slot; a missing backend resource is the named refusal
  Fatal{RoleViolation, "multidraw-indirect-buffer-arm"}, a sibling of mv's
  RefuseMissingIndexBufferRecord, never a quiet fall-back to the frontend. The monolith body
  below it is unchanged token for token. The function moved down beside BoundIndexBufferId,
  which is the same question about the other target.
- WHY A HANDLE ARM AND NOT A MIGRATION: the tier never reads a byte of the client's indirect
  buffer. It binds its OWN scratch command buffer and wants to put back the name that was
  there - a save/restore. With a transport the only other writer of this process's
  GL_DRAW_INDIRECT_BUFFER is DirectGLES.cpp's DrawSyncBit::IndirectBuffer arm, which binds from
  MGPipeApplier().VerbIndirectBuffer and nothing else, so "what was bound" IS "what the verb's
  record named".
- Escalation (iii) withdrawn in the same commit - MGPipeBarriered's clause, the client's
  verb-keyed half in ClientVerbIsBarriered, and the contract row. It was never wrong, it was
  the wrong instrument: there is one draw opcode and the tier is chosen server-side per batch,
  so the narrowest key both roles could compute charged EVERY plain glMultiDraw* on the
  auto -> ext default - a per-batch rendezvous on the arm the phone ships, added to make a lane
  green. THE CHECK ON AN ESCALATION IS "WHICH ARM PAYS FOR IT", NOT "WHICH LANE GOES GREEN";
  the rule is recorded in PipeApply.h beside the three that remain and in CONTRACT-P5E §2.1.
- Red-once D: `if (false && ...)` on the new arm and the entry dies 3/3, deterministically, on
  `Fatal{UnmigratedPipeInput, "GetBufferBindingSlot@DrawArrays"} [BARRIER-PULLED, UNBARRIERED,
  the client did not fill it, retires in P8 (indirect), P9 (readback), P13 (transfer)]`.
  Its counterpart is this head itself: the escalation is GONE and the lane is green, so nothing
  needed it - and the strict census's admitted set drops from nine rows back to ID-128's eight,
  because the pull no longer happens at all rather than being legalised.
- Gate on the flipped head: unit 2256/2256, isplit 179/179, gens rc=0, lane counts unchanged
  (179 / 1357 / 2 / 2).
2026-09-18 14:10:04 -04:00
swung0x48 98ea16042a [MG_Backend] (Disaggregated): P5e mv - the multi-draw path stops reading the frontend VAO
- MultiDraw.cpp asked the bound element array buffer three questions (is one bound,
  what GL name is bound and how big is its store, give me its bytes on the CPU) and
  asked all three of MGB_CTX->GetBoundVertexArray() on the apply thread. That was the
  last unguarded read of that field in the backend: package vi retired the ordinary
  draw path's copy and this one survived only because these 9 entries used to die
  earlier, on the framebuffer row fb has since retired.
- ResolveBoundIndexBuffer(question, entry) answers all three from
  MGPipeApplier().IndexBuffer.Res on the record arm - EnsureBufferResourceForHandle
  for the driver name, ResourceWidthForHandle for the size, the server's staged
  shadow (hostBytes + RequireStagedCoverage) for the CPU bytes - and keeps the
  monolith body token for token below it. No wire row was added.
- The arm is STATED, not inferred (ID-81 / ID-110): BufferImpl::VertexInputReadsRecords(),
  the family's own selector, which reduces to Transport != Monolith AND the vertex-input
  bit. Nothing here decides an arm from a null pointer or a noted handle.
- A missing record on the handle arm is a named refusal:
  Fatal{RoleViolation, multidraw-index-buffer-arm}, the shape of
  RefuseNullFrontendTextureOffTheHandleArm. The frontend element slot is not a second
  opinion on this side - it answers for whatever the client has bound now.
- VertexInputReadsRecords() moved from DirectGLES.cpp to Managers.h, unchanged, so the
  two translation units on this draw path share ONE selector rather than a copy each.
- Strict census: GetBoundVertexArray@DrawArrays 9 -> 0. The same 9 entries now stop on
  GetProgramForDraw@DrawArrays, which is pa's row; no other row moved, no new row.
2026-09-18 11:38:28 -04:00
swung0x48 d4504e30f8 [Refactor] (Espryt): route every frontend read through MGB_CTX - 113 arrow sites sed'd, 9 non-arrow lines converted (the fb-slot cache keys on MGB_CTX_IDENTITY); pull build byte-identical
- P1 package B (BRIEF-P1 C.2): the four DirectGLES TUs include <MG_Pipe/PipeInputsSwitch.h> right after
  their MG_State/GLState/Core.h include (Managers.cpp after its Managers.h include) and spell every
  frontend read MGB_CTX->Accessor(...). In the pull build MGB_CTX is MG_State::pGLContext, so the
  code is the tree before this commit token for token; in the push build it is &gPipeInputs, the block
  the frontend fills at every verb boundary.
- 113 arrow occurrences on 113 lines went through the mechanical sed (DirectGLES.cpp 91, Managers.cpp 15,
  MultiDraw.cpp 5, Utils.cpp 2). The 9 non-arrow lines follow D9: Managers.cpp's five bare/compound
  guards and three ternary conditions become MGB_CTX_LIVE (UniquePtr::operator bool spelled out, so the
  pull build does not move); DirectGLES.cpp's GetFramebufferBindingSlotFast keys its static cache on
  MGB_CTX_IDENTITY (a const void* compare) instead of pGLContext.get().
- The cache refill loop dereferences MGB_CTX once into a local reference and reads the slots through it,
  instead of &MGB_CTX->GetFramebufferBindingSlot(i) per iteration as D9 spells it: a store into
  g_fbSlotCache (a pointer) may alias the unique_ptr's own pointer under clang's TBAA, so the per-iteration
  spelling re-reads pGLContext inside the loop and grows the three functions the loop is inlined into
  (SyncCurrentProgram +16, ForceBindCurrentFBO +9, BlitNamedFramebuffer +1; .text +32). Hoisting the
  dereference restores the single load and a zero .text delta.
- grep -rc pGLContext MobileGL/MG_Backend/DirectGLES reports 0 in every file; symbol_report --threshold 0
  against the 087685d1 baseline: 0 added / 0 removed / 0 resized / 0 renamed, .text +0, nm --defined-only
  set identical. The only bytes that move are __LINE__ immediates in RecordError sites after the inserted
  include line. The 8 SyncPersistentMappedRange and 3 SyncGpuWrites sites and the PipeStats AddCalls
  literals are untouched.
2026-09-06 04:41:28 -04:00
swung0x48 d380a01f32 [Fix] (Metrics, DirectGLES, DirectVulkan): stop the summary line printing window totals under a per-frame label, and wire the six staging paths the site inventory claimed were covered or absent
- A window with no Present divided by a faked 1 and printed the window TOTALS under
  "bytes/f[...]": the *MultiDraw* slice (47 draws, no present) reported 1,404,550 bytes as a
  PER-FRAME figure, a 47x overstatement of exactly the SEG_STAGE sizing input plan B section
  8.2 / section 11 P0 asks this package to produce. FormatWindowLine now relabels the bracket
  to "bytes[...]" and prints draws/f=n/a when the window holds no frame; acc/draw=n/a follows
  the same rule, because "0.00" beside a non-zero acc= is the same lie. Pinned by
  PipeStatsTest.SummaryLineSurvivesZeroFrames and the reworked SummaryLineSurvivesZeroDraws.
- Every per-frame and per-draw field now goes through one FormatFixed2 helper. draws/f read 1
  for 26 draws over 14 frames (1.86) and buf read 97 for 1360 bytes (97.14): a systematic
  downward truncation of up to a whole unit on the figures the package exists to produce.
  Pinned by PipeStatsTest.PerFrameFieldsKeepTwoDecimals.
- FormatSummaryLine rewrote the window bases as a side effect of formatting, so any second
  reader silently zeroed the next window. Split into a pure FormatWindowLine() and an explicit
  AdvanceSummaryWindow(); EmitSummaryLine calls both. Pinned by
  PipeStatsTest.FormattingTwiceDoesNotConsumeTheWindow.
- Init() called ResetForTesting(), against the header's own "not used by any shipping path".
  Both now forward to an internal ResetCounters().
- TracyPlot published only the MISS half of each gate under the gate's unqualified name, so
  the headline output channel of section 11 P0 carried no denominator. Two series per gate now
  ("...-hit" / "...-miss") from static literal arrays. The payload histogram stays unplotted
  and says why: it is a run-total distribution over draws (section 4.5.7), not a per-frame
  scalar, and it reaches the operator through the JSON dump.
- GetOrCreatePipeline's 15-call tally sat ABOVE the list-topology primitive-restart refusal,
  so a declined draw added ten reads it never made - an OVER-count, which breaks the lower
  bound contract every other tally keeps. Moved to immediately before the payload build, and
  the enumeration reconciled with the constant: the excluded read is the sample-shading
  capability, short-circuited by m_sampleRateShadingFeatureEnabled.
- Six real staging paths were uncounted while the inventory claimed coverage. The inventory
  claim "DirectVulkan's own buffer staging ... has no second copy to count" was simply false.
  Now wired: MultiDraw.cpp's UploadScratch/UploadScratchRing (indirect commands, the compute
  tier's draw-info array, the rebased index stream - the class is passed in, so a new tier
  cannot forget it); Managers.cpp's pool-recycle reseed and the VBO-backed Float64 narrowing;
  VkBufferManager's eight host->device copies of buffer contents plus UploadTransient, the
  single chokepoint for Magma's per-draw vertex/index/indirect staging; VkTextureManager's
  packed staging slice, with the same box/rect SHAPE split Espryt already reported.
- New byte class stage-indirect-cmd, for draw PARAMETER bytes a backend synthesises and
  stages. Kept out of stage-index-client because these are the population that becomes MGPipe
  command-record payload (section 4.5.7), not resource bytes. A name addition, not a rename:
  no recorded baseline is invalidated.
- stage-ubo-named moved past the zero-copy direct-bind decision in ResolveUniformBufferPayload
  (a direct bind repacks nothing, so counting it there reported a copy that never happened),
  and Magma's default-uniform-block image now feeds stage-ubo-global the way Espryt's does,
  counted after the per-frame slice memo.
- The site inventory in PipeStats.cpp is rewritten to name every unwired path by file and
  function. An inventory that overstates coverage is worse than a missing counter, because
  the zero is then read as an answer.
- Evidence, lavapipe/llvmpipe, MOBILEGL_PIPE_STATS=1: the MultiDraw slice now prints
  "window=0 draws/f=n/a bytes[buf=1404550 ...]"; the indirect tiers
  (MOBILEGL_ESPRYT_MULTIDRAW_MODE=indirect|multiindirect) move icmd 0 -> 660; Magma's GuiBatch
  line moves from buf=0 tex=0 ubog=0 to buf=685.71 tex=41.14 ubog=157.71 with tex[emit=9
  box=9 rect=0 jobs=9]. Off-path A/B against the base tree with the env unset, 9 runs each of
  a 40-scenario draw slice, sorted totals in ms: Espryt base 389..794 (median 399) vs branch
  384..403 (median 394); Magma base 406..472 (median 410) vs branch 408..761 (median 414) -
  the always-compiled guard is below this harness's noise on both backends.
- 1410 unit tests green (15 PipeStatsTest). integration-gpu 860/860, 860/860, 859/860; the one
  failure is DirectVulkan.PointSizeDemotion...TheDemotionIsActuallyArmedWhenTheEnvironmentPins-
  ItOn, a member of the load-dependent *IsActuallyArmed* flake family already present in the
  untouched base tree, and it passes 8/8 standalone here. stdio gate and gen_pipe check green.
2026-09-05 20:16:49 -04:00
Swung0x48 90b7a689c5 [Fix] (Backend): resolve primitive restart per draw - never for a non-indexed one, and never on an index the type cannot hold 2026-08-27 03:18:09 -04:00
Swung0x48 0f2fcbc469 [Fix] (Backend): honour desktop GL_PRIMITIVE_RESTART with an arbitrary index instead of throwing through the C GL ABI 2026-08-27 02:11:18 -04:00
swung0x48 908172ba0f [Feat] (DirectGLES, Config, ShaderTranspiler): route gl_ViewportIndex on Espryt by replaying a draw per distinct viewport state 2026-08-21 22:08:25 -04:00
Swung0x48 dd2a62228f [Fix, Feat, Test] (MG_Util, MG_Backend, MG_Impl, MG_State): correct the log severity ordering and unwind the diagnostics it silenced 2026-08-13 02:02:49 -04:00
swung0x48 3ed9501be5 [Fix, Feat, Test] (MG_Backend/DirectGLES, MG_Test): the draw-parameter builtins never reached the draws that carry them, and glMultiDrawArraysIndirectCount had no backend at all 2026-08-12 04:18:08 -04:00
BZLZHH 0ec487c993 [Feat] (MG_Backend): port MobileGlues' multi-draw emulation to DirectGLES as a tier ladder
ES has neither glMultiDrawElements nor glMultiDrawElementsBaseVertex, so
both are emulated. DirectGLES had two ways of doing it - one
glMultiDrawElementsBaseVertexEXT where the driver has the extension
interaction, otherwise a per-draw loop. This adds the five MobileGlues
uses (gl/multidraw.cpp), so the ladder is now: one
glMultiDrawElementsBaseVertexEXT; one glMultiDrawElementsIndirectEXT
over a synthesized command buffer; one glDrawElementsIndirect per
command over that same buffer; the base-vertex replay; plain
glDrawElements over a CPU-rewritten index stream, for drivers with no
base-vertex draw at all; and a compute shader that flattens the whole
batch into one rebased index buffer drawn by a single glDrawElements.
They live in their own translation unit that owns the entry point
outright, preparation included - the compute tier has to dispatch BEFORE
PrepareForDraw, or it would have to unpick the program, storage-block
and index bindings the preparation just made, and a dispatch inside an
open transform-feedback span is not legal at all.

The auto ladder is ext -> basevertex -> multiindirect -> indirect ->
drawelements, which is NOT MobileGlues' order (it puts the indirect
tiers first). Measured on mc_sodium_multidraw, ns/op, median of three:
NVIDIA ES 3.2 basevertex 2500 vs multiindirect 5700 and indirect 5800;
Mesa llvmpipe ext 19300, basevertex 25200, multiindirect 27600,
drawelements 28700, indirect 31000. Ring-allocating the command staging
instead of respecifying per batch was tried first and moved the indirect
tiers by less than noise, so the cost is the indirect draw path itself,
not the upload; only a real multi-draw entry point beats replaying the
sub-draws. auto therefore resolves to basevertex on this box - byte for
byte the behaviour that shipped - and the new tiers are what a driver
with the ext interaction, or without base vertex at all, now gets.
compute is never chosen by auto (nor by MobileGlues'): it rewrites the
primitive stream rather than replaying it, and it measured slowest here.

Four places this deliberately does not follow MobileGlues, each a
correctness bug there. A rewritten stream is emitted as GL_UNSIGNED_INT
whatever came in, because GL adds baseVertex at full precision and
folding it into ushort indices wraps. The restart sentinel is carried
across a rebase unrebased, or an enabled primitive restart is lost. The
flattening tier declines strip/loop/fan modes, any sub-draw whose count
is not a whole number of primitives, and any batch at all while
primitive restart is enabled - a restart ends a primitive, so leftover
vertices would find a third vertex in the next sub-draw and become a
triangle GL never draws. And the indirect tiers decline client-memory
index arrays, which have no buffer to address.

gl_DrawID gets better rather than worse: the unrolled tiers now feed
each sub-draw its index (the spec's value, where the old loop left the
uniform untouched), and a program that actually reads it demotes the
batched tiers, which can only hold one value for the whole batch. The
per-batch cost is nil for the programs that do not read it.

Verified: the five DirectGLES retraces are byte-identical (md5) across
all six tiers on NVIDIA and on Mesa, each tier proven to have really
executed rather than silently demoted, via a per-tier announcement in
the log. Unit suite 421/421. The full retrace suite's five failures all
reproduce unchanged on a stashed tree, so none are new.
2026-08-07 08:15:54 -04:00