- SetterConsistency is G7. It drives every public RenderState setter with a value that
differs from the one stored, and asserts the pipeline-subset hash moves IF AND ONLY IF
m_pipelineStateVersion moves. Every case also asserts m_version moved, which is the
vacuity guard: a setter handed the value it already holds satisfies "neither moved"
trivially and proves nothing.
- The cases that are not just a list: SetStencilFunc twice (a reference-only change must
move the version and NOT the hash, because Ref/ValueMask are dynamic and Func is
pipeline, and RenderState.cpp's pipeline bump is conditional on Func); SetPolygonMode
with only the back face moving (PolygonModeBack is one of the members P2's subset added
over the 24 ComputePipelineStateHash hashed); the eight ClipDistance capabilities (the
one family that moves m_version alone, so the hash must hold); SetScissorBox across the
ScissorBoxWrittenMask transition; all 25 SET_CAPABILITY names including the three that
had no storage before the contract commit; and SetPixelStoreParam, which must move
neither counter and touch no byte of the block.
- Verified red for the right reason: moving the P1/D2 boundary so ColorMasks falls in the
dynamic half - the partition stays complete, so it still compiles - makes
SetterConsistency fail naming SetColorMask and SetColorMaskIndexed, and nothing else.
- ChunkTablePartitionsTheBlock re-states the header's static_assert at run time and adds
the half the hash cannot check for itself: membership. It walks PipeFields.def's
MGP_FIELDS_RenderStateParameters - the same list gen_pipe.py checks against the struct -
and asserts a member is covered by a pipeline chunk exactly when
kMGPipePipelineStateMembers names it, that every other member is wholly dynamic, and
that StencilStates straddles at exactly the sub-member granularity the table intends.
- DerivationMatchesTheFrontendGetters drives 30-odd setters on a live GLContext AFTER the
filler has run, assembles the working block through the real create/bind/set_dynamic_state
path, and compares the derived fields against the frontend getters. The stale fill is the
point: an ASSERT_NE before each apply proves the block disagrees first, so nothing here
can pass by comparing the filler with itself. It runs in THREE verb phases, because the
fill table is the only thing that says what a verb may read: 25 of these fields are
kDraw's, the three clear values are kClear's and GetClampReadColor is kReadback's alone,
and reading a clear value under DrawArrays is Fatal{UnmigratedPipeInput} - correctly, and
the poison caught exactly that in the verify build before this shape.
- GetViewport's rounding is exercised on (1.5, 2.5, 63.5, 32.25) and the expected literal is
std::lround's answer - half away from zero - not the banker's rounding nearbyint gives.
- DynamicChunksCoverMagmasDynamicTailKey checks every GL-state input of DirectVulkan's
ApplyDynamicDrawStateTail against the dynamic half, and records the one exception the
design implies but no document states: ScissorTestEnabledMask is read by DynamicTailKey's
scissorEnabled yet is PIPELINE state, because SetCapability(ScissorTest) calls
BumpVersions(). Harmless - BumpVersions moves m_version too, so MGPDynamicState::Version
still moves and the tail still re-runs - and asserted the other way round so a later
table edit that demotes the mask is loud here.
- Replaces the contract commit's placeholder case, which existed only so the target had a
test before this package filled it in. The four names are the same four in every build:
in a pull build each is a visible SKIP, never a vanishing test.
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.