P3b/P4b espryt D1 slice 4, landing under the P7 program (notes/p7/PLAN-PH-P34B-P7.md
§1.2 row "回读 / pack state", §3 wave 2-D).
(a) THE CENSUS, AND IT CAME BACK CLEAN. Twenty-two cases per arm now run on the three split
arms: the two F1 pack-state cases, PixelStoreSweepScenario, FramebufferChurnScenario,
PackedWordReadbackScenario, LayeredTextureReadbackScenario and
DepthStencilReadbackMatrixScenario. The row expected reds and said so ("Expect reds - that
is the point"); the first run was 65/65 before any of this commit's code changes. That is
the finding: the 回读 half was assumed open because nothing had ever run it under a
transport, and the assumption was what was wrong - ScatterTightReadbackIntoPackState and the
server's neutral-pack read were already carrying it. No case needed a fix and no case needed
a named deferral.
DepthStencilReadbackMatrixScenario gets a per-arm block of its own, because the registration
macro cannot carry MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION=1 and without that pin the
scenario is unfalsifiable here: ES has no core depth/stencil readback, Mesa accepts the
reads anyway, and on llvmpipe every case goes green through a path the device does not have.
Its SeparateDepthAndStencilAttachmentsAreBothReadable SKIPS on all three arms and on monolith
too, naming the driver reason itself - a driver fact, not a transport one.
(b) THE TWO std::abort EMULATIONS, checked rather than assumed. copy-image-shadow-mirror
ALREADY cannot abort: MirrorCopyImageIntoDestinationShadow returns under a transport before
reaching MGPipeUnmigratedEmulation, and has since P5b package i1. get-tex-image-shadow is
retired here, and the reason is that its own premise did not hold: P4a wrote "a split server
holds no shadow to convert", but the level storage this converts IS the server's own, fed by
the staged texture store. When MapMipmapData answers, the conversion reads bytes that exist
on this side. So it converts when the shadow is there and DECLINES BY NAME when it is not
(rule I: MGLOG_E_ONCE + GL_INVALID_OPERATION, destination untouched). std::abort inside a
server answering a client's readback takes the session down for a level it happens not to
hold, and bypasses Session::Fail, which is the funnel the census gate watches. The funnel
keeps its teeth for the other four sites - generate-mipmap-storage,
generate-mipmap-cpu-fallback, generate-mipmap-cpu-filter, texture-remint-pull - which really
do reach into a client address space; fatal_census is unchanged at 79 abort sites because
the abort lives in MGPipeUnmigratedEmulation and that function stays. Stated plainly in the
notes: no case in the armed census reaches this site under a transport (the server answers
GetTextureImage with ReadTextureImageWire, never through the backend's GetTexImage slot), so
the change is defence in depth and has no integration red-once of its own.
(c) THE CASE NOTHING COVERED, and this slice's red-once:
PixelStoreSweepScenario.ReadPixelsIntoAPackBufferHonoursPackStateAndLeavesTheGapsAlone -
glReadPixels into a bound GL_PIXEL_PACK_BUFFER at a non-zero buffer offset with
PACK_ALIGNMENT/ROW_LENGTH/SKIP_ROWS/SKIP_PIXELS all non-default, read back with
glMapBufferRange. It is the only thing that drives EmitTables.cpp's `if (pbo)` branch, the
client servicing the pack PBO itself after the reply lands; the existing sweep case reads
into a client pointer, which is the other half and has unit cover. Every number makes a term
matter: ROW_LENGTH 5 at 4 bpp is 20, which ALIGNMENT 8 rounds up to a 24-byte stride;
SKIP_ROWS 1 and SKIP_PIXELS 2 put the first pixel at image byte 32; the read is issued at
buffer offset 16, so it lands at 48. The whole buffer starts 0xCD and the case asserts both
halves - the rows land where the pack state says, and every other byte is still poison.
Red-once (R-16): dropping just the buffer-offset term from EmitTables.cpp's `start` reds the
three split entries with "readback[at] Which is: '\xCD' (205)" - the destination still poison
because the rows landed 16 bytes early - while the ambient monolith entries pass, since the
driver services its own PBO there. EmitTables.cpp is not part of this commit.
(d) SplitReadbackPackBuffer's comment claimed "The client refuses PACK_BUFFER before
emission". It does not: it KEEPS the PBO and services it after the reply, and a refusal would
have been observable as a GL error. The conclusion (the server must see no pack buffer) was
right and the reason was backwards; rewritten to ID-49's actual split of the work.
Gates: integration-split 225/225 (base 186), integration-spawn 141/141 (base 102),
integration-tcp 144/144, ctest -L unit 2408/2408, integration-magma-split 73/73,
spawn_lane_parity / fatal_census (79 sites, 0 unmarked) / link_ratchet (186, unchanged)
green, G1 .text 0xa52203 with both nm lists byte-identical to ~/w7/p7-before.
MobileGL
A desktop OpenGL implementation
MobileGL is a free and open-source project that implements a desktop OpenGL API. The goal is to provide a complete desktop OpenGL implementation with a state management layer and multi-backend support.
Note
Status: In development. Parts of the codebase are incomplete. Current short-term target: OpenGL 4.2 (Core Profile).
Project positioning
MobileGL is an implementation of a desktop OpenGL library. It aims to provide:
- Full OpenGL state management.
- A front-end that exposes OpenGL functions.
- Multiple independent backend implementations, where each backend targets a specific graphics API and remains fully isolated from others.
This project is intended as an implementation/translation layer.
Key components
The repository is organized into following top-level modules:
- MG_State — state tracking and management logic for Graphics APIs.
- MG_Impl — front-end implementations of Graphics APIs that interact with
MG_StateandMG_Backend. - MG_Backend — per-backend translation layer that maps front-end Graphics APIs' semantics and state into concrete backend API calls (e.g. OpenGL ES, Vulkan).
- MG_Util and other utility modules.
Third-party components
MobileGL reuses several open-source projects:
- SPIRV-Cross by KhronosGroup - Apache License 2.0: github
- glslang by KhronosGroup - Various Licenses: github
- DiligentCore by Diligent Graphics - Apache License 2.0: github
- flat_hash_map by Malte Skarupke - Boost Software License 1.0: github
Refer to each component's repository for exact license texts. Any bundled third-party code in this repository is included under the upstream project's license.
Compatibility & target
- Short-term target:
OpenGL 4.2 (Core Profile). - Current development focus:
- Performance improvement
MG_StateandMG_ImplforOpenGL 4.2 (Core Profile)Direct (Vulkan)backendDirect (OpenGL ES)backend
Build Instructions
We currently provide no releases and no precompiled binaries.
If you want to try the project right now, you’ll need to build it yourself:
-
Clone the repository:
git clone https://github.com/MobileGL-Dev/MobileGL.git -
Initialize and update all submodules recursively:
git submodule update --init --recursive -
Follow glslang’s own documentation for its required initiation.
-
Configure and build the project with CMake:
cmake -B build cmake --build buildor do it in a modern way:
cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ cmake --build buildAlternatively, you can use platform-specific build commands as needed.
Build For macOS
On macOS, MobileGL can be built as a dylib that exposes the normal OpenGL/CGL/NSOpenGL entry points and routes them to the DirectVulkan backend. This is useful for running applications such as Minecraft through their stock GLFW/LWJGL OpenGL path while MobileGL is injected before context creation.
Prerequisites:
- macOS with Clang and Ninja.
- Vulkan loader and MoltenVK installed. With Homebrew, the MoltenVK ICD is commonly located at
/opt/homebrew/etc/vulkan/icd.d/MoltenVK_icd.json.
Configure and build:
cmake -S . -B build-macos-magma \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DMOBILEGL_BACKEND_TYPE=DirectVulkan \
-DMOBILEGL_BUILD_TEST=OFF \
-DMOBILEGL_BUILD_BENCHMARK=OFF
cmake --build build-macos-magma --target MobileGL -j8
The dylib will be generated at:
build-macos-magma/libMobileGL.dylib
To run Minecraft by MobileGL from a launcher like PrismLauncher, keep the stock LWJGL/GLFW natives and add a wrapper command to the instance settings:
env DYLD_INSERT_LIBRARIES=/absolute/path/to/MobileGL/build-macos-magma/libMobileGL.dylib MOBILEGL_BACKEND_TYPE=DirectVulkan VK_ICD_FILENAMES=/opt/homebrew/etc/vulkan/icd.d/MoltenVK_icd.json
Also make sure the JVM arguments include:
-XstartOnFirstThread
DYLD_INSERT_LIBRARIES must be active before GLFW creates its OpenGL context. After startup, the Minecraft F3 screen should report MobileGL and the Direct (Vulkan) backend if the injection worked.
Build Options
| Option | Description | Default |
|---|---|---|
MOBILEGL_BUILD_TEST |
Build MobileGL tests (requires Clang) | ON |
MOBILEGL_BUILD_BENCHMARK |
Build MobileGL benchmarks (requires Clang) | ON |
MOBILEGL_FORCE_RELEASE_OPT |
Enable O3 and LTO in Debug build | ON |
MOBILEGL_ENABLE_TRACY |
Enable Tracy profiler for performance analysis | OFF |
Notes:
- The project requires C++23.
MG_TestandMG_Benchmarkcan only be built with Clang, not GCC. To enforce Clang, add-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++to your command.- On Android, tests and benchmarks are always disabled.
Environment Variables
MobileGL supports runtime configuration via environment variables.
Supported Keys
| Variable | Description | Allowed Values | Default |
|---|---|---|---|
MOBILEGL_BACKEND_TYPE |
Select active backend implementation at startup. | DirectGLES, DirectVulkan |
DirectGLES |
MOBILEGL_DISABLE_TIMERQUERY |
Disable GPU timer-query exposure and use. | 0, 1 |
0 |
MOBILEGL_ESPRYT_USE_ANGLE |
Load ANGLE EGL/GLES libraries. | 0, 1 |
0 |
MOBILEGL_MAGMA_DISABLE_SUBGROUP |
Disable Vulkan shader subgroup support. | 0, 1 |
0 |
MOBILEGL_ADVERTISE_FP64 |
Advertise GL_ARB_gpu_shader_fp64. GLSL double/dvec/dmat compile and run either way - they are narrowed to 32 bits - so this only changes whether an application is told it has 64-bit precision, which it does not. |
0, 1 |
0 |
MOBILEGL_MAGMA_R11G11B10F_FALLBACK |
Use Magma's R11G11B10F format fallback. | 0, 1 |
0 |
MOBILEGL_MAGMA_FRAMESINFLIGHT |
Set Magma frames in flight. | Integer 1–64 |
3 |
MOBILEGL_ESPRYT_AVOID_SAMPLER_MIPMAP_MIN_FILTER |
Avoid sampler mipmap minification filters. | 0, 1 |
0 |
MOBILEGL_COHERENT_AS_FLUSH |
Treat persistent GL_MAP_FLUSH_EXPLICIT_BIT maps as coherent (app-compat for engines like Flywheel that never flush them). |
0, 1 |
0 |
MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION |
Always emulate depth/stencil glReadPixels/glGetTexImage by shader sampling on Espryt, instead of using the driver's own depth/stencil readback where it has one. |
0, 1 |
0 |
VK_ICD_FILENAMES |
Select the Vulkan ICD used by the Vulkan loader. | Path to an ICD JSON file | Loader default |
License
This project is distributed under GNU LGPL v3.0. See the LICENSE file in the repository for detailed information.