[Docs] (.github/workflows, CMakeLists.txt, MG_Backend, MG_Backend/DirectGLES, MG_Backend/DirectVulkan, MG_Backend/MGPipe, MG_Backend/Record, MG_Impl/Pipe, MG_IntegrationTest, MG_IntegrationTest/Harness, MG_IntegrationTest/Scenarios, MG_Pipe, MG_Remote, MG_Remote/Client, MG_Remote/Server, MG_Remote/Transport, MG_Remote/Wire, MG_State/GLState, MG_Test, MG_Test/Buffer, MG_Test/Purity, MG_Test/Util, MG_Test/Wire, MG_Util/Metrics, MobileGL, scripts, tools/trace_replay): replace stale line-number citations with sections and symbols

This commit is contained in:
2026-10-15 10:15:35 -04:00
parent c4fb9397cb
commit 506ab1541d
55 changed files with 119 additions and 116 deletions
+7 -7
View File
@@ -831,20 +831,20 @@ jobs:
# build, so an entry the filter misses is either never run under the P3a bits at all or runs
# only in the pull `integration` job, where a MOBILEGL_PIPE_PUSH value steers nothing
# (Config.h declares the field inside the push guard) and both arms are the same legacy path.
# A lane that cannot go red where it is installed is not a gate (ROADMAP.md:7).
# A lane that cannot go red where it is installed is not a gate (ARCHITECTURE.md §13.2).
# P4a ADDS THREE ALTERNATIVES, and each one is here because this is the only CI job that
# unpacks a push build:
# * `ObjectSubsystem` reaches the three DirectGLES.ObjectSubsystemControl. entries - the
# 0x1fff-vs-0x1ff A/B and the 0x9ff dependency refusal (G12). `ResourceSubsystem` does
# NOT match it: the two families are named apart on purpose, because they are different
# phases' switches and a filter that merged them would hide one behind the other.
# * `TextureParamsWithoutASamplerView` reaches G9's four cases, the scenario ROADMAP.md:20
# * `TextureParamsWithoutASamplerView` reaches G9's four cases, the scenario the phase's acceptance gate
# names by hand. It runs in the ambient lanes, which the label already selects - but this
# step is where those cases run against a PUSH library, and G9's whole claim is about the
# push path. All four cases are green on the contract commit - including the one D-E3
# expected to be red, for the reason the scenario's header records - so this row is green
# from the day it lands and goes red only if a reachability path stops syncing texture
# parameters at all, which is the coupling ARCHITECTURE.md:100 exists to remove.
# parameters at all, which is the coupling ARCHITECTURE.md §3.2 exists to remove.
# * `TextureUploadShape` is RECORDED, not gated (D-D4): it asserts that the two upload-shape
# counters could be read and that they agree, and prints the shape for MEASUREMENTS.md. It
# is in the filter so that the number is actually collected on every run - an unmeasured
@@ -1496,7 +1496,7 @@ jobs:
path: ci-artifacts/mobilegl-linux-runtime-split.tgz
if-no-files-found: error
# The split lane itself: the three-arm shape ARCHITECTURE.md:521 asks for verbatim, plus the
# The split lane itself: the three-arm shape ARCHITECTURE.md §13.2 asks for verbatim, plus the
# first real run of the five MG_Test/Wire suites, plus P5's two exit-gate negative controls.
integration-split:
runs-on: ubuntu-latest
@@ -2419,13 +2419,13 @@ jobs:
- name: Protocol revision pin check
run: python3 scripts/ci/protocol_revision_pin.py --self-test
# P0.5 interface-purity gate A (ARCHITECTURE.md:501): the two extracted headers' include closure,
# P0.5 interface-purity gate A (ARCHITECTURE.md §13.2): the two extracted headers' include closure,
# asserted on `-H` output because `nm --undefined-only` is blind to "included but not called" -
# a header whose types are never named leaves no symbol behind, and "included at all" is exactly
# the coupling P1 and P7 have to sever. Needs a preprocessor and three header submodules, no
# CMake configure and no glslang sources, so like pipe-gates it does not depend on build-linux.
# The script's own --self-test is always on: a negative control that stopped tripping fails the
# job, because a gate that cannot go red is not a gate (ROADMAP.md:7).
# job, because a gate that cannot go red is not a gate (ARCHITECTURE.md §13.2).
include-graph-check:
name: Include-closure purity gate
runs-on: ubuntu-latest
@@ -3683,7 +3683,7 @@ jobs:
echo "no fprintf(stderr/stdout / printf( / puts( / std::cout|cerr under MobileGL/MG_Backend or MobileGL/MG_State"
# A GATE as of P2, which is when MG_Pipe/DirtySurface.def exists to diff the scan against
# (ROADMAP.md:18 puts the first mapping round in P2). --check fails BOTH directions: a
# (the first mapping round was part of that phase's deliverable). --check fails BOTH directions: a
# mutator the scanner finds with no row in the def, and a row naming a mutator the scan no
# longer finds - so a deleted mutator cannot leave a stale row behind claiming coverage.
#
+2 -2
View File
@@ -21,7 +21,7 @@ option(MOBILEGL_IOS "Build MobileGL for iOS instead of macOS when
# That emptiness is one of the two byte-level equalities the plan's validation
# gates keep (section 10.3).
option(MOBILEGL_BUILD_DISAGGREGATED "Build the MG_Remote transport layer (two-process shape)" OFF)
# The CI / debugging shape (ARCHITECTURE.md:581): both roles in ONE process, talking over the
# The CI / debugging shape (ARCHITECTURE.md §16): both roles in ONE process, talking over the
# same SEG_CMD ring and the same G3 codec a spawned server would use. It IMPLIES
# MOBILEGL_BUILD_DISAGGREGATED (below) and additionally admits the role-isolation shims that
# only make sense when the two roles share an address space. It is a SUPERSET, never a
@@ -1204,7 +1204,7 @@ endif()
# P0 spike, which links no MobileGL library and exists only to prove the Android
# delivery chain - this one links the library and runs mobilegl_server_main.
#
# ARCHITECTURE.md:496 called for a ~30-line stub that dlopen's libMobileGL.so and
# ARCHITECTURE.md §15.2 called for a ~30-line stub that dlopen's libMobileGL.so and
# dlsym's the entry point, so one shared library serves both roles. On a desktop
# configure we link it directly instead: there is no APK packaging rule to satisfy
# and a direct link is what makes an undefined symbol a BUILD error rather than a
+2 -2
View File
@@ -503,7 +503,7 @@ namespace MobileGL::MG_Config {
//
// MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>.
//
// WHY `Transport` IS NOT A FeaturesTable MEMBER. ARCHITECTURE.md:580 requires that with
// WHY `Transport` IS NOT A FeaturesTable MEMBER. ARCHITECTURE.md §16 requires that with
// MOBILEGL_BUILD_DISAGGREGATED=OFF it be a `constexpr Monolith`, so that the single hook
// in MG_Backend/Init.cpp compiles away entirely rather than becoming a branch nobody can
// take. A FeaturesTable member is a runtime field in every build, which is the opposite
@@ -590,7 +590,7 @@ namespace MobileGL::MG_Config {
// transport: a build that cannot reach the MG_Remote code cannot honour one of them.
//
// P5 lands exactly the knobs P5's own packages read. A later phase's knob is added HERE,
// through the integrator, and not invented at its call site - ARCHITECTURE.md:615 holds
// through the integrator, and not invented at its call site - ARCHITECTURE.md appendix A holds
// the full planned inventory (PRESENT_CREDIT, POLL_ESCALATE, SHADOW_SHM,
// INLINE_PAYLOADS, TRACE, ATTACH, RESPAWN, IDLE_EXIT_S), and every one of those belongs
// to P6 or later.
+2 -2
View File
@@ -495,7 +495,7 @@ namespace MobileGL::MG_ConfigLoader {
#if MOBILEGL_BUILD_DISAGGREGATED
// MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>
// (ARCHITECTURE.md:583). Shaped after InitBackendType above: an exact-name table, then
// (ARCHITECTURE.md §16). Shaped after InitBackendType above: an exact-name table, then
// one fallback that names what it did instead. The two prefixed forms are the only
// reason this is not literally that function's ENTRY macro.
//
@@ -539,7 +539,7 @@ namespace MobileGL::MG_ConfigLoader {
// P6 `sm`/`cp`: spawn is IMPLEMENTED. It launches a server process on a
// rendezvous of its own and connects to it - the two processes are
// independent, so this is `Dial = Connect` with a launcher attached
// rather than the fork-coupled shape ARCHITECTURE.md:488 described.
// rather than the fork-coupled shape ARCHITECTURE.md §15.1 described.
if (lowered == "spawn") {
MG_Config::Transport = MG_Config::TransportMode::Spawn;
MG_Config::SplitTransportRequestedByConfig = true; // P7 F1, as above.
+1 -1
View File
@@ -51,7 +51,7 @@ namespace MobileGL {
MGLOG_I("MobileGL closing...");
}
#if MOBILEGL_BUILD_DISAGGREGATED
// P5: the split roles come down FIRST - ARCHITECTURE.md:537's order puts the whole
// P5: the split roles come down FIRST - ARCHITECTURE.md §14's order puts the whole
// of it before MobileGL::Destroy(), and this function IS MobileGL::Destroy. A no-op
// in a monolith RUN; absent from a monolith BUILD, because G1 admits no new pull
// symbol and no resized one (the first version called it unconditionally and moved
+2 -2
View File
@@ -21,7 +21,7 @@ namespace MobileGL::MG_Backend {
// not split. It exists ONLY in a split build: G1 admits no new symbol in the pull build,
// so MobileGL/Init.cpp's call sits under the same #if rather than calling a no-op.
//
// IT MUST RUN FIRST, BEFORE ANYTHING ELSE IN DestroyImpl. ARCHITECTURE.md:537's order is
// IT MUST RUN FIRST, BEFORE ANYTHING ELSE IN DestroyImpl. ARCHITECTURE.md §14's order is
// publish -> the server drains and acks -> stop the apply thread (Kill, then join) -> close
// the transport -> the client drains the compile pool -> MobileGL::Destroy() -> release the
// sync/query handles; DestroyImpl IS MobileGL::Destroy, so everything before that arrow has
@@ -34,7 +34,7 @@ namespace MobileGL::MG_Backend {
// owns the context, by ServerLoop::Stop, rather than on the app thread.
//
// The sync/query registries stay where they are, drained at MobileGL/Init.cpp:62 and :67
// BEFORE pActiveBackendObject.reset(). ARCHITECTURE.md:537 puts them after
// BEFORE pActiveBackendObject.reset(). ARCHITECTURE.md §14 originally put them after
// MobileGL::Destroy(); the two are only reconcilable if a split sync handle is
// client-minted and needs no backend call, which is P10's. CONTRACT-P5 4 flags this as a
// KNOWN OPEN ITEM and asks v1 to record which way it went: P5 keeps today's order.
@@ -13014,7 +13014,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// (MG_IntegrationTest/Harness/HeadlessGL.cpp). A child that dies on a signal is reported
// to the parent as "no usable GPU/display/ICD" and every scenario in the lane is
// SKIPPED - so the stop became a green lane that ran nothing, on exactly the two env
// vars the D14/D18 A/B is driven with (ROADMAP.md:7). The stop now belongs to the first
// vars the D14/D18 A/B is driven with (ARCHITECTURE.md §13.2). The stop now belongs to the first
// twin lookup, which happens in a scenario body where a crash IS a test failure.
static void DiagnoseEsprytSlotArmAtBringUp() {
DiagnoseEsprytSlotArm();
+3 -3
View File
@@ -7025,7 +7025,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// P4a (D-D5), the dirty-ownership inversion, applied at the two places the upload loops
// below actually ask: "does this (uploadTarget, level) owe an upload" and "it has been
// uploaded". ARCHITECTURE.md:253 puts the rect model and the emission cursor on the
// uploaded". ARCHITECTURE.md §6 puts the rect model and the emission cursor on the
// CLIENT, which clears its own flags AT EMISSION - so on the handle arm the frontend's
// IsStorageDirty is already false for every level the applier accepted, and asking it
// would upload nothing at all. The applier's pending set is what these two read instead;
@@ -8127,7 +8127,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// name the client's texture object.)
const Bool layersAsRows =
MGB_TEXTURE_TARGET(stateTextureObject) == TextureTarget::Texture1DArray;
// P4a (D-D6, and ARCHITECTURE.md:321's ONE item moved out of the
// P4a (D-D6, and ARCHITECTURE.md §9.1's ONE item moved out of the
// Espryt do-not-touch list): the DECISION below is unchanged and
// stays on the server - it is the side that pays the GPU cost, and
// the union-box-versus-N-rects choice is worth 16x the bytes on one
@@ -13908,7 +13908,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// PULL build each expands to the pre-P4a expression at its original site, so that
// build's tokens and its symbol sizes are unchanged (D-P).
//
// ARCHITECTURE.md:130 keeps the renderbuffer an INDEPENDENT frontend class while giving
// ARCHITECTURE.md §4.1 keeps the renderbuffer an INDEPENDENT frontend class while giving
// it the same discriminated MGPResourceDesc a texture gets, and this is where that pays:
// the same four fields, read out of the same record type, with Desc.Target telling the
// applier which of the three per-kind tables the record lives in.
+5 -5
View File
@@ -487,7 +487,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// runs inside eglMakeCurrent and the integration harness pre-flights exactly that sequence
// in a FORKED CHILD; a child that dies on a signal is reported as "no usable GPU" and every
// scenario in the lane is SKIPPED - the lane goes green having run nothing, on the very
// pair of env vars the A/B is driven with, which is what ROADMAP.md:7 forbids. So a stop
// pair of env vars the A/B is driven with, which is what ARCHITECTURE.md §13.2 forbids. So a stop
// has to land in a test body, i.e. at the first lookup. That is what the inline latches
// below give: a guard-variable load and a perfectly-predicted branch per consult, and the
// arm dispatch folds into the caller (SlotTables.h's EsprytSlotTablesEnabled argument
@@ -1988,7 +1988,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// ---- P4a's handle arm (D-B3). Three server-owned serials that REPLACE, on their
// own arm, the six frontend-version memos above; the legacy members stay beside
// them under MOBILEGL_PIPE_LEGACY_MEMOS because ARCHITECTURE.md:369 keeps the
// them under MOBILEGL_PIPE_LEGACY_MEMOS because ARCHITECTURE.md §9.6 keeps the
// pre-handle arm compiled through P3a/P4a, and because clearing the family's bit
// has to run the pre-handle arm rather than a half-migrated one.
//
@@ -3219,7 +3219,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint16 m_syncedSamplerVersion = 0;
// P4a (D-B3): the SamplerCso record's Serial at the last completed sync. It replaces
// m_syncedSamplerVersion, which stays beside it because the pre-handle arm compiles
// under MOBILEGL_PIPE_LEGACY_MEMOS through P3a/P4a (ARCHITECTURE.md:369).
// under MOBILEGL_PIPE_LEGACY_MEMOS through P3a/P4a (ARCHITECTURE.md §9.6).
//
// The two are not interchangeable and that is the point: the frontend version is per
// OBJECT, while the serial is per CONTENT-ADDRESSED CSO, and two frontend samplers
@@ -3274,14 +3274,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
// has no frontend object at all. MobileGL has no sampler-view class: GL binds a texture
// to a unit and the sampler uniform's type, the mipmap-completeness predicates and
// IsUndefinedDefaultTexture decide what the shader sees. Gallium's one-view-per-slot IS
// that resolved form, the resolution moves to the CLIENT (ARCHITECTURE.md:206), and
// that resolved form, the resolution moves to the CLIENT (ARCHITECTURE.md §5.5), and
// create_sampler_view carries the restrictions the resolution had to read.
//
// So this twin owns NO DRIVER ID. There is nothing in ES to create for a view; the id
// the unit binds is the texture's, and it lives on BackendTextureObject. What this twin
// is, is the server's MEMO of one resolved view: the record it was built from, keyed on
// that record's serial, plus the two BACKEND-SPECIFIC POST-PROCESSINGS
// ARCHITECTURE.md:206 keeps on the server and which act on the already-resolved set.
// ARCHITECTURE.md §5.5 keeps on the server and which act on the already-resolved set.
// Espryt's is the raw-depth-fetch sampler substitution; Magma's feedback-loop detection
// is its own and is not here.
//
+2 -2
View File
@@ -40,7 +40,7 @@
// MG_Remote/Server/PipeObjectTables) be an array rather than an object graph.
//
// Death is ANNOUNCED, and that is what lets this table have no garbage collector - the
// deliverable ROADMAP.md:18 spells "GC" in and the one D13 makes a precondition of the switch-
// one the slot-table plan lists for deletion as "GC" and the one D13 makes a precondition of the switch-
// over. All six re-keyed object classes raise MG_State::GLState::NotifyStateObjectDestroyed()
// from their destructor carrying {kind, lifetimeId, handle}; the backend consumes it in
// Managers.cpp and releases the twin BY THAT HANDLE in every holder of the kind
@@ -94,7 +94,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// sequence in a FORKED CHILD (MG_IntegrationTest/Harness/HeadlessGL.cpp): a child that dies
// on a signal is reported as "no usable GPU/display/ICD" and every scenario in the lane is
// SKIPPED - i.e. the lane goes green having run nothing, on the very pair of env vars the
// D14/D18 A/B is driven with, which is what ROADMAP.md:7 forbids. So bring-up only
// D14/D18 A/B is driven with, which is what ARCHITECTURE.md §13.2 forbids. So bring-up only
// DIAGNOSES; the stop is raised by ResolveEsprytSlotTablesArm() at the first twin lookup,
// which happens in the test body where the harness reports it as a failure.
//
@@ -1539,7 +1539,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// (MG_Util/Debug/Log.h) is an UNCONDITIONAL std::atomic_flag::test_and_set - a locked
// xchg, executed on every evaluation, not "one static bool test" as an earlier round of
// this comment claimed - and this site is on the per-draw pipeline path in the very
// configuration that reaches it (no tracker: every draw). ROADMAP.md:7 forbids leaving
// configuration that reaches it (no tracker: every draw). guide/discipline.md forbids leaving
// instrumentation on a hot path, so the once-ness is one non-atomic, always-predicted
// load of a member that is false exactly once. Single-threaded like the rest of the
// renderer, and per renderer rather than per process, which is also the right scope: a
+2 -2
View File
@@ -149,7 +149,7 @@ namespace MobileGL::MG_Backend {
// question could never notice the swap - only the pointer can.
const MG_Pipe::MGPipeResourceOps* g_resourceOpsAtStep2 = nullptr;
// The single hook (ARCHITECTURE.md:29). Returns false when the split could not be
// The single hook (ARCHITECTURE.md §1.3). Returns false when the split could not be
// brought up, and the caller then REFUSES TO CONTINUE rather than falling back to the
// switch below - a fallback here is "the split lane ran monolith and went green".
// Steps 1 and 2 of the split bring-up: the server role's private backend
@@ -257,7 +257,7 @@ namespace MobileGL::MG_Backend {
return true;
}
// The single hook (ARCHITECTURE.md:29) for the INPROC shape: both roles in
// The single hook (ARCHITECTURE.md §1.3) for the INPROC shape: both roles in
// this process. The spawn shape runs InitServerRoleCommon in the child and
// the client half here.
Bool InitSplitRoles() {
+3 -2
View File
@@ -427,8 +427,9 @@ namespace MobileGL::MG_Pipe {
// Only [0] (pack) has a carrier - set_pixel_pack_state, which the applier writes
// (PipeApply.cpp:1373) - so the field is APPLIER-DERIVED and the UNPACK half is FATAL:
// every gPipeInputs->GetPixelStoreParameters site in the tree passes false
// (DirectGLES.cpp:7924, :9399, :10893, :11272, Utils.cpp:2302,
// VulkanRenderer.cpp:10980), and PipeFill.cpp's EmitPixelPackState says the same from
// (DirectGLES.cpp's PackStateFromContext, StoreReadbackRowsToClient and ReadPixels, Utils.cpp's
// ReadbackImpl::StoreClientRows, RecordVerbSink::ReadBoundFramebufferTight and
// VulkanRenderer::ReadDepthStencilImageToClient), and PipeFill.cpp's EmitPixelPackState says the same from
// the other side: "nothing on the far side of the boundary reads unpack state".
PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const {
MGP_INPUT_CHECK_ARG(MGPipeInputField::GetPixelStoreParameters, isUnpack ? 1u : 0u);
@@ -124,7 +124,7 @@ namespace MobileGL::MG_Record {
// image's own dimensions. Texture1DArray shrinks x only; Texture2DArray and
// TextureCubeMapArray shrink x and y; every other target shrinks all three. This is the
// mip chain's definition (MG_State's IsMipmapCompleteForFilter applies the same split,
// TextureObject.cpp:705-734), so two honest ends compute the same number.
// via ComputeMipmapCompleteForFilter in TextureObject.cpp), so two honest ends compute the same number.
struct StagedTextureDeviceLimits {
Int MaxTextureSize = 16384;
Int MaxRectangleTextureSize = 16384;
+4 -4
View File
@@ -6,14 +6,14 @@
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
// THE CLIENT-SIDE CONSERVATIVE GPU-WRITE SET (ARCHITECTURE.md:575 names this component;
// THE CLIENT-SIDE CONSERVATIVE GPU-WRITE SET (ARCHITECTURE.md §16 names this component;
// CONTRACT-P5.md section 3, table 2's first set). Owner: package b1.
//
// WHY IT HAS TO MOVE SIDES. `BufferObject::SyncGpuWrites` (BufferObject.cpp:369) runs
// synchronously, on the application's thread, the moment the application calls glMapBuffer or
// glGetBufferSubData. It has to answer "did the GPU write this buffer since I last read it?"
// - and today all six producers of that answer are BACKEND-side (DirectGLES.cpp:570, :618,
// :2603, UniformManager.cpp:1075, :1231, VulkanRenderer.cpp:11618), i.e. on the server's side
// :2603, UniformManager.cpp:1075, :1231, VulkanRenderer::BeginXfbCaptureForDraw), i.e. on the server's side
// of a split. Asking the server is a round trip the design forbids in steady state, so the
// client must build the set itself, from state it already owns: the SSBO and atomic-counter
// binding points, the image units whose Access is not GL_READ_ONLY, and the transform-feedback
@@ -32,7 +32,7 @@
// reads ResourceTracker.h:577-581 alone will think it owns that already. It does not.
//
// THE TWO NEW PRODUCERS. Rows 4 and 5 have no backend twin: they are behaviour P5 ADDS
// (ARCHITECTURE.md:508), and both are strictly better than what monolith does.
// (ARCHITECTURE.md §13.1), and both are strictly better than what monolith does.
// * glReadPixels into a pack PBO becomes fire-and-forget plus a client-side mark. Monolith
// maps the PBO and copies it into the shadow inside the call (DirectGLES.cpp:10983-10993),
// which is an unconditional stall on every glReadPixels whether or not anyone reads the
@@ -87,7 +87,7 @@ namespace MobileGL::MG_Record {
// make the next map wait on - and then re-read - a dispatch that could not have
// changed a byte of it.
WritableImageBufferTexture,
// VulkanRenderer.cpp:11618 (BeginXfbCaptureForDraw): the capture targets, because
// VulkanRenderer.cpp (BeginXfbCaptureForDraw): the capture targets, because
// "the capture is a GPU write like any shader's".
TransformFeedbackCapture,
// P5, new: glReadPixels into a bound GL_PIXEL_PACK_BUFFER.
+1 -1
View File
@@ -2015,7 +2015,7 @@ else()
"PersistentCoherentMapScenario's membership assertion SKIPS")
endif()
# ARCHITECTURE.md:543 - every new ctest ENVIRONMENT and add_trace_replay_test's SPLIT branch
# ARCHITECTURE.md §15.1 - every new ctest ENVIRONMENT and add_trace_replay_test's SPLIT branch
# carries MOBILEGL_IPC_SERVER_PATH, because the dladdr fallback cannot find the server from a
# binary that links MobileGL_s statically. P5 is inproc-only and nothing reads the value yet; it
# is carried now so that an unparsed variable and a parsed-and-ignored one stop being
@@ -11,7 +11,7 @@
// no-op, hidden by the pre-handle program pass binding the same values) and F-2 / SD-4 (the
// shader-image window does not follow a program switch, hidden by the server's window/high-water
// union taking the pre-handle bind for the units outside it). Both are correct pictures over a
// permanent silent fallback, which is precisely the class ROADMAP.md:20 says a gate has to be
// permanent silent fallback, which is precisely the class ARCHITECTURE.md §13.2 says a gate has to be
// able to make red - and the only place the difference exists is inside.
//
// A SEPARATE TRANSLATION UNIT for PipeApplyPeek.h's reason, verbatim: this file includes
@@ -1760,7 +1760,7 @@ void main() { oColor = texture(uTex, vec2(4.0, 4.0)); }
//
// A sampler view is the RESOLVED (texture, sampler) pair - what the unit actually
// samples - and P4a addresses it by IDENTITY per texture object (D-F2, the deviation
// from ARCHITECTURE.md:63's content-addressed 4096-entry cache, which is P7's). So the
// from ARCHITECTURE.md §2.3's content-addressed 4096-entry cache, which is P7's). So the
// view's key names the texture; the case recycles the TEXTURE while an explicitly bound
// SAMPLER OBJECT stays alive and unchanged across the window, so what a stale view
// would inherit is the dead texture through a live sampler - which the texture case
@@ -30,7 +30,7 @@
// changes what the three above assert:
//
// * AnAdoptionCostsExactlyOneMapPersistentRoundtrip counts the acquisition.
// ARCHITECTURE.md:474 prices the adopted store at one round trip per STORAGE
// ARCHITECTURE.md §12 prices the adopted store at one round trip per STORAGE
// DEFINITION; `map-persistent-roundtrips` counts every map_persistent
// emission, mint or decline (D-B2), so one definition plus a frame of draws
// must publish exactly one. It reads the library's summary line, so it needs
@@ -602,7 +602,7 @@ void main() { word = 0xC0FFEEu; }
ASSERT_GE(roundtrips, 0) << "the summary line carries no mpr= field: " << window.line;
EXPECT_EQ(roundtrips, 1)
<< "one storage definition of an adopted arena is one map_persistent emission "
"(ARCHITECTURE.md:474, D-B2: mint OR decline, both need an answer from the resource "
"(ARCHITECTURE.md §12, D-B2: mint OR decline, both need an answer from the resource "
"owner). This window defined the arena once and drew from it "
<< kDrawsInTheWindow << " times, so 1 is the whole cost; " << kDrawsInTheWindow
<< " would mean the acquisition moved onto the draw path - the ~167 ms/arena hiccup this "
@@ -573,7 +573,7 @@ void main() { oColor = texture(uTex, vUv); }
// (texture resources). Every MGPBoundView::Texture and every MGPImageView::Res names a
// Texture handle, and only bit 10 populates the texture slot table, so with bit 11 alone
// every lookup would miss and the unit walk would `continue` without unbinding - a
// half-run subsystem, which ROADMAP.md:7 forbids as loudly as a dead switch. The bring-up
// half-run subsystem, which ARCHITECTURE.md §13.2 forbids as loudly as a dead switch. The bring-up
// logs ONE error naming both bits, refuses bit 11, and runs the legacy sampler arm.
//
// TWO ASSERTIONS, and the second is the one that stops this from being a log-scraping test:
@@ -54,7 +54,7 @@
// only ever sees whichever arm its driver and transport happen to give it.
//
// `mpr` (map-persistent-roundtrips) is counted per ACQUISITION ATTEMPT, mint or decline
// (ARCHITECTURE.md:492), so it is the SAME NUMBER on both arms and in both transports: that is
// (ARCHITECTURE.md §12), so it is the SAME NUMBER on both arms and in both transports: that is
// what makes exit gate E3(c)'s "mpr equal to the monolith arm's" checkable by one process. Both
// lanes assert the same constant against the same workload, so the equality holds by
// construction and each lane can fail on its own.
@@ -519,9 +519,8 @@ void main() { oColor = vec4(vColor, 1.0); }
ASSERT_GE(roundtrips, 0) << "the summary line carries no mpr= field: " << window.line;
EXPECT_EQ(roundtrips, kExpectedRoundtrips)
<< "one PERSISTENT|WRITE|COHERENT map of one freshly defined store is ONE acquisition "
"attempt, mint or decline (ARCHITECTURE.md:492). This window mapped once and drew "
<< kDrawsInTheWindow << " times, so " << kExpectedRoundtrips << " is the whole cost; "
<< kDrawsInTheWindow
"attempt, mint or decline (ARCHITECTURE.md §12). This window mapped once and drew "
<< kDrawsInTheWindow << " times, so " << kExpectedRoundtrips << " is the whole cost; " << kDrawsInTheWindow
<< " would mean the acquisition moved onto the draw path. The number is counted as "
"ATTEMPTS precisely so that it is the SAME on the adopted and the emulated arm and "
"under both transports - which is what makes exit gate E3(c)'s 'mpr equal to the "
@@ -102,7 +102,7 @@ namespace MGITest {
// as a hard SIGSEGV in the vertex fetch; that detour is what ID-9 supersedes.
//
// The COUNT is unaffected by the change: two storage definitions either way, which is
// what ARCHITECTURE.md:474 prices.
// what ARCHITECTURE.md §12 prices.
constexpr int kDefinitionsInTheWindow = 2;
constexpr int kDrawsPerDefinition = 3;
constexpr int kInset = 2;
@@ -20,7 +20,7 @@
// The assertion is deliberately on the WHOLE grown range, so a partial write names the byte the
// stale extent stopped at.
//
// P3a ADDS THE COST OF THAT REGROWTH (gate G10). ARCHITECTURE.md:474 prices a persistently mapped
// P3a ADDS THE COST OF THAT REGROWTH (gate G10). ARCHITECTURE.md §12 prices a persistently mapped
// store at "one round trip per STORAGE DEFINITION, not one per store" - and, emphatically, not one
// per draw. `map-persistent-roundtrips` (`mpr=` in the summary line) counts every map_persistent
// EMISSION, mint or decline (D-B2), so the claim is directly countable: N definitions of an
@@ -297,9 +297,9 @@ void main() {
"map-persistent-roundtrips counter to read: " << window.line;
EXPECT_EQ(roundtrips, static_cast<long long>(kAdoptedDefinitions))
<< "an adopted store costs ONE map_persistent per STORAGE DEFINITION "
"(ARCHITECTURE.md:474). This window defined the store " << kAdoptedDefinitions
<< " times and dispatched " << kDispatchesPerDefinition << " times against each of them, so "
<< kAdoptedDefinitions << " is the whole cost. "
"(ARCHITECTURE.md §12). This window defined the store "
<< kAdoptedDefinitions << " times and dispatched " << kDispatchesPerDefinition
<< " times against each of them, so " << kAdoptedDefinitions << " is the whole cost. "
<< (kAdoptedDefinitions * kDispatchesPerDefinition)
<< " would mean an acquisition per DRAW - the regression this counter exists to catch - and 0 "
"would mean nothing emitted map_persistent at all. It reported: "
@@ -7,9 +7,9 @@
// End of Source File Header
//
// Scenario - A TEXTURE'S PARAMETERS TAKE EFFECT EVEN WHEN IT HAS NO SAMPLER VIEW (gate G9), the
// one scenario ROADMAP.md:20 names by hand and requires to be RED before P4a lands.
// one scenario the acceptance gate names by hand and requires to be RED before P4a lands.
//
// THE DESIGN STATEMENT IT TESTS, ARCHITECTURE.md:100 (D10), verbatim: "SetTextureParams 按资源寻址、
// THE DESIGN STATEMENT IT TESTS, ARCHITECTURE.md §3.2 (D10), verbatim: "SetTextureParams 按资源寻址、
// 与 sampler view 分开(D10):只作 FBO attachment / image 单元 / glCopyImageSubData 端点的纹理没有
// sampler view,但 Espryt 对 attachment 也同步纹理参数,且 RequireImageBindableStorage 需要在前端参数
// 版本不动时强制重同步." A texture that is only an attachment, only an image-unit binding or only a
@@ -48,7 +48,7 @@
// in particular they would go RED if any of the four reachability paths were ever made to
// depend on the texture having a sampler VIEW - which is exactly the coupling P4a's
// resource-addressed set_texture_params removes and the thing a later phase could reintroduce;
// * the "落地前必须红" artefact ROADMAP.md:20 asks for is NOT produced by the public-GL half
// * the "must be red before landing" artefact the acceptance gate asks for is NOT produced by the public-GL half
// of this file, and no public-GL integration scenario on a monolith tree can produce it.
// Producing it needs an observation of the DRIVER's texture object taken while the texture is
// still read-attachment-only. ID-19 rules that G9 is therefore a WHITE-BOX assertion, and this
@@ -109,7 +109,7 @@
// (DirectGLES.cpp:1944), so a texture that is exclusively a READ attachment gets its STORAGE synced
// and its PARAMETERS never. P4a closes that gap deliberately (D-E3): the record is addressed by
// resource, and Espryt's SyncAttachmentObject applies parameters for ANY attachment, draw or read.
// It is a behaviour change and it is the deliverable, not a drive-by dev fix (ROADMAP.md:98).
// It is a behaviour change and it is the deliverable, not a drive-by dev fix (guide/discipline.md).
//
// HOW EACH CASE OBSERVES "REACHED THE DRIVER", and why the observation is always a LATER SAMPLE.
// A texture parameter is by definition a sampling parameter: nothing about an attachment, an image
@@ -524,7 +524,7 @@ void main() {
}
// ------------------------------------------------------------------------------------
// 2. READ ATTACHMENT ONLY - THE MANDATORY RED (ROADMAP.md:20, D-E3, G9).
// 2. READ ATTACHMENT ONLY - THE MANDATORY RED (D-E3, G9).
//
// The parameter is GL_DEPTH_STENCIL_TEXTURE_MODE and the texture is a packed
// depth/stencil one, because that is the parameter whose absence is not a mis-filtered
@@ -652,7 +652,7 @@ void main() {
"unsynced parameter (see this file's header: the unit sync list calls "
"SyncTextureParamsToBackend whenever the params version moved) - a red here means "
"something stronger than the D-E3 gap: a reachability path that does not sync "
"parameters AT ALL, i.e. the sampler-view coupling ARCHITECTURE.md:100 (D10) "
"parameters AT ALL, i.e. the sampler-view coupling ARCHITECTURE.md §3.2 (D10) "
"exists to remove. Read the case's own stdout line for the GL error the sample "
"raised before assuming an aspect-mode bug.";
@@ -11,7 +11,7 @@
// WHAT IT IS FOR. SSIM is completely blind to the difference between "one union box" and "N
// separate rects", and that difference is the Mali upload cliff: Mali prices an upload by the
// number of JOBS, and ~100 one-rect sprite jobs against one union box measured +6 ms/frame
// (ARCHITECTURE.md:249-251). Every gate in the phase can be green while the emission shape has
// (ARCHITECTURE.md §6). Every gate in the phase can be green while the emission shape has
// silently inverted, so the shape needs a number - and there are TWO numbers, deliberately:
//
// tex[emit= box= rect= jobs=] the SERVER's count, Espryt's own, which has existed since P2
@@ -633,10 +633,11 @@ void main() { oColor = texture(uTex, vUv); }
EXPECT_EQ(rect, kGold.RectEmissions)
<< "the BOX/RECT split moved: " << rect << " rect-list emissions against a gold of "
<< kGold.RectEmissions
<< ". This is the direction that costs ~+6 ms/frame on Mali (ARCHITECTURE.md:249-"
"251): the driver is handed N upload jobs where it used to be handed one, and no "
<< ". This is the direction that costs ~+6 ms/frame on Mali (ARCHITECTURE.md §6): "
"the driver is handed N upload jobs where it used to be handed one, and no "
"SSIM case can see it. If this is intended, re-measure the row and say so in "
"docs/Disaggregated/MEASUREMENTS.md. " << shapeWindow.line;
"docs/Disaggregated/MEASUREMENTS.md. "
<< shapeWindow.line;
EXPECT_EQ(jobs, kGold.Jobs)
<< "the JOB count moved: " << jobs << " against a gold of " << kGold.Jobs
<< ". Jobs are what Mali prices the upload by. " << shapeWindow.line;
+3 -2
View File
@@ -71,8 +71,9 @@
// (pack) has a carrier, and the applier writes it.
//
// AND THE UNPACK HALF HAS NO BACKEND READER AT ALL. Every gPipeInputs->GetPixelStoreParameters
// call site in the tree passes `false`: DirectGLES.cpp:7924, :9399, :10893, :11272,
// Utils.cpp:2302 and VulkanRenderer.cpp:10980 - six, not the five the scout named, and the
// call site in the tree passes `false`: DirectGLES.cpp's PackStateFromContext, StoreReadbackRowsToClient
// and ReadPixels, Utils.cpp's StoreClientRows, VulkanRenderer::ReadDepthStencilImageToClient() and
// RecordVerbSink::ReadBoundFramebufferTight() - six, not the five the scout named, and the
// scout did not open them. PipeFill.cpp's own EmitPixelPackState says the same thing from
// the other side: "PACK only, deliberately: nothing on the far side of the boundary reads
// unpack state". So the honest class for the unpack half is FATAL, not BARRIER_PULLED: a
+1 -1
View File
@@ -147,7 +147,7 @@
X(DeleteTransformFeedback, kXfbSpan) \
X(GetGpuTimestampNs, kQuery)
// X(Class) - the nine verb classes (ARCHITECTURE.md:153 names eight; kProgramOp is split out because
// X(Class) - the nine verb classes (ARCHITECTURE.md §5.1 first named eight; kProgramOp is split out because
// ShaderStorageBlockBinding is the one non-draw verb that syncs Espryt's render state and textures).
#define MGP_FILL_CLASS_LIST(X) \
X(kDraw) X(kDispatch) X(kClear) X(kBlitOrCopy) X(kTextureOp) X(kReadback) X(kXfbSpan) X(kProgramOp) X(kQuery)
+1 -1
View File
@@ -54,7 +54,7 @@ namespace MobileGL::MG_Remote {
// bits 48..63 reserved.
//
// protocol.fbs:94's `tableSlotMask: ulong` is DELETED rather than renamed (R-8 offered
// either). Two reasons, and the second is decisive: ARCHITECTURE.md:114 says CallMask
// either). Two reasons, and the second is decisive: ARCHITECTURE.md §3.3 says CallMask
// REPLACES "is this table slot null" as the capability probe, so a field whose comment is
// "which GLFunctionsTable slots the peer registered" re-introduces exactly what it
// replaced; and GLFunctionsTable has SIXTY-NINE function-pointer slots
+1 -1
View File
@@ -417,7 +417,7 @@ namespace MobileGL::MG_Remote::Client {
// AND THE NO-OP IS THE ONE THIS FRONTEND ALREADY GIVES for a fence it cannot wait on:
// GL_Sync.cpp:103-106 answers GL_ALREADY_SIGNALED for a sync with no backend handle,
// PipeApplier.cpp:175-177 answers GL_ALREADY_SIGNALED for a fence with no native
// object (a fence that provably did no work), and DirectGLES.cpp:16489 does the same
// object (a fence that provably did no work), and ClientWaitSync() in DirectGLES.cpp does the same
// for an absent sync. A lost device is that same class of fact.
//
// WHAT ABORTING HERE COSTS, MEASURED: after a clean device loss Minecraft 26.2's next
+1 -1
View File
@@ -48,7 +48,7 @@
// (GL_Query.cpp:481, :785), BeginXfbPrimitivesQuery (:534), SubDataResident. With no null slot
// in this table every one of them answers "supported" and the fallback behind it silently
// disappears. A null check on a slot may not survive into the client: it becomes a caps-mirror
// read, which is what ARCHITECTURE.md:114 means by "CallMask replaces 'is this table slot null'".
// read, which is what ARCHITECTURE.md §3.3 means by "CallMask replaces 'is this table slot null'".
//
// NOTE the asymmetry this table does not resolve, AND WHERE IT IS RESOLVED (R-17): the
// resource, CSO, framebuffer, texture, sampler and program families do NOT come through here.
+1 -1
View File
@@ -13,7 +13,7 @@
// slot in the client's emit table - so in that table every one of those probes would answer
// "supported", and whatever fallback sits behind it would silently disappear. That is not a
// theoretical risk: it is how a split lane produces a plausible picture for the wrong reason.
// ARCHITECTURE.md:114 already said what replaces the probe - "CallMask replaces 'is this table
// ARCHITECTURE.md §3.3 already said what replaces the probe - "CallMask replaces 'is this table
// slot null' as the implicit capability probe" - and this header is the concrete list.
//
// TWO SPELLINGS, AND WHICH ONE A SITE TAKES IS DECIDED BY THE SLOT'S CLASS, NOT BY TASTE:
+1 -1
View File
@@ -274,7 +274,7 @@ namespace MobileGL::MG_Remote::Server {
if (table->Present == nullptr) return false;
// Present is the ONLY frame-boundary drain the backend has (DirectGLES.cpp:12424-12470:
// the fence poll, the four ring OnPresent hooks, TrimBufferPool, PipeStats::OnPresent),
// which is why ARCHITECTURE.md:531 wants present <-> eglSwapBuffers to stay 1:1.
// which is why ARCHITECTURE.md §14 wants present <-> eglSwapBuffers to stay 1:1.
//
// m-1: THAT 1:1 IS A CONVENTION c1 UPHOLDS, NOT A STRUCTURAL GUARANTEE, and the earlier
// claim that it was structural is wrong. This Present() is reached ONLY from a present
+1 -1
View File
@@ -10,7 +10,7 @@
//
// Deliberately the smallest thing that can be one: everything it could do
// belongs to mobilegl_server_main, which lives IN THE LIBRARY so that one
// shared library serves both roles (ARCHITECTURE.md:496). Keeping this file
// shared library serves both roles (ARCHITECTURE.md §15.2). Keeping this file
// empty of logic is what stops the server growing a second, divergent copy of
// bring-up that the client half never executes.
+1 -1
View File
@@ -24,7 +24,7 @@
// gone.
//
// ANTI-RECURSION IS STILL TWO INDEPENDENT CATCHES, and CONTRACT-P6 §3.1 is why
// neither is ARCHITECTURE.md:488's. That rule says the child hard-sets
// neither is the original ARCHITECTURE.md §15.1 rule. That rule says the child hard-sets
// Transport to Monolith; a6 measured that 226 live lines test
// `Transport != Monolith` to select the SERVER arm, 148 of them in MG_Backend,
// so obeying it flips the whole backend to frontend glue in the one process
+1 -1
View File
@@ -12,7 +12,7 @@
// THE ID IS THE RECORD SEQUENCE NUMBER (P5 R-3). There is no second id space and
// no allocator: the ten kReplySlot calls carry no MGPReplySlot in their payloads
// (that is why the id has to be DERIVED rather than carried), the wire has no
// per-record seq field (ARCHITECTURE.md:124), so the record's ordinal IS its
// per-record seq field (ARCHITECTURE.md §4), so the record's ordinal IS its
// reply-slot id. The slot is addressed `seq % slotCount` and the server STAMPS
// THE SEQ BACK INTO THE SLOT HEADER, which is what makes a wrong-slot read
// detectable rather than merely plausible. Seq is 1-based; 0 means "no record".
+1 -1
View File
@@ -9,7 +9,7 @@
// The ring-owning half of a session: the four segments, the two ring endpoints,
// and the five watermarks. Owner: package s1.
//
// This is the object the P5 gate is really about. ROADMAP.md:21 asks that
// This is the object the P5 gate is really about. ARCHITECTURE.md §10.1 asks that
// `inproc` run THE SAME G3 codec as `spawn`, and InProcessTransport cannot
// deliver that no matter how it is edited: it is two deque<vector<uint8_t>> plus
// two condvar doorbells (InProcessTransport.cpp:38-97), it owns THE BELLS BUT
+1 -1
View File
@@ -2387,7 +2387,7 @@ namespace MobileGL::MG_Remote::Wire {
return m_verbs != nullptr && m_verbs->OnClear(*static_cast<const MGPClear*>(payload));
case MGPWireOp::ReadPixels:
// P5 BLOCKS on read_pixels (ROADMAP.md:21) and the pixels come back in the reply
// P5 BLOCKS on read_pixels (ARCHITECTURE.md §13.1) and the pixels come back in the reply
// slot, which is why ReplyPool::SlotBytes() is sized from the scenario's largest
// read rather than guessed. MGPReadbackInfo has DstOffset/DstSize and no Seg on
// purpose: in P5 the destination is ALWAYS SEG_REPLY (contract table 1 row 23).
+1 -1
View File
@@ -33,7 +33,7 @@
// 0xDD, so an implementation that kept a pointer past apply reads 0xDD next frame.
//
// SEQ. The record ordinal IS the sequence number and IS the reply-slot id (R-3): there is no
// per-record seq field on the wire (ARCHITECTURE.md:124) and no second id space. Seq is
// per-record seq field on the wire (ARCHITECTURE.md §4) and no second id space. Seq is
// 1-based so that 0 can mean "nothing encoded". A kRecPad wrap filler DOES NOT ADVANCE SEQ -
// both sides must skip it before counting, or every ring wrap offsets the two sides'
// numbering permanently and nothing checksums it (R-9, Ring.h's header).
@@ -14,7 +14,7 @@
#include <mutex>
#include <MG_Pipe/PipeMutation.h>
#if MOBILEGL_BUILD_DISAGGREGATED
// MG_State reaching into MG_Remote/Client is the layering ARCHITECTURE.md:575 names - the CLIENT
// MG_State reaching into MG_Remote/Client is the layering ARCHITECTURE.md §16 names - the CLIENT
// role IS MG_State plus MG_Impl - and the edge exists only in a build that has the transport at all.
#include <MG_Remote/Client/GpuWritePending.h>
#endif
@@ -577,7 +577,7 @@ namespace MobileGL::MG_State::GLState {
void BufferObject::SyncGpuWrites() {
if (!m_gpuWritePending) return;
#if MOBILEGL_BUILD_DISAGGREGATED
// THE THIRD STATE (CONTRACT-P5.md section 3, ARCHITECTURE.md:509). This function has
// THE THIRD STATE (CONTRACT-P5.md section 3, ARCHITECTURE.md §13.1). This function has
// only ever been able to say "pending" or "not pending", and clearing first is safe
// in monolith because the readback is synchronous INSIDE the applier: the caller sees
// the reconciled shadow on return. Under a transport there is a third state - the
@@ -585,7 +585,7 @@ namespace MobileGL::MG_State::GLState {
// and clearing optimistically leaves the shadow silently stale for the object's life.
//
// So: emit, then BLOCK until OnBufferWriteback lands, and let the writeback do the
// clearing. ARCHITECTURE.md:509 lists "the first CPU read of a GPU-write-pending
// clearing. ARCHITECTURE.md §13.1 lists "the first CPU read of a GPU-write-pending
// buffer" among the UNAVOIDABLE blocking points, because monolith already glFinish()es
// here; under R-1's verb barrier the block is nearly free, since the client is already
// waiting for appliedSeq to reach the record it just emitted.
@@ -12,8 +12,8 @@
// WHY THIS EXISTS AT ALL. A coherent persistent map is the one buffer shape with no per-write
// API call: the application memcpys through the pointer and neither a serial, an epoch nor a
// record moves. In monolith that is free, because the pointer IS the backend's GPU storage -
// MEASUREMENTS.md:87 prices the adoption at p99 163 -> 21 ms and ~400 MB saved, and
// ARCHITECTURE.md:481 requires it to hold unmoved for the whole monolith track. Across a
// MEASUREMENTS.md §1.4 prices the adoption at p99 163 -> 21 ms and ~400 MB saved, and
// ARCHITECTURE.md §12 requires it to hold unmoved for the whole monolith track. Across a
// process boundary the adopted address is meaningless, so P5 runs at tier T2 (emulate): the
// client keeps the shadow, MGPipeApplyMapPersistent declines, and the bytes the application
// wrote with no call have to be SHIPPED. `persistent-map-push` (PipeStats `pmap`) is exactly
@@ -39,7 +39,7 @@
//
// PHASE 1 IS CONSERVATIVE, AND SAYS SO. The whole mapped span is pushed, by block, at every
// validate point; no dirty bits, no memcmp. Phase 2 (MOBILEGL_IPC_SHADOW_SHM, P6+) makes it
// precise, and ARCHITECTURE.md:499 grants it the right to be pulled forward if Phase 1 is
// precise, and ARCHITECTURE.md §12 grants it the right to be pulled forward if Phase 1 is
// unacceptable on the Create/Flywheel fixtures - the one place in the plan where a
// measurement may reorder phases.
//
@@ -264,7 +264,7 @@ namespace MobileGL::MG_Record {
// reads as what it is: "publish everything the application wrote with no call".
//
// In P5 the 21 SyncPersistentMappedRange sites (CONTRACT-P5.md section 3: 9 Espryt + 12
// Magma, MEASUREMENTS.md:111's 20 being one low) still stand where they are and route
// Magma, MEASUREMENTS.md §2.1's 20 being one low) still stand where they are and route
// into PushBlocksFor through BufferObject::SyncPersistentMappedRange, so the push already
// happens at every point monolith pushes at. They retire into THIS call at P8, when the
// draw-path binding walks move to the client.
@@ -15,7 +15,7 @@
#include <set> // std::set<String> (LinkArtifacts); NOT provided by Includes.h on its own terms
// PURITY: no ShaderObject.h, no SpvcSession.h, nothing under MG_Util/ShaderTranspiler/, no Config.h,
// no MG_Backend/, no BufferState/. scripts/check_include_closure.py probe "artifacts-header" (ROADMAP P0.5;
// ARCHITECTURE.md:260) asserts that closure. The glslang scope token appears exactly twice below (B.0 D5: the two
// ARCHITECTURE.md §13.2) asserts that closure. The glslang scope token appears exactly twice below (B.0 D5: the two
// glslang-typed LinkArtifacts members moved verbatim) and the gate pins that count.
namespace MobileGL::MG_State::GLState {
@@ -445,7 +445,7 @@ namespace MobileGL::MG_State::GLState {
Bool pointSizeDemoted = false;
};
// ---- the archive field tables (ARCHITECTURE.md:259): ONE table per type, serving both directions ----
// ---- the archive field tables (ARCHITECTURE.md §7): ONE table per type, serving both directions ----
//
// Visitor contract: v(const char* name, Field&) - Field is const when Self is const, so a
// single table serves the serializer (const) and the deserializer (non-const); `Self`
+3 -3
View File
@@ -246,9 +246,9 @@ TEST_F(SplitBufferSet, Row2TheSweepIsBoundedByTheImageUnitHighWaterMark) {
binding = MG_State::GLState::ImageTextureBinding{};
}
// Row 3 - VulkanRenderer.cpp:11618. With no capture active there is nothing to mark, and that
// gate is the half worth pinning: a mark taken with no active capture would mark whatever the
// binding points happened to hold from a previous one.
// Row 3 - VulkanRenderer::BeginXfbCaptureForDraw() in VulkanRenderer.cpp. With no capture
// active there is nothing to mark, and that gate is the half worth pinning: a mark taken with no
// active capture would mark whatever the binding points happened to hold from a previous one.
TEST_F(SplitBufferSet, Row3TransformFeedbackTargetsAreOnlyMarkedWhileACaptureIsActive) {
auto target = MakeBuffer(15u, 256);
MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::TransformFeedback, 0).Bind(target);
+4 -3
View File
@@ -1,14 +1,15 @@
cmake_minimum_required(VERSION 3.14)
# The P0.5 include-closure assertions (ROADMAP P0.5; ARCHITECTURE.md:501 gate A): no MobileGL
# The P0.5 include-closure assertions (ROADMAP P0.5; ARCHITECTURE.md §13.2 gate A): no MobileGL
# compilation, no GL context. Text mode only here, because this CTestTestfile also runs on the
# `test` job's runner (test.yml:149-203), which has no submodules; the compiler-backed run is the
# `test` job's runner in test.yml, which has no submodules; the compiler-backed run is the
# include-graph-check job and the developer's local `--mode both`.
find_package(Python3 COMPONENTS Interpreter)
if (Python3_Interpreter_FOUND)
add_test(NAME MobileGLPurity.IncludeClosure
COMMAND ${Python3_EXECUTABLE} ${MGL_ROOT}/scripts/check_include_closure.py --mode text --self-test --require-all)
# ctest -L unit (test.yml:198-203). NO ENVIRONMENT property: it replaces the job env (ARCHITECTURE.md:567).
# ctest -L unit (the Test step of test.yml's test job). NO ENVIRONMENT property: it replaces the job env
# (ARCHITECTURE.md §16).
set_tests_properties(MobileGLPurity.IncludeClosure PROPERTIES LABELS unit)
else()
message(STATUS "MobileGLPurity.IncludeClosure not registered: no python3 interpreter (Windows is not a correctness gate)")
+2 -2
View File
@@ -3723,7 +3723,7 @@ TEST(DirectGLESSlotTable, OneDeathNoticeDropsTheTwinInEveryHolderOfTheKind) {
EXPECT_EQ(slots.LiveCount(kKind), liveBefore);
}
// The sweep and both of its drivers are RETIRED (ROADMAP.md:18's "delete the GC"), and this is
// The sweep and both of its drivers are RETIRED, and this is
// the property that replaces them: an announced death releases the twin before the next creation
// asks for a slot, so NOTHING accumulates under object churn.
TEST(DirectGLESSlotTable, AnnouncedDeathKeepsObjectChurnFromAccumulatingWithoutASweep) {
@@ -4055,7 +4055,7 @@ TEST(DirectGLESSlotTable, EverySwitchedOverKindResolvesItsTwinThroughTheHandleAr
// resolution moves to the CLIENT (D-F3). So this table is handle-keyed only, like the
// buffer resource table above, and its twin owns no driver id whatsoever - what it holds is
// the server's memo of one resolved view plus the raw-depth-fetch substitution decision,
// which is one of the two backend post-processings ARCHITECTURE.md:206 keeps on the server.
// which is one of the two backend post-processings ARCHITECTURE.md §5.5 keeps on the server.
//
// The handle is minted off the TEXTURE's lifetime id (D-F2: one view per ITextureObject),
// which is what makes HandleOf resolve at all - and it is legal precisely because the two
+1 -1
View File
@@ -385,7 +385,7 @@ namespace {
EXPECT_EQ(line.find("wrec/f=47.00"), String::npos) << line;
}
// THE STAGED-BLOB DISTRIBUTION, which is the optional deliverable MEASUREMENTS.md:342 says
// THE STAGED-BLOB DISTRIBUTION, which is the optional deliverable MEASUREMENTS.md §6.3 says
// has never existed. It shares the draw-payload histogram's edges - bucket 0 is "0 bytes",
// bucket n>0 is [2^(n-1), 2^n) - so the two are read the same way, and it is a COUNT per
// bucket rather than a byte sum: the shape is the deliverable and the bytes have their own
+1 -1
View File
@@ -19,7 +19,7 @@
// Each assertion exists because something would otherwise pass silently:
//
// the image links - a6 found mobilegl_server_main existed NOWHERE in
// the tree, only in ARCHITECTURE.md:488-496. A
// the tree, only in ARCHITECTURE.md §15. A
// target that failed to link would make every case
// below read as "did not run".
// the bytes crossed a - the echo carries the SERVER's own getpid(), so a
+1 -1
View File
@@ -777,7 +777,7 @@ namespace MobileGL::MG_Util::PipeStats {
// P6 gate 8's two per-frame numbers have their JSON homes where every other ByteClass and
// CallClass already does - the `bytes` and `calls` blocks above, under their long names
// (stage-segment-bytes, wire-records) - so there is nothing to add for them here. The
// staged-blob DISTRIBUTION does need one: it is the deliverable MEASUREMENTS.md:342 says
// staged-blob DISTRIBUTION does need one: it is the deliverable MEASUREMENTS.md §6.3 says
// has never been measured, and like the draw-payload histogram above it is a run-total
// distribution, which is exactly what Tracy cannot plot and this dump exists to carry.
// Bucket 0 is "0 bytes" and bucket n>0 is [2^(n-1), 2^n): the same edges PayloadBucketOf
+1 -1
View File
@@ -421,7 +421,7 @@ namespace MobileGL::MG_Util::PipeStats {
// populations: the one above is the command payload of a draw (plan section 4.5.7, sizing
// SEG_CMD), this one is how big the blobs a workload stages into SEG_STAGE actually are.
//
// IT EXISTS FOR CONTRACT-P6.md §9 item 8, and MEASUREMENTS.md:342 says in as many words why:
// IT EXISTS FOR CONTRACT-P6.md §9 item 8, and MEASUREMENTS.md §6.3 says in as many words why:
// the chunking work landed (1e7c372e buffer walks, 9469d48e texture slabs) and every
// `maxrec` number the file carries predates it, so "the per-blob byte distribution after
// chunking" had no measurement at all. A per-frame AVERAGE cannot answer it either: an
+2 -2
View File
@@ -10,8 +10,8 @@
A design document that cites the code is only as good as its line numbers, and a wrong one
is worse than none: it sends the next reader to a function that does something else. The
disaggregation plan's first draft cited SamplerObject.h:468-492 for a struct that lives at
:72-96 in a 160-line file, and nothing caught it.
disaggregation plan's first draft cited lines 468-492 of SamplerObject.h for a struct that then
lived at lines 72-96 of a 160-line file, and nothing caught it.
So every `File.h:123` and `File.cpp:123-456` in the given documents is resolved against a
git revision - the file must exist there and must have at least that many lines. Bare file
+3 -3
View File
@@ -10,7 +10,7 @@
ROADMAP.md P0.5 asks for a CI assertion on the include CLOSURE of the two headers the
phase extracts, and for a negative control that goes red when an `MG_State` include is
added back (ROADMAP.md:7 - every gate must be able to fail for the reason it exists).
added back (ARCHITECTURE.md §13.2 - every gate must be able to fail for the reason it exists).
`nm --undefined-only` cannot do that job: a header that is included but whose types are
never named leaves no symbol behind, and "included at all" is exactly the coupling P1
and P7 have to be able to sever. So the arbiter here is the preprocessor's own
@@ -91,7 +91,7 @@ PROBES = [
],
"Allow": [],
"TextLimits": {},
"Why": "MG_Pipe is below MG_State (ARCHITECTURE.md:550-561): the value types P1 hands "
"Why": "MG_Pipe is below MG_State (ARCHITECTURE.md §16): the value types P1 hands "
"the backend must not drag the frontend state tree back in.",
},
{
@@ -634,7 +634,7 @@ def main():
# it. `--mode text` is the default and never reaches pick_compiler, so a gate line that
# spelled a compiler this image does not have (clang++-20, say) used to run the text half,
# print nothing about it and exit 0 - a green nobody earned, which is exactly what
# ROADMAP.md:7 forbids. Asking for a compiler that is not there is an operator error
# ARCHITECTURE.md §13.2 forbids. Asking for a compiler that is not there is an operator error
# whatever the mode, and it stops the run here rather than half-running it.
resolved_compiler = pick_compiler(args.compiler) if args.compiler else None
if args.compiler and "clang" not in modes:
+5 -5
View File
@@ -2,8 +2,8 @@
# G5's gate: "pool 与延迟释放原样搬" is LITERAL - ELEVEN functions in
# MobileGL/MG_Backend/DirectGLES/Managers.cpp are byte-identical after P3a.
#
# WHAT G5 CLAIMS, and why a diff of the file cannot say it. ARCHITECTURE.md:316 puts the three
# persistently mapped rings and the buffer pool in the do-not-touch list, and :515 says what
# WHAT G5 CLAIMS, and why a diff of the file cannot say it. ARCHITECTURE.md §9.1 puts the three
# persistently mapped rings and the buffer pool in the do-not-touch list, and §14 says what
# protects them: `present` and eglSwapBuffers are strictly 1:1, so the rings' and the pool's retire
# only ever happens inside Present, and a batching change would starve them. P3a rewrites the file
# those functions live in - Ops_* becomes handle-shaped, the twin's gate is re-keyed - so the
@@ -69,8 +69,8 @@
# "a G5-protected function" and E's risk row at :1708 makes this gate the WHOLE mitigation for
# "the three-tier drain silently changes tier because its caller now supplies bytes differently":
# dropping the hot path from tier 1 into tier 3 costs the Mali WAR stall back, which is
# MEASUREMENTS.md:87's p99 163 -> 21 ms and ROADMAP.md:19's headline number, and under ID-6
# performance is RECORDED rather than gated, so no other gate stops it. A risk row whose named
# MEASUREMENTS.md §1.4's p99 163 -> 21 ms and the phase gate's headline number (MC 26.3 p99 on Adreno unchanged),
# and under ID-6 performance is RECORDED rather than gated, so no other gate stops it. A risk row whose named
# mitigation does not exist is worse than an unmitigated one. It is appended LAST rather than
# inserted, so the first nine lines of the D.0 baseline capture keep their positions.
#
@@ -449,7 +449,7 @@ compare_lists() {
say " SHIPS has moved away from the text that was reviewed. Either re-pin deliberately,"
say " replacing the sha AND the commit AND the decision beside it, or revert the body."
fi
say " G5 (ARCHITECTURE.md:316, :515) says the buffer pool, the deferred-release drain, the"
say " G5 (ARCHITECTURE.md §9.1, §14) says the buffer pool, the deferred-release drain, the"
say " three rings and BOTH arms of the three-tier flush drain - FlushPendingRangesNow in"
say " the pull build, FlushPendingRangesFrom in the push build (BRIEF-P3A.md:420, :1708,"
say " ID-11, ID-15) - move VERBATIM. If this change is intended, it is not a P3a change"
+4 -4
View File
@@ -2,8 +2,8 @@
# G5's gate for P4a: the Espryt do-not-touch list is LITERAL - SEVENTEEN regions across THREE
# files stay byte-identical after P4a.
#
# WHAT G5 CLAIMS, and why a diff of the files cannot say it. ARCHITECTURE.md:318 is the Espryt
# do-not-touch list and :321 names the ONE item moved out of it (the sub-rect upload decision and
# WHAT G5 CLAIMS, and why a diff of the files cannot say it. ARCHITECTURE.md §9.1 is the Espryt
# do-not-touch list and §6 names the ONE item moved out of it (the sub-rect upload decision and
# the stride computation, which is P4a's D-D3/D-D6 subject). P3a made the buffer half of that list
# literal with a sha gate over eleven functions in Managers.cpp (scripts/p3a_untouched_regions.sh);
# P4a rewrites the rest of Managers.cpp, DirectGLES.cpp and Utils.cpp by design - the twins become
@@ -85,7 +85,7 @@
# expected shape of a #if/#else pair that re-spells one of these bodies beside an untouched copy -
# a finding, not a limitation, because two ladders drift (ID-11, ID-15).
#
# A SHARED TEMPLATE OVER AN ACCESSOR INTERFACE IS REJECTED (ID-13, MEASUREMENTS.md:521): it resizes
# A SHARED TEMPLATE OVER AN ACCESSOR INTERFACE IS REJECTED (ID-13 in notes/p3a/INTEGRATOR-DECISIONS.md): it resizes
# pull symbols and breaks G1. If a P4a arm needs a variant of one of the seventeen it gets its own
# `#if MOBILEGL_PIPE_PUSH` function with its own name and its own pinned sha - the
# FlushPendingRangesFrom shape.
@@ -636,7 +636,7 @@ compare_lists() {
say " replacing the sha AND the commit AND the decision beside it in BOTH this script"
say " and its parent scripts/p3a_untouched_regions.sh, or revert the body."
fi
say " G5 (ARCHITECTURE.md:318, :321, :515) says the Espryt do-not-touch list is literal:"
say " G5 (ARCHITECTURE.md §9.1, §6, §14) says the Espryt do-not-touch list is literal:"
say " P3a's buffer pool, deferred-release drain, three rings and BOTH arms of the three-tier"
say " flush drain, plus P4a's unpack-PBO staging repack and its two ring helpers, the"
say " attachment permutation, the D24S8 sampling-emulation core and the format-caveat"
+3 -3
View File
@@ -9,7 +9,7 @@
"""Per-symbol nm/.text attribution between two libMobileGL.so builds.
P0.5's acceptance gate says every `nm --defined-only -S` delta has to be explainable per
symbol (ROADMAP.md:16). The awkward part is that de-nesting a type renames every mangled
symbol. The awkward part is that de-nesting a type renames every mangled
name that mentions it - `ProgramObject::LinkArtifacts` -> `LinkArtifacts` shows up inside
every `std::vector<...>` instantiation too - so a raw nm diff of a pure move looks
catastrophic. `--strip-scope` folds those into a "renamed-only" bucket: same normalised
@@ -30,8 +30,8 @@ GUARD RAILS - the comparison is meaningless unless both .so files were built wit
The header of every report prints both paths and their byte sizes so a mismatched pair is
visible in the output rather than only in the reader's assumptions.
This tool is informational by default (ARCHITECTURE.md:507, job name `monolith-symbol-report`
ARCHITECTURE.md:568): with no gate flag it prints its report and exits 0, whatever it found.
This tool is informational by default (ARCHITECTURE.md §13.2, job name `monolith-symbol-report`
ARCHITECTURE.md §16): with no gate flag it prints its report and exits 0, whatever it found.
Three flags turn it into a hard gate, and P1's G1 uses the first two - the strangler's pull build
has to stay byte-identical, and G1 spells that out as `added == removed == resized == renamed == 0`
with a `.text` delta of zero:
+1 -1
View File
@@ -382,7 +382,7 @@ function(add_trace_replay_test CASE_NAME BACKEND)
# --- P5: the variant suffix, and why the OUTPUT DIRECTORIES have to carry it too ----------
#
# ARCHITECTURE.md:584 asks for the SPLIT suffix because without it the entry collides with
# ARCHITECTURE.md §16 asks for the SPLIT suffix because without it the entry collides with
# the same case+backend and add_test with a duplicate NAME is a hard CMake error.
#
# THE DIRECTORIES ARE THE HALF THAT IS EASY TO FORGET AND EXPENSIVE TO GET WRONG. Both arms
+1 -1
View File
@@ -47,7 +47,7 @@ if(DEFINED TRACE_TRANSPORT AND NOT "${TRACE_TRANSPORT}" STREQUAL "")
set(ENV{MOBILEGL_TRANSPORT} "${TRACE_TRANSPORT}")
endif()
if(DEFINED TRACE_IPC_SERVER_PATH AND NOT "${TRACE_IPC_SERVER_PATH}" STREQUAL "")
# ARCHITECTURE.md:543. P6 consumes it; P5 carries it so that "unparsed" and
# ARCHITECTURE.md §15.1. P6 consumes it; P5 carries it so that "unparsed" and
# "parsed and ignored" stop being the same observation.
set(ENV{MOBILEGL_IPC_SERVER_PATH} "${TRACE_IPC_SERVER_PATH}")
endif()