swung0x48 70c45ab9ce [MG_Remote] (P6/sm): two MobileGL processes, talking
The first time this project has had a second process. fork + execve of a real
server image, the control socket surviving the exec, bytes crossing a process
boundary, and the child exiting on EOF with nothing left behind.

mobilegl_server_main EXISTS NOW. a6 found ARCHITECTURE.md:488-496 had described
it for three phases while the symbol was nowhere in the tree, and the only
MobileGLServer target was the P0 spike stub, which links no MobileGL library at
all. The spike keeps its evidence and its name becomes MobileGLServerSpike; the
real image links the library, so an undefined symbol is a build error rather
than a dlsym failure in a child whose stderr is /dev/null.

WHAT sm OWNS AND WHAT IT LEAVES: the process, the inherited descriptors, the
transport and the exit discipline. Not the session, not the applier, not the
four segments - wiring those from ServerMain before lk has a seam to wire them
THROUGH is how call sites get written twice. The loop is a read/answer/exit-on-
EOF stand-in whose SHAPE is the part that matters: one reader, EOF ends the
process, and no timeout is ever allowed to stand in for the death fact (§5.4).

ANTI-RECURSION IS TWO CATCHES, and neither is ARCHITECTURE.md:488's. 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 in MG_Backend, so
obeying it flips the whole backend to frontend glue in the one process with no
frontend. Instead: (a) MOBILEGL_IPC_DIAL=no, structural and separate from role,
and (b) MOBILEGL_TRANSPORT and every MOBILEGL_IPC_* scrubbed from the child's
envp. The child refuses with 64 for (a) and 65 for (b) so the two safeties are
distinguishable - two that cannot be told apart are one.

TWO BUGS WORTH RECORDING, both found by the test rather than by review:

dup2(n, n) IS A NO-OP THAT DOES NOT CLEAR CLOSE-ON-EXEC. FdPassing sets
SOCK_CLOEXEC on the aux pair, so the child depends on dup2 to clear it - but in
a gtest process a fresh socketpair lands on exactly fds 3..8, so a source fd
often IS its own target. The no-op left CLOEXEC set and the following close()
then shut the descriptor we had just "installed". The child came up with no
socket and the parent saw TRANSPORT_CLOSED on its first send. Now spelled out
rather than written cleverly.

THE CHILD'S DIAGNOSTICS WERE INVISIBLE. WireLogError reaches the file sink
only - Defines.h builds the logger with the console sink off - so a child that
refused to start said so into a file the parent does not know the path of.
ARCHITECTURE.md §15.2 warns about exactly this on Android. Both refusal paths
now also write stderr directly, and both carry a distinct exit code the parent
can name without reading anything.

TESTS: six cases, 6/6. Each exists because something would otherwise pass
silently - the reply carries the child's own getpid() so a test that talked to
itself cannot pass (ID-124's lesson at the smallest scale); the process tree is
COUNTED before, during and after, not promised; the child is proven not to exit
while merely idle before it is proven to exit on EOF; an unresolvable image is a
named refusal that spawns nothing (S1); a surviving client knob is caught by
name (S3); and a descriptor crosses execve by SCM_RIGHTS, which is the mechanism
the four segments will ride on and is now exercised before it is needed.

Also records the asio decision in the contract: declined for P6 because spawn
needs five platform mechanisms and asio covers one - its own socketpair returns
operation_not_supported on Windows, it has no descriptor passing, segment
delivery is POSIX-only by design, and there is no fork. Revisit at P6.5, where
asio::generic::stream_protocol carries a raw family/type/protocol triple and
therefore gives AF_VSOCK from one implementation.

Gates: unit suite 2346, up 6, same two pre-existing environmental failures. G1
pull 0 added / 0 removed, .text size 10822147 unchanged, and zero spawn, server
or SocketTransport symbols in the pull build.
2026-09-21 10:04:31 -04:00

MobileGL

C++ GNU LGPL 3.0 Development

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:

  1. MG_State — state tracking and management logic for Graphics APIs.
  2. MG_Impl — front-end implementations of Graphics APIs that interact with MG_State and MG_Backend.
  3. 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).
  4. MG_Util and other utility modules.

Third-party components

MobileGL reuses several open-source projects:

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_State and MG_Impl for OpenGL 4.2 (Core Profile)
    • Direct (Vulkan) backend
    • Direct (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:

  1. Clone the repository:

    git clone https://github.com/MobileGL-Dev/MobileGL.git
    
  2. Initialize and update all submodules recursively:

    git submodule update --init --recursive
    
  3. Follow glslang’s own documentation for its required initiation.

  4. Configure and build the project with CMake:

    cmake -B build
    cmake --build build
    

    or do it in a modern way:

    cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
    cmake --build build
    

    Alternatively, 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_Test and MG_Benchmark can 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.

S
Description
No description provided
Readme
2.6 GiB
Languages
C++ 84.3%
C 6.1%
Python 5.7%
CMake 1.7%
Shell 1.4%
Other 0.5%