mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
13 KiB
13 KiB
Open questions, full text (formerly the "Open questions" section of ROADMAP.md, moved here 2026-09-24)
ROADMAP.mdkeeps only a one-line status per question; here is the full statement of each question, the source for the answered parts, and the criteria for the unanswered parts. Numbering is stable; cite as "open question N".
Questions answered in P0 are no longer listed (spike A's domain, spike B's tiers, posix_spawn unavailable, the OOM probing idiom, retirement of GetInteger64i_v/GetProgramiv, D21 and the RenderbufferObject lifetime id, the dynamic accessor baseline).
- The real per-draw CPU cost of the client-side dirty walk. Answered (P2–P4a): pushing did not net a reduction below the pull baseline; under Release the P2 boundary is +6–12%, P3a adds another +17–19 pt on rd12 where VAO switching is dense, P4a +3.4–5.7 pt on Espryt (
MEASUREMENTS.md§3–§5). The user accepted on 2026-09-08, and performance has been recorded only since then. - The incidence of texture re-mint pulls on real corpora. Answered (P4a): negligible; the LRU is kept and the default stays 0 — 2 times in 780 statistics windows over 79 cases × two backends (
iris-photonandiris-derivativeone each, only in DirectGLES). But under P5b this path was a named Fatal, exactly the first block of these two traces pluscreate-indirectGLES (P9). P9 W2 closed: re-mint needs no pull — the server reads the GPU level, the store fills the pending box (Espryt), GPU→GPU copy (Magma); the census over 77 rows × {monolith, inproc} is still the same two times (both are render targets whose store has no bytes), andOnTexturePullRequestis deleted (see git history). - Re-check of spike B's
untrusted_appdomain. The tiers for both devices were measured in theshelldomain; runextmem_probeonce more from the application process (spike A's exec hook is already available). Do before P11. 2026-09-22 downgraded: only meaningful for the same-machine arm's T0 / T1; the stream data plane does not need it. - Wire granularity of render state. Answered (P2): 16 boundaries / 15 chunks, 7 pipeline 396 B + 8 dynamic 772 B; CSO LRU 64 provisional, retuned in P13.
- Capabilities without storage. Answered (P2):
FramebufferSrgb,DepthClamp,TextureCubeMapSeamlessall gained real storage, andsizeof(RenderStateParameters)is still 1168. - The shape of the named UBO host payload (D-B8). Magma repacks 331 KB of named UBO bytes per frame in the 26.3 world; Espryt 0. Either freeze the second variable-length tail shape, or take the alternative (Magma binds a resident
VkBufferrange directly at the descriptor, a separatedevPR). P7. - The cut seam in
MG_Util. The server needs SPIRV-Cross / ESSL translation cache / format handlers / POST probe; the client needs glslang and the reflection layer; whetherMG_Utilhas a clean Transpile-vs-Reflect seam inside has not been audited. P7. - Can one reflection archive serve three consumers. The Espryt half is answered (P4a): yes, and no copy is needed. Magma's first consumer was answered by P5f fm:
MagmaProgramSourcetakes everything from the wireProgramArchive, no frontend object, no copy. The second (storage block table) today is no and has gotten worse: under split,MagmaProgramSource::EnsureStorageBlocksre-runs SPIRV-Reflect every draw (the monolith arm'sDirectVulkan.cpp:177-200at least has a persistent cache); the answer is to add orderedstorageBlockstoLinkArtifacts(the data is already inblockReflection), and both consumers read it instead. Answered (P7 wave 2-C,dce9953d..cf7ca59f):storageBlocksenters the archive, both consumers read it, per-draw SPIRV-Reflect 4→0; the monolith half ofg_programResourceCachesgoes to P13 (G1). - Can viewport-array replay fit into one
draw_vbo: answered (2026-09-30, ID-P8-1): yes — the server replays it pass by pass within one draw, grouped by state (DirectGLES.cpp:8421-8465), andViewportArrayScenariois green on each split arm. - The
ResidentSubDataasymmetry. Half answered (checked 2026-09-22): Magma's implementation is complete (VkBufferManager.cpp:123monolith table,:148wire table,fff9d639f). Still unanswered:kCapResidentSubDatais never published by the server —MG_Backend/Init.cpp:192-219is the only productionSetCapabilityBitscall site in the whole tree, OR-ing only XFB, the three query bits, and the run-ahead bit; soPipeFill.cpp:848is always false under split, and both backends under split fall back to the in-place memcpy atBufferObject.cpp:711-716, making Magma's implementation dead code in split. Answered (P7 wave 2-C, ID-P7-20):InitServerRoleCommonpublisheskCapResidentSubDatafrom the server's own wire resource table, and the mirror accepts it on receipt; the white-box check "what is emitted is opcode 49" is unreachable before the P11 adoption tier lands (§5.4 debt). - The
SEG_STAGElimit. Content side answered (2026-09-20): chunking is implemented — the buffer range walk (1e7c372e) and the texture full-width slab (9469d48e) split into multipleresource_subdatarecords perMGPipeStageChunkBytes()(default 1/4 of 32 MiB = 8 MiB), so a single 128 MiB upload no longer needs an explicitMOBILEGL_IPC_STAGE_MB=256; when a single piece still exceeds the arena or that record type is not wired into chunking, theFatal{RingOverrun, "SEG_STAGE"}fallback remains. Still unanswered (narrowed 2026-09-22): in a6 §6's measured results, the only things not walked are the program archive (the only unbounded blob) and thedraw_vboNumDraws*12range tail; the host index span has no producer (struck out);set_global_constantshas a walk. Chunking both is the same work shared by P6.5 sl and P8, and the stream send window is sized against them. The occupancy distribution of MC in-world / Create is still unmeasured (gate 8 has given bytes/frame and records/frame for the two loads; the per-blob distribution was taken only on the integration lane). P8-0 measured result (2026-09-30, ID-P8-5): largest program archive 354,846 B, largestdraw_vborecord 1,936 B, both far below arena/4; no chunking, closed. - A second opinion on the server side for split-only rendering bugs after P13. The verify build + recorder cover only what is pushed, not the backend's interpretation of it.
- Whether baked internal shaders can express uniform locations and UBO layouts without a live
ProgramObject. Color blit answered (P5f fv:WireColorBlit.{vert,frag}uses push constants, andWireColorBlitSpirv.his checked into the tree); narrowed to the depth mip program (today compiled out under split, whose split path is a named Fatal) and pass-through TCS (ProgramFactory.cpp:4060-4262, the third uninventoried internal shader generator). Answered (P7 wave 2-B / B2): depth mip baking (A)(D) (WireDepthMipmap.*, push constant,MOBILEGL_BAKED_INTERNAL_SHADERSfreshness gate table-driven) and (B′) (the disaggregated build's monolith arm switches to the baked module) landed; the third baked shader set, for multisample resolve, comes with B2; pass-through TCS is still uninventoried. - Which pull-mode-tuned cache hit rates the push model changes. Survivor capacity is retuned in P13. One clue: on device, 26.3 Espryt's
sve≈ draw count (the sampler-view set is re-sent once per draw), while desktop is only ~0.07/draw; on the P3b/P4b optimization list. - Whether monolith's
*IndirectCountnot callingSyncGpuWrites()is a latent gap. A separatedevissue; the split must not fix it opportunistically. Answered (2026-09-30): yes — P8-C / P8-D host red-once confirms (Espryt*IndirectCount, MagmaglMultiDrawArraysIndirectCountread 0); the split half is fixed (ID-P8-9), and the monolith half is fixed in the P8 second wave's dev package (ID-P8-3). - Actual memory footprint of the index host mirror. The total element-array buffer in the MC / Sodium / Iris corpora is unmeasured; if it significantly exceeds 64 MiB, the frequency and cost of the fallback path must be measured. P8.
- The
create-indirectfixture's failure on Adreno 830 predates this branch (reproduces with the baseline APK,dev@81b17c0b); it is not caused by this branch. Thescudo::reportMapErrorcrash withrd12+ Magma on both Adreno 830s is also on thedevside. Both are excluded from device A/B and stay in the desktop corpus; P8 must assertroundtrips-per-frame == 0oncreate-indirect, so thedevfix is on someone else's critical path. The create-indirect part is answered (2026-09-30): the original fixture was captured on a desktop driver withGL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT= 16, and Flywheel laid out the scatter list for 16; Adreno 830 on both backends and Mali's Vulkan require 64, so all 1,270 range bindings were rejected withGL_INVALID_VALUE. The original fixture is retired and replaced by the derivedminecraft-1.21.1-neoforge-create-indirect-in-world-align1024(not the same trace:tools/trace_replay/fixture_tools/realign_buffer_ranges.cpp --align 1024moves these bindings to 1024-aligned slots, inserting 3,812 calls, target calls 504631 → 508443; host SSIM matches the original fixture to 9 digits). Redmi passes on both backends for monolith / spawn; on Mali-G1-Ultra Magma passes (the split arm separately fixed the T0 POST, see the POST section ofCONTRACT-P11.md), while Espryt is still 0.848: that machine's GLES driver vertex-stage SSBO limit is 0, so Flywheel indirect's vertex program cannot link (a missing capability, not a split defect). - Load balancing between the two split sides. A new question unlocked by P5e: under VD32 (~3550 draws/frame) the apply thread is 11-12 ms, the client 15.7 ms, and the client is the bottleneck, pinned at ~94%. Moving work from the client to apply would directly lower the bottleneck — meaningless under lockstep (the two sides add serially); run-ahead is what makes it a lever. Options: the emitter on the encode side, the tracker walk, dirty-page tracking of the persistent map (
change_protectionwas 1.3% in the profile). Must re-profile first: with the waits gone, the denominators of all the tail items have changed. Queued after P5e; unowned; on 2026-09-22 suggested to attach to the optimization phase after the roadmap completes, with the 2×2 matrix lane of P6.5 re-profiling along the way. - Link bandwidth budget and compression. In the TCP endgame,
SEG_STAGEbytes/frame is against Wi-Fi / USB (on the order of 30–100 MB/s), not memory; the ~1 MB/frame budget inARCHITECTURE.md§14 at 60 fps is 60 MB/s, already at the Wi-Fi limit. Whether to LZ4-style compress the stage payload and whether to deduplicate texture uploads by content hash on the server side must wait for gate 8's distribution. Must be answered before the first line of the P6.5 contract is written. - The stall of a large single upload. A 128 MiB single upload at 50 MB/s is 2.5 s; content-side chunking solves "does it fit", not "how long must we wait". On the cross-machine arm, either accept and record it, or make uploads asynchronous (think it through together with P9's semantics). Do not pretend it is solved.
- The form of pairing / authentication. Ruled (ID-P7-3, 2026-09-22): a token is enough, no TLS. The threat model is "a remote code path anyone can connect to", not eavesdropping: token comparison in constant time, ≥16 bytes, no token means loopback only, the data plane bound to the authenticated control connection by
Welcome.dataNonce, authentication before fork. TLS is kept as a P12 open item. - Client platform scope. The default is Linux + Android first (existing CI can verify), the Windows client in the second batch (
ShmSegmentWin32exists; thepipe:named refusal is retired, TCP replaces it), and macOS is still not split. This decides whetherARCHITECTURE.md§15.3 "Windows machines are not a correctness gate" needs changing. - Detection of half-open connections. A Wi-Fi disconnect does not produce a hang-up event; dl's latch comes from the descriptor hang-up, while TCP needs keepalive / heartbeat timeout and reporting as a hang-up by the transport layer — this does not contradict "never take it from an apply timeout"; write it down to avoid re-arguing. P6.5 ct.
- Redefinition of the E1 control (ID-122). Closed (2026-09-29 debt review):
10bfd29freplaced E1's pixel race with the negative controlscripts/ci/wait_boundary_negative_control.pythat observes protocol waits. On 2026-10-18 that negative control retired: the probe could see the missing wait, so the resident unit caseRemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWaitproves it instead (the sameApplierReset, no wait after publishing, must read parked=0).