mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
Add an end-user guide under userguide/.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# MobileGL user guide
|
||||
|
||||
MobileGL is a desktop OpenGL implementation, up to OpenGL 4.6 core profile. Applications call
|
||||
OpenGL through EGL, GLX or WGL. MobileGL runs those calls on one of two backends:
|
||||
|
||||
| Backend | Internal name | Runs on top of |
|
||||
|---|---|---|
|
||||
| **Espryt** | `DirectGLES` (the default) | the platform's OpenGL ES 3.x driver (EGL + GLES) |
|
||||
| **Magma** | `DirectVulkan` | the platform's Vulkan driver |
|
||||
|
||||
You pick the backend at run time with `MOBILEGL_BACKEND_TYPE` (see [configuration.md](configuration.md)).
|
||||
|
||||
This guide is for people who build, install, configure and run MobileGL. Developer notes live under
|
||||
`docs/`; where they disagree with this guide, this guide follows the current code.
|
||||
|
||||
> **Status.** MobileGL is in development and ships no prebuilt binaries. Everything here is built
|
||||
> from source. Commands were checked against the `feat/disaggregated` branch.
|
||||
|
||||
## Topologies: where the backend runs
|
||||
|
||||
The GL frontend (state tracking, shader translation) always runs in the application. The backend
|
||||
can run in three places:
|
||||
|
||||
| Topology | `MOBILEGL_TRANSPORT` | What happens | Needs a split build |
|
||||
|---|---|---|---|
|
||||
| **Monolith** | `monolith` (default) | Frontend and backend run on the application's GL thread. | No |
|
||||
| **In-process split** | `inproc` | The backend runs on a second thread of the same process, fed through a ring buffer. | Yes |
|
||||
| **Out-of-process split** | `spawn` | The backend runs in a separate server process. The client either launches its own server or connects to a running one over a Unix socket or TCP. | Yes |
|
||||
|
||||
A *split build* is a library built with `MOBILEGL_BUILD_DISAGGREGATED=ON`. In a build without it,
|
||||
`MOBILEGL_TRANSPORT` is silently ignored and everything runs monolith.
|
||||
|
||||
Out-of-process rendering needs somewhere to present frames. A server process started on its own has
|
||||
no window. On Android, a client's window cannot be handed to another process, so a windowed Android
|
||||
app can only render out of process into a window that the **server** owns. See
|
||||
[android-plugin.md](android-plugin.md#out-of-process-rendering-with-a-window).
|
||||
|
||||
## Which setup do I need?
|
||||
|
||||
| You want to... | Setup | Guide |
|
||||
|---|---|---|
|
||||
| Play Minecraft on Android with the copy of MobileGL that is built into an FCL build | FCL embedded, monolith | [android-fcl.md](android-fcl.md) |
|
||||
| Use MobileGL in FCL (or another launcher that reads FCL renderer plugins) without rebuilding the launcher | Renderer plugin APK, monolith or `inproc` | [android-plugin.md](android-plugin.md) |
|
||||
| Test out-of-process rendering on Android, with frames shown on screen | Plugin APK: on-screen display server + `spawn` client | [android-plugin.md](android-plugin.md#out-of-process-rendering-with-a-window) |
|
||||
| Render on a phone's GPU for a program on a Linux PC | Plugin (server) + Linux client over TCP | [android-plugin.md](android-plugin.md#tcp-server-for-remote-clients), [linux.md](linux.md#tcp-client) |
|
||||
| Give a Linux container on Android (anland) GPU acceleration through the Android drivers | Linux client library as the system glvnd/GBM vendor, server on Android | [linux.md](linux.md#system-wide-split-client-glvnd-vendor-gbm-backend) |
|
||||
| Run a Linux program on a Linux desktop through MobileGL | Linux library, monolith (experimental) | [linux.md](linux.md#monolith-on-a-linux-desktop) |
|
||||
| Run a Windows OpenGL program (for example Minecraft) through MobileGL | WGL `opengl32.dll` drop-in, monolith | [windows.md](windows.md) |
|
||||
| Build from source | | [building.md](building.md) |
|
||||
| Look up a setting | | [configuration.md](configuration.md) |
|
||||
| Fix something that does not work | | [troubleshooting.md](troubleshooting.md) |
|
||||
|
||||
When **not** to use the split topologies: if you only want the best frame rate in one app, use
|
||||
monolith (FCL embedded) or `inproc` (plugin). `spawn` adds a process boundary and a socket for every
|
||||
frame. It exists for sharing one GPU-owning server between processes, sandboxes or machines.
|
||||
|
||||
## Platform support at a glance
|
||||
|
||||
| Platform | Monolith | `inproc` | `spawn` (Unix socket) | `spawn` (TCP) | Server |
|
||||
|---|---|---|---|---|---|
|
||||
| Android (FCL embedded) | yes | no (built without the split layer) | no | no | no |
|
||||
| Android (plugin APK) | yes | yes | yes | yes | yes, offscreen or on-screen |
|
||||
| Linux (glibc) | experimental | yes | yes | yes | yes, offscreen only |
|
||||
| Windows (WGL) | yes, but see the build note in [windows.md](windows.md) | not supported | not supported | not supported | no |
|
||||
| macOS / iOS | the code exists (CGL and NSOpenGL frontends); not covered by CI and not verified for this guide. The project README describes the macOS build. | | | | |
|
||||
|
||||
## How to tell MobileGL is active
|
||||
|
||||
- `GL_RENDERER` starts with `Espryt (MobileGL Core)` or `Magma (MobileGL Core)`.
|
||||
- `GL_VENDOR` contains `MobileGL-Dev`.
|
||||
- `GL_VERSION` looks like `4.6 MobileGL 26.10.0-dev..., Direct (GLES) Backend, GIT@<hash>` (or
|
||||
`Direct (Vulkan)`).
|
||||
- In Minecraft, the F3 screen shows these strings.
|
||||
- The log says `Config: Active backend type set to DirectGLES` (or `DirectVulkan`). Logs go to
|
||||
logcat (tag `MobileGL`) on Android, and to the file named by `MOBILEGL_LOG_FILE_PATH` elsewhere.
|
||||
See [troubleshooting.md](troubleshooting.md#logs).
|
||||
|
||||
## Files in this guide
|
||||
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| [android-fcl.md](android-fcl.md) | MobileGL built into FCL: monolith, choosing the backend, settings |
|
||||
| [android-plugin.md](android-plugin.md) | The renderer plugin APK: install, `inproc`, the render server, windowed out-of-process rendering, TCP, same-device external programs, embedding the server in your own APK |
|
||||
| [linux.md](linux.md) | Linux library: glvnd EGL/GLX vendor, GBM backend, `/etc/mobilegl/client.conf`, the server, TCP |
|
||||
| [windows.md](windows.md) | WGL `opengl32.dll` drop-in |
|
||||
| [building.md](building.md) | Toolchains, CMake options, Gradle properties, artifacts |
|
||||
| [configuration.md](configuration.md) | User-facing `MOBILEGL_*` settings and where they can be set |
|
||||
| [troubleshooting.md](troubleshooting.md) | Logs, common failures and their fixes |
|
||||
@@ -0,0 +1,129 @@
|
||||
# MobileGL embedded in FCL (Android, monolith)
|
||||
|
||||
Some FCL (Fold Craft Launcher) builds carry MobileGL as a Gradle module and ship `libMobileGL.so`
|
||||
inside the launcher APK. This page covers that embedded copy. For the separately installed renderer
|
||||
plugin, see [android-plugin.md](android-plugin.md).
|
||||
|
||||
## When to use it
|
||||
|
||||
- You play Minecraft on Android through an FCL build that already lists MobileGL renderers.
|
||||
- You want the simplest setup with the least overhead: everything runs inside the game process.
|
||||
|
||||
When not to use it:
|
||||
|
||||
- You want `inproc`, `spawn` or TCP. The embedded copy is built **without** the split layer
|
||||
(`MOBILEGL_BUILD_DISAGGREGATED=OFF`), so `MOBILEGL_TRANSPORT` is ignored and it always runs
|
||||
monolith. Use the [plugin APK](android-plugin.md) instead.
|
||||
- Your launcher does not embed MobileGL. Use the plugin.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Android 8.0 (API 26) or newer, arm64-v8a. The embedded build packages arm64-v8a only.
|
||||
- Espryt needs an OpenGL ES 3.x driver. Magma needs a Vulkan driver.
|
||||
|
||||
## How it is built and integrated
|
||||
|
||||
The FCL source tree has MobileGL as a git submodule and Gradle module:
|
||||
|
||||
| Where | What |
|
||||
|---|---|
|
||||
| `.gitmodules` | submodule `MobileGL` -> `https://github.com/MobileGL-Dev/MobileGL.git` |
|
||||
| `settings.gradle.kts` | `include(":MobileGL")` |
|
||||
| `FCLauncher/build.gradle.kts` | `implementation(project(":MobileGL"))` |
|
||||
|
||||
MobileGL's `build.gradle` detects that it is not the standalone plugin build (the root project is
|
||||
not `MobileGLPlugin`) and then:
|
||||
|
||||
- builds arm64-v8a only;
|
||||
- builds without the split layer (`MOBILEGL_BUILD_DISAGGREGATED=OFF`), so there is no
|
||||
`libMobileGLServer.so`;
|
||||
- builds with ThinLTO and `-O3` (`MOBILEGL_ENABLE_LTO=ON`) unless you pass
|
||||
`-Pmobilegl.enableLto=OFF`;
|
||||
- uses NDK `27.3.13750724` and the Android SDK's CMake `3.22.1`.
|
||||
|
||||
Before the first build, initialize MobileGL's submodules and glslang's external sources. Run these
|
||||
inside the FCL checkout:
|
||||
|
||||
```sh
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
```sh
|
||||
cd MobileGL/3rdparty/glslang && python3 update_glslang_sources.py
|
||||
```
|
||||
|
||||
Then build FCL as its own documentation describes. The `mobilegl.*` Gradle properties from
|
||||
[building.md](building.md#gradle-properties) apply when passed to FCL's Gradle invocation (for
|
||||
example `-Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_DEBUG`).
|
||||
|
||||
## Choosing the renderer and backend
|
||||
|
||||
In FCL, open the game settings and pick the renderer under **OpenGL Implementation (Renderer)**. The
|
||||
embedded copy appears as two entries. FCL sets the backend from the entry you pick:
|
||||
|
||||
| FCL entry | Sets |
|
||||
|---|---|
|
||||
| `MobileGL (Dev, Espryt)` | `MOBILEGL_BACKEND_TYPE=DirectGLES` |
|
||||
| `MobileGL (Dev, Magma)` | `MOBILEGL_BACKEND_TYPE=DirectVulkan` |
|
||||
|
||||
The entry names above are from the FCL build that this guide was checked against; other FCL builds
|
||||
may label them differently.
|
||||
|
||||
Which backend to pick: try Espryt first (the default). Use Magma if your device's Vulkan driver is
|
||||
better than its GLES driver. Compare with the in-game frame rate; there is no universal answer.
|
||||
|
||||
## Other settings
|
||||
|
||||
FCL's **Environment Variables** editor (game settings, advanced section) takes one `KEY=VALUE` per
|
||||
line. FCL applies it after the renderer's own variables, so it can also override
|
||||
`MOBILEGL_BACKEND_TYPE`. Example:
|
||||
|
||||
```text
|
||||
MOBILEGL_FRAMES_IN_FLIGHT=2
|
||||
MOBILEGL_RELAXED_SEMANTICS=1
|
||||
```
|
||||
|
||||
Useful keys are listed in [configuration.md](configuration.md). The FCL build checked for this guide
|
||||
stores this editor's contents launcher-wide, not per instance.
|
||||
|
||||
Without access to the launcher's settings (for example while testing a launcher you cannot
|
||||
rebuild), Android system properties work from `adb`, with no root needed:
|
||||
|
||||
| Property | Effect |
|
||||
|---|---|
|
||||
| `debug.mobilegl.backend` | Overrides `MOBILEGL_BACKEND_TYPE`, even when the launcher set it. |
|
||||
| `debug.mobilegl.env` | `KEY=VALUE;KEY=VALUE` list of settings. It ranks **below** the process environment: it fills in only keys the launcher did not set. It holds at most 91 characters (Android's property length limit). |
|
||||
| `debug.mobilegl.fps_log` | `1` logs the frame rate about every two seconds (same as `MOBILEGL_FPS_LOG=1`). |
|
||||
|
||||
```sh
|
||||
adb shell setprop debug.mobilegl.backend DirectVulkan
|
||||
```
|
||||
|
||||
```sh
|
||||
adb shell setprop debug.mobilegl.env "MOBILEGL_FRAMES_IN_FLIGHT=2;MOBILEGL_RELAXED_SEMANTICS=1"
|
||||
```
|
||||
|
||||
These properties apply to every app on the device that loads MobileGL, and they last until reboot.
|
||||
Clear one by setting it to an empty string:
|
||||
|
||||
```sh
|
||||
adb shell setprop debug.mobilegl.env ""
|
||||
```
|
||||
|
||||
`debug.mobilegl.env` covers most settings in [configuration.md](configuration.md). The ones marked
|
||||
*env only* there are read straight from the process environment and ignore it, notably
|
||||
`MOBILEGL_LOG_FILE_PATH` and `MOBILEGL_IPC_TOKEN`. `MOBILEGL_FPS_LOG` and
|
||||
`MOBILEGL_GPU_HANG_BUDGET_MS` have their own properties (`debug.mobilegl.fps_log`,
|
||||
`debug.mobilegl.gpu_hang_budget_ms`).
|
||||
|
||||
## How to tell it works
|
||||
|
||||
- Minecraft's F3 screen shows `Espryt (MobileGL Core)` or `Magma (MobileGL Core)` as the renderer.
|
||||
- logcat shows MobileGL's lines:
|
||||
|
||||
```sh
|
||||
adb logcat -s MobileGL
|
||||
```
|
||||
|
||||
Look for `Config: Active backend type set to DirectGLES` (or `DirectVulkan`).
|
||||
- MobileGL also writes `/sdcard/MG/latest.log`, if the process may write there.
|
||||
@@ -0,0 +1,236 @@
|
||||
# MobileGL renderer plugin APK (Android)
|
||||
|
||||
The plugin is a standalone app (`top.mobilegl.plugin`, built from `android-plugin/`). It does three
|
||||
jobs:
|
||||
|
||||
1. **Renderer plugin.** FCL and other launchers that read FCL renderer plugins find it and load its
|
||||
`libMobileGL.so` into the game process.
|
||||
2. **Render server.** It can run a MobileGL server, either offscreen (a foreground service) or
|
||||
on-screen (a full-screen Activity that shows a client's frames).
|
||||
3. **Driver self-test.** Its launcher screen (**POST** tab) tests the device's GLES and Vulkan
|
||||
drivers, and can run a short benchmark.
|
||||
|
||||
## When to use it
|
||||
|
||||
- You want MobileGL in a launcher without rebuilding the launcher.
|
||||
- You want `inproc`, out-of-process (`spawn`) or TCP rendering on Android. Only split builds can do
|
||||
that, and the plugin is a split build by default.
|
||||
- You want a phone to render for a client on another machine.
|
||||
|
||||
When not to use it: if your FCL build already embeds MobileGL and you only need monolith rendering,
|
||||
the embedded copy is simpler ([android-fcl.md](android-fcl.md)).
|
||||
|
||||
## Build and install
|
||||
|
||||
Build instructions are in [building.md](building.md#android-plugin-apk). In short:
|
||||
|
||||
```sh
|
||||
gradle -p android-plugin :app:assemblePluginRelease -Pmobilegl.buildDisaggregated=ON -Pmobilegl.buildDisaggregatedInproc=ON
|
||||
```
|
||||
|
||||
The APK is
|
||||
`android-plugin/app/build/outputs/apk/plugin/release/MobileGL-plugin-release-<git-hash>.apk`. A
|
||||
release APK is signed only when the signing environment variables are set (see
|
||||
[building.md](building.md#signing)); otherwise sign it yourself before installing.
|
||||
|
||||
```sh
|
||||
adb install -r MobileGL-plugin-release-<git-hash>.apk
|
||||
```
|
||||
|
||||
Android refuses to replace an installed plugin that was signed with a different key. Either
|
||||
uninstall the old one first (the launcher then forgets its plugin settings) or build with
|
||||
`-Pmobilegl.applicationIdSuffix=.dev` to install a second copy next to it.
|
||||
|
||||
Requirements: Android 8.0 (API 26) or newer. The default ABI is arm64-v8a
|
||||
(`-Pmobilegl.abis=all` adds x86_64).
|
||||
|
||||
## Using the plugin in a launcher
|
||||
|
||||
The plugin advertises itself through manifest metadata. The launcher lists it as a renderer named
|
||||
**MobileGL** and loads `libMobileGL.so` from the plugin's install directory.
|
||||
|
||||
| Metadata | Read by | Contents |
|
||||
|---|---|---|
|
||||
| `fclPlugin`, `renderer`, `boatEnv`, `pojavEnv` | launchers using the original FCL plugin format | Fixed environment: `LIBGL_ES=3`, `POJAV_RENDERER=opengles3`, `MOBILEGL_BACKEND_TYPE=DirectGLES`, plus `MOBILEGL_TRANSPORT=inproc` in an `inproc` build (see below) |
|
||||
| `fclPlugin_V2` | launchers that read the v2 renderer-plugin format | The same environment plus user options: backend (`DirectGLES`/`DirectVulkan`), frames in flight, and toggles for `MOBILEGL_DISABLE_TIMERQUERY`, `MOBILEGL_MAGMA_DISABLE_SUBGROUP`, `MOBILEGL_MAGMA_R11G11B10F_FALLBACK`, `MOBILEGL_ESPRYT_AVOID_SAMPLER_MIPMAP_MIN_FILTER`, `MOBILEGL_COHERENT_AS_FLUSH`, `MOBILEGL_RELAXED_SEMANTICS`, `MOBILEGL_ESPRYT_USE_ANGLE` |
|
||||
|
||||
The FCL build this guide was checked against reads only the original format, so it shows no plugin
|
||||
options and always starts the plugin with Espryt. To change anything there, use FCL's
|
||||
**Environment Variables** editor (applied after the plugin's variables), for example:
|
||||
|
||||
```text
|
||||
MOBILEGL_BACKEND_TYPE=DirectVulkan
|
||||
```
|
||||
|
||||
The `debug.mobilegl.*` properties described in [android-fcl.md](android-fcl.md#other-settings) also
|
||||
work for the plugin. One more exists for split builds: `debug.mobilegl.transport` overrides
|
||||
`MOBILEGL_TRANSPORT`.
|
||||
|
||||
## In-process split (`inproc`)
|
||||
|
||||
With `MOBILEGL_TRANSPORT=inproc`, the GL frontend runs on the game's thread and the backend runs on
|
||||
a second thread. On a CPU-bound game this can raise the frame rate; it costs up to one extra frame of
|
||||
latency.
|
||||
|
||||
The plugin's launcher environment includes `MOBILEGL_TRANSPORT=inproc` **only if** the APK was built
|
||||
with `-Pmobilegl.buildDisaggregated=ON` or `-Pmobilegl.buildDisaggregatedInproc=ON` passed explicitly
|
||||
(the CI build of `feat/disaggregated` does this). A plain `gradle :app:assemblePluginRelease`
|
||||
still builds the split layer into the library, but the launcher environment then omits the transport
|
||||
and the plugin runs monolith. Either rebuild with the property, or add
|
||||
`MOBILEGL_TRANSPORT=inproc` in the launcher's environment editor.
|
||||
|
||||
Check the log for:
|
||||
|
||||
```text
|
||||
Config: MOBILEGL_TRANSPORT=inproc - the MGPipe record stream crosses a real ring to an apply thread
|
||||
```
|
||||
|
||||
## The render server
|
||||
|
||||
Open the MobileGL app and switch to the **Render Server** tab. It starts one of two servers:
|
||||
|
||||
| Mode | Component | Process | What it is for |
|
||||
|---|---|---|---|
|
||||
| Offscreen (default) | `MobileGLServerService` (foreground service) running `libMobileGLServer.so <endpoint> --serve` | `:mglsrv` | Remote clients over TCP, offscreen (pbuffer) programs, same-device programs through the broker |
|
||||
| On-screen (tick **On-screen window**) | `MobileGLDisplayActivity`, a full-screen Activity with an in-process server | `:mglwin` | Clients that set `MOBILEGL_IPC_SURFACE=server`: their window surface is drawn into this Activity |
|
||||
|
||||
Fields:
|
||||
|
||||
| Field | Default | Notes |
|
||||
|---|---|---|
|
||||
| Listen endpoint | `tcp://0.0.0.0:40613` | `tcp://host:port`, `@name` (abstract Unix socket) or a file path (relative paths resolve against the app's files directory) |
|
||||
| Auth token | empty | Clients present it as `MOBILEGL_IPC_TOKEN`. A TCP listen on a non-loopback address (including `0.0.0.0`) **requires** a token of at least 16 bytes; without a token, use `tcp://127.0.0.1:<port>`. **Generate token** makes a random one. |
|
||||
| Extra env | empty | `KEY=VALUE;KEY` list for the server process (`KEY` alone unsets). For example `MOBILEGL_BACKEND_TYPE=DirectVulkan` pins the server's backend. |
|
||||
|
||||
Only one server runs at a time: starting one stops the other. The plugin flavor does not export these
|
||||
components, so other apps and `adb` cannot start them by component name; use the screen.
|
||||
|
||||
Backend selection: the client's `MOBILEGL_BACKEND_TYPE` decides the backend for its session. A
|
||||
server started with `MOBILEGL_BACKEND_TYPE` in its extra env refuses clients that ask for the other
|
||||
backend. The on-screen server keeps the first session's backend for its whole process lifetime; to
|
||||
switch, stop the server and start it again.
|
||||
|
||||
Server logs go to logcat (tags `MobileGL`, `MobileGLServer`, `MobileGLDisplay`) and to
|
||||
`mgl.server.log` (offscreen) or `mglwin.server.log` (on-screen) in the app's private files directory.
|
||||
|
||||
## Out-of-process rendering with a window
|
||||
|
||||
A spawned server process has no display, and an Android client's window cannot be passed to another
|
||||
process. So a windowed app (a launcher's Minecraft, for example) can render out of process only into
|
||||
a window the **server** owns: the plugin's on-screen display server.
|
||||
|
||||
Without that, a `spawn` client that creates a window surface fails. With the default
|
||||
`MOBILEGL_IPC_SURFACE=offscreen`, the server rejects the window with
|
||||
`Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"}`. With `MOBILEGL_IPC_SURFACE=server` and an
|
||||
offscreen server, the client logs `Refuse ServerOwned (NoServerDisplay)`.
|
||||
|
||||
Steps (client in FCL, server in the plugin, same device):
|
||||
|
||||
1. In the MobileGL app, **Render Server** tab: set **Listen endpoint** to
|
||||
`tcp://127.0.0.1:40613`, leave the token empty, tick **On-screen window**, tap **Start server**.
|
||||
A black full-screen window appears; this is the display server.
|
||||
2. In FCL, select the **MobileGL** plugin renderer. The FCL-embedded MobileGL entries cannot do
|
||||
this, because they are built without the split layer.
|
||||
3. In FCL's **Environment Variables** editor, add:
|
||||
|
||||
```text
|
||||
MOBILEGL_TRANSPORT=spawn
|
||||
MOBILEGL_IPC_CONTROL=tcp://127.0.0.1:40613
|
||||
MOBILEGL_IPC_SURFACE=server
|
||||
```
|
||||
|
||||
If the server has a token, also add `MOBILEGL_IPC_TOKEN=<token>`.
|
||||
4. Launch the game. Its frames are drawn into the display server's window, at the size the game
|
||||
asks for, letterboxed to the screen.
|
||||
|
||||
Limits:
|
||||
|
||||
- The display window only shows frames. It has no input handling: touch and keys go to whichever
|
||||
window has focus.
|
||||
- The display window must be visible when the game creates its window surface. Otherwise the client
|
||||
logs `Refuse ServerOwned (NoServerWindow)`. If the display window goes away while a game renders
|
||||
into it, that session ends with a device loss. The server keeps listening, and the next session
|
||||
renders when the window is back.
|
||||
- Use this setup to test out-of-process rendering. For normal play, monolith or `inproc` is faster
|
||||
and simpler.
|
||||
- A known open issue: each run logs `MG_Remote server: shared image 1 could not be sent on the aux
|
||||
socket (rc=3)`. Rendering continues.
|
||||
|
||||
How to tell it works: the client log has
|
||||
`MG_Remote client: control=tcp data=stream server=127.0.0.1:40613 ... dial=connect`, and the
|
||||
server's logcat has `listening on tcp://127.0.0.1:40613 (in-process display server, display installed)`.
|
||||
|
||||
## TCP server for remote clients
|
||||
|
||||
The phone renders; a client on another machine sends GL commands over TCP. The client must be a
|
||||
split build of the **same commit** (see [linux.md](linux.md#tcp-client)). Only window surfaces the
|
||||
client presents itself (Linux X11/Wayland windows) or offscreen surfaces work this way.
|
||||
|
||||
1. Find the phone's address:
|
||||
|
||||
```sh
|
||||
adb shell ip -f inet addr show wlan0
|
||||
```
|
||||
|
||||
2. In the **Render Server** tab: endpoint `tcp://0.0.0.0:40613`, tap **Generate token**, keep
|
||||
**On-screen window** unticked, tap **Start server**.
|
||||
3. On the client, set `MOBILEGL_TRANSPORT=spawn`, `MOBILEGL_IPC_CONTROL=tcp://<phone-ip>:40613` and
|
||||
`MOBILEGL_IPC_TOKEN=<token>`.
|
||||
|
||||
If the network isolates devices, tunnel over adb instead: start the server on
|
||||
`tcp://127.0.0.1:40613` (no token needed), then on the client machine run the command below and
|
||||
point the client at `tcp://127.0.0.1:40613`:
|
||||
|
||||
```sh
|
||||
adb forward tcp:40613 tcp:40613
|
||||
```
|
||||
|
||||
## Same-device programs outside the app (Termux, `adb shell`)
|
||||
|
||||
Android does not let another app connect to the plugin's sockets directly. The plugin ships a broker
|
||||
for this case: a helper class, run with `app_process` under the program's own user, asks the plugin
|
||||
for a connected socket pair and then starts the program with it.
|
||||
|
||||
1. Start the **offscreen** server with a token of at least 16 bytes (**Generate token**).
|
||||
2. Tap **Copy launch command**. It produces a line of this form:
|
||||
|
||||
```sh
|
||||
MOBILEGL_IPC_TOKEN='<token>' CLASSPATH=<plugin APK path> app_process / top.mobilegl.plugin.ExternalClientHelper -- <program> [args...]
|
||||
```
|
||||
|
||||
3. Run it with your program. The program must use a split build of MobileGL built for Android
|
||||
(bionic). The helper starts it with `MOBILEGL_TRANSPORT=spawn`,
|
||||
`MOBILEGL_IPC_CONTROL=fd:<control>,<aux>` and `MOBILEGL_IPC_DATA=shm` already set.
|
||||
|
||||
Helper options: `--server <package>` (default: the APK it was loaded from), `--timeout-ms <n>`
|
||||
(default 10000), `--keep-affinity` (do not keep the program off the server's reserved CPU core). The
|
||||
token can also come from a file named by `MOBILEGL_IPC_TOKEN_FILE`; never put it on the command line.
|
||||
The program renders offscreen: the offscreen server has no display.
|
||||
|
||||
## Embedding the server in your own APK
|
||||
|
||||
An app can host the server itself instead of using the plugin. The C interface is
|
||||
`MobileGL/MG_Remote/Server/EmbeddedServer.h` (plain C types, also reachable through `dlsym`); the
|
||||
library must be a split build.
|
||||
|
||||
1. Before loading `libMobileGL.so`, set `MOBILEGL_IPC_ROLE=server` and `MOBILEGL_IPC_DIAL=no`, and
|
||||
unset `MOBILEGL_TRANSPORT`, `MOBILEGL_IPC_SERVER_PATH`, `MOBILEGL_IPC_RING_MB` and
|
||||
`MOBILEGL_IPC_STAGE_MB`. Running the server in its own process keeps a GPU fault away from your UI.
|
||||
2. For a windowed server, call `mobilegl_server_display_install_android(callback, user)`, then
|
||||
`mobilegl_server_display_attach_android(window, width, height)` with the `ANativeWindow` of your
|
||||
`Surface`, and `mobilegl_server_display_detach(timeout_ms)` when the surface is destroyed.
|
||||
3. Call `mobilegl_server_serve_inprocess("<endpoint>")` on a thread of its own (it blocks). Stop it
|
||||
with `mobilegl_server_stop_inprocess()`, then `mobilegl_server_display_uninstall(timeout_ms)`.
|
||||
|
||||
Clients connect with `MOBILEGL_TRANSPORT=spawn`, `MOBILEGL_IPC_CONTROL=unix:@<name>` (or `tcp://...`)
|
||||
and, for the windowed server, `MOBILEGL_IPC_SURFACE=server`. The anland Linux-container setup uses
|
||||
exactly this interface ([linux.md](linux.md#the-anland-setup)). For more offscreen clients at the same
|
||||
time, package `libMobileGLServer.so` and run it as
|
||||
`libMobileGLServer.so @<name> --serve --max-sessions <1-64>` from your own service.
|
||||
`MobileGLServerService.java` and `ServerEnvironment.java` in `android-plugin/` are working examples.
|
||||
|
||||
## The trace flavor
|
||||
|
||||
`assembleTraceRelease` builds `top.mobilegl.plugin.trace`, a development APK that replays recorded GL
|
||||
traces and exports the server components so that `adb` can start them by name. It is not a renderer
|
||||
plugin. See `android-plugin/TRACE_REPLAY.md`.
|
||||
@@ -0,0 +1,200 @@
|
||||
# Building MobileGL
|
||||
|
||||
MobileGL builds with CMake (all platforms) and with Gradle for the Android packages. It is C++23.
|
||||
The commands below come from the project's CI workflows (`.github/workflows/test.yml` and
|
||||
`apk.yml`), which build these exact shapes.
|
||||
|
||||
## Get the sources
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MobileGL-Dev/MobileGL.git
|
||||
```
|
||||
|
||||
```sh
|
||||
git -C MobileGL submodule update --init --recursive
|
||||
```
|
||||
|
||||
glslang needs its external sources (SPIRV-Tools and SPIRV-Headers) fetched once:
|
||||
|
||||
```sh
|
||||
cd MobileGL/3rdparty/glslang && python3 update_glslang_sources.py
|
||||
```
|
||||
|
||||
Without this step, configuring fails with a message that SPIR-V tools were not found.
|
||||
|
||||
Large trace fixtures in the repository are stored with Git LFS. You do not need them to build. If
|
||||
cloning or adding a worktree fails while fetching them, set `GIT_LFS_SKIP_SMUDGE=1`.
|
||||
|
||||
## Toolchains
|
||||
|
||||
| Target | Compiler | Other tools |
|
||||
|---|---|---|
|
||||
| Linux | Clang (CI: clang 20 with lld). The test and benchmark targets require Clang. | CMake 3.22.1 or newer (CI pins **3.31.10**), Ninja, Python 3, Vulkan development files, EGL and GLES development headers (Ubuntu: `libvulkan-dev libegl-dev libgles-dev`). For the GBM module: `gbm.h` and `gbm_backend_abi.h` from your distribution's GBM development package. |
|
||||
| Android | NDK `27.3.13750724` (the version Gradle pins) | JDK 17, Gradle (CI: 8.10.2; the plugin uses Android Gradle Plugin 8.6.0), Android SDK platform 34, the SDK's CMake `3.22.1` |
|
||||
| Windows | MSVC (Visual Studio 2022). See the build status note in [windows.md](windows.md). | CMake, Python 3, Vulkan SDK |
|
||||
|
||||
The minimum Android API level is **26**. Configuring for a lower level is an error; a higher level is
|
||||
allowed, but the code must not use newer APIs. A separate API 29 build is planned and not available
|
||||
yet.
|
||||
|
||||
## Linux
|
||||
|
||||
Shipping-style monolith library:
|
||||
|
||||
```sh
|
||||
cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DMOBILEGL_BUILD_TEST=OFF -DMOBILEGL_BUILD_BENCHMARK=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
```
|
||||
|
||||
```sh
|
||||
cmake --build build --target MobileGL
|
||||
```
|
||||
|
||||
Split build (`inproc`, `spawn`, TCP; adds the server executable and the GBM module):
|
||||
|
||||
```sh
|
||||
cmake -S . -B build-split -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DMOBILEGL_BUILD_TEST=OFF -DMOBILEGL_BUILD_BENCHMARK=OFF -DMOBILEGL_BUILD_DISAGGREGATED=ON -DMOBILEGL_BUILD_DISAGGREGATED_INPROC=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
```
|
||||
|
||||
```sh
|
||||
cmake --build build-split --target MobileGL MobileGLServer mobilegl_gbm
|
||||
```
|
||||
|
||||
Drop `mobilegl_gbm` from the target list if configure printed
|
||||
`gbm.h / gbm_backend_abi.h not found, mobilegl_gbm is not built`.
|
||||
|
||||
`-DCMAKE_POLICY_VERSION_MINIMUM=3.5` is what CI passes. It is required only when configuring with
|
||||
CMake 4.x, which refuses some submodules' old minimum versions.
|
||||
|
||||
For an aarch64 Linux target (for example a Linux container on an Android device), cross-compile with
|
||||
your own CMake toolchain file and a sysroot of the target distribution (`--toolchain <file>`); there is
|
||||
nothing MobileGL-specific about it. Build the client with `MOBILEGL_BUILD_DISAGGREGATED=ON`.
|
||||
|
||||
### Tests
|
||||
|
||||
Tests need Clang. Configure without the `MOBILEGL_BUILD_TEST=OFF` /
|
||||
`MOBILEGL_BUILD_BENCHMARK=OFF` options (both default to `ON`; configure then downloads googletest and
|
||||
Google Benchmark), build everything, and run the unit label. Use **CMake 3.31.x** for this: CI pins
|
||||
3.31.10, because the test registrations carry escaped environment and label lists that newer CMake
|
||||
releases handle differently. Under CMake 4.x, tests can start with the wrong environment.
|
||||
|
||||
```sh
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
```sh
|
||||
ctest --test-dir build --output-on-failure -L unit
|
||||
```
|
||||
|
||||
GPU integration tests need `-DMOBILEGL_BUILD_INTEGRATION_TEST=ON` and a working GPU driver. Their
|
||||
label is `integration-gpu`. Do not run two `ctest` suites at the same time.
|
||||
|
||||
## Android: direct CMake (NDK)
|
||||
|
||||
For embedding the library in your own app, or for the server of an app that hosts one:
|
||||
|
||||
```sh
|
||||
cmake -S . -B build-android -G Ninja -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-26 -DCMAKE_BUILD_TYPE=Release -DMOBILEGL_BUILD_DISAGGREGATED=ON -DMOBILEGL_BUILD_DISAGGREGATED_INPROC=ON
|
||||
```
|
||||
|
||||
```sh
|
||||
cmake --build build-android --target MobileGL MobileGLServer
|
||||
```
|
||||
|
||||
Tests and benchmarks are always off on Android. Package `libMobileGL.so` (and, if you run the
|
||||
offscreen server, `libMobileGLServer.so`) under the APK's `lib/arm64-v8a/`. `libMobileGLServer.so`
|
||||
is an executable with a library name, because that is the only place in an APK from which Android
|
||||
lets an app run executables. Extract native libraries at install time
|
||||
(`useLegacyPackaging = true`) so it exists on disk.
|
||||
|
||||
## Android plugin APK
|
||||
|
||||
The Gradle project is `android-plugin/` (root project `MobileGLPlugin`, modules `:app` and
|
||||
`:MobileGL`, which is the repository root). It has no Gradle wrapper; use a Gradle installation
|
||||
(CI uses 8.10.2). The build needs network access to Google's Maven repository, Maven Central and
|
||||
`jitpack.io` (for the renderer-plugin build DSL).
|
||||
|
||||
`android-plugin/local.properties` (or `ANDROID_HOME`) must name the SDK. If the NDK or the SDK's CMake
|
||||
is missing:
|
||||
|
||||
```sh
|
||||
sdkmanager "ndk;27.3.13750724" "cmake;3.22.1"
|
||||
```
|
||||
|
||||
Release build, with `inproc` in the launcher environment (the same command CI runs):
|
||||
|
||||
```sh
|
||||
gradle -p android-plugin :app:assemblePluginRelease -Pmobilegl.buildDisaggregated=ON -Pmobilegl.buildDisaggregatedInproc=ON
|
||||
```
|
||||
|
||||
Output: `android-plugin/app/build/outputs/apk/plugin/release/MobileGL-plugin-release-<git-hash>.apk`.
|
||||
|
||||
A debug build, debug-signed and installable as is:
|
||||
|
||||
```sh
|
||||
gradle -p android-plugin :app:assemblePluginDebug -Pmobilegl.buildDisaggregated=ON
|
||||
```
|
||||
|
||||
Its file is also named `MobileGL-plugin-release-<git-hash>.apk`, but it is in `.../apk/plugin/debug/`.
|
||||
|
||||
### Signing
|
||||
|
||||
A release APK is signed only when `android-plugin/keystore.jks` exists **and** the environment
|
||||
variables `SIGNING_STORE_PASSWORD`, `SIGNING_KEY_ALIAS` and `SIGNING_KEY_PASSWORD` are set (they belong
|
||||
to the project's own key). Otherwise the release APK is unsigned; sign it with your own key:
|
||||
|
||||
```sh
|
||||
apksigner sign --ks my-release.jks --out MobileGL-plugin-signed.apk MobileGL-plugin-release-<git-hash>.apk
|
||||
```
|
||||
|
||||
### FCL-embedded library
|
||||
|
||||
When MobileGL is a module of an FCL build (see [android-fcl.md](android-fcl.md)), FCL's Gradle build
|
||||
compiles it. The same `mobilegl.*` properties apply when passed to FCL's Gradle; the differences from
|
||||
the plugin are in the table below.
|
||||
|
||||
## Gradle properties
|
||||
|
||||
Pass with `-P<name>=<value>`. Some can also come from an environment variable.
|
||||
|
||||
| Property | Env fallback | Default | Effect |
|
||||
|---|---|---|---|
|
||||
| `mobilegl.enableLto` | `MOBILEGL_ENABLE_LTO` | `ON` | ThinLTO and `-O3` for the native library. `OFF` builds faster. |
|
||||
| `mobilegl.buildDisaggregated` | `MOBILEGL_BUILD_DISAGGREGATED` | plugin: `ON`; FCL-embedded: `OFF` | Build the split layer and the server. In the plugin, passing it explicitly as `ON` also adds `MOBILEGL_TRANSPORT=inproc` to the launcher environment. |
|
||||
| `mobilegl.buildDisaggregatedInproc` | `MOBILEGL_BUILD_DISAGGREGATED_INPROC` | follows `mobilegl.buildDisaggregated` | Implies the above; the same launcher-environment effect. |
|
||||
| `mobilegl.abis` | `MOBILEGL_ABIS` | `arm64-v8a` | Comma-separated ABIs, or `all` (= `arm64-v8a,x86_64`). Plugin only; the FCL-embedded build is always arm64-v8a. |
|
||||
| `mobilegl.logLevel` | `MOBILEGL_LOG_ACTIVE_LEVEL` | `MOBILEGL_LOG_LEVEL_INFO` | Lowest log level compiled in: `MOBILEGL_LOG_LEVEL_DEBUG`, `_INFO`, `_WARN`, `_ERROR`, `_FATAL` |
|
||||
| `mobilegl.cmakeCompilerLauncher` | `MOBILEGL_CMAKE_COMPILER_LAUNCHER` | none | Compiler launcher, for example `ccache` |
|
||||
| `mobilegl.applicationIdSuffix` | | none | Suffix for the plugin's application ID, to install next to another copy |
|
||||
| `mobilegl.apkSuffix` | `MOBILEGL_APK_SUFFIX` | git short hash | Suffix in the APK file name |
|
||||
| `mobilegl.debuggableRelease` | | `false` | Make the release build debuggable |
|
||||
|
||||
Prefer the `-P` form for `mobilegl.buildDisaggregated`: the plugin's two Gradle scripts read the
|
||||
environment fallback differently.
|
||||
|
||||
## CMake options
|
||||
|
||||
| Option | Default | Effect |
|
||||
|---|---|---|
|
||||
| `MOBILEGL_BUILD_DISAGGREGATED` | `OFF` | Build the split layer (`inproc`, `spawn`, TCP), the server executable `libMobileGLServer.so` (not on Windows) and, on Linux, the shared-image API and `mobilegl_gbm.so`. Needs the `3rdparty/flatbuffers` submodule; without it the option is turned off with a warning. |
|
||||
| `MOBILEGL_BUILD_DISAGGREGATED_INPROC` | `OFF` | Implies `MOBILEGL_BUILD_DISAGGREGATED`. CI and Gradle set both. |
|
||||
| `MOBILEGL_ENABLE_LTO` | `OFF` | ThinLTO (or the compiler's IPO) plus `-O3`, section garbage collection and identical-code folding. Gradle turns it on. |
|
||||
| `MOBILEGL_FORCE_RELEASE_OPT` | `ON` | Apply the `MOBILEGL_ENABLE_LTO` flags in Debug builds too. Has no effect without `MOBILEGL_ENABLE_LTO=ON`. |
|
||||
| `MOBILEGL_LOG_ACTIVE_LEVEL` | `MOBILEGL_LOG_LEVEL_INFO` | Lowest log level compiled in |
|
||||
| `MOBILEGL_BUILD_TEST` | `ON` (forced `OFF` on Android) | Unit tests (Clang only) |
|
||||
| `MOBILEGL_BUILD_BENCHMARK` | `ON` (forced `OFF` on Android) | Benchmarks (Clang only) |
|
||||
| `MOBILEGL_BUILD_INTEGRATION_TEST` | `OFF` | GPU integration tests |
|
||||
| `MOBILEGL_BUILD_TRACE_REPLAY` | `OFF` | apitrace replay runner (needs the `3rdparty/apitrace` submodule) |
|
||||
| `MOBILEGL_ENABLE_TRACY` | `OFF` | Tracy profiler |
|
||||
| `MOBILEGL_BUILD_STAMP` | empty (git commit) | Build identity used by the client/server handshake when `git rev-parse HEAD` does not work in the source tree |
|
||||
|
||||
## Artifacts
|
||||
|
||||
| Build | Files |
|
||||
|---|---|
|
||||
| Linux | `libMobileGL.so`, `libMobileGL_s.a`, symlinks `libEGL.so`, `libEGL.so.1`, `libGL.so`, `libGL.so.1`, `libGLX_mobilegl.so.0`; split: `libMobileGLServer.so`, `MobileGL/MG_Gbm/mobilegl_gbm.so` |
|
||||
| Windows | `MobileGL.dll`, `opengl32.dll` (a copy), `MobileGL_s.lib` |
|
||||
| Android (CMake) | `libMobileGL.so`; split: `libMobileGLServer.so` |
|
||||
| Android (Gradle) | `MobileGL-plugin-release-<hash>.apk` (plugin flavor), `MobileGL-plugin-trace-release-<hash>.apk` (trace flavor, development only) |
|
||||
|
||||
Client and server talk only if they come from the same source revision (the wire layout must match;
|
||||
for a different build of a compatible wire, the client logs a warning). Build both ends from one commit.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Configuration
|
||||
|
||||
MobileGL is configured with `MOBILEGL_*` variables. This page lists the ones meant for users.
|
||||
Variables that exist for development, CI and benchmarking (`MOBILEGL_PIPE_*`, most `MOBILEGL_IPC_*`
|
||||
tuning knobs, quirk overrides) are left out on purpose. Some of them are negative controls that
|
||||
break rendering by design.
|
||||
|
||||
## Where settings come from
|
||||
|
||||
Settings are read once, when the library initializes in a process. Changing them later has no effect
|
||||
until the process restarts.
|
||||
|
||||
| Source | Platform | Precedence |
|
||||
|---|---|---|
|
||||
| `debug.mobilegl.backend` property | Android | Overrides `MOBILEGL_BACKEND_TYPE` from every other source |
|
||||
| `debug.mobilegl.transport` property | Android, split builds | Overrides `MOBILEGL_TRANSPORT` from every other source |
|
||||
| Process environment | all | Highest for everything else |
|
||||
| `/etc/mobilegl/backend` (one line: the backend name) | desktop Linux | Below the environment; `MOBILEGL_BACKEND_TYPE` only |
|
||||
| `/etc/mobilegl/client.conf` (`KEY=value` lines) | desktop Linux | Below the backend file |
|
||||
| `debug.mobilegl.env` property (`KEY=VALUE;KEY=VALUE`, at most 91 characters) | Android | Below the environment |
|
||||
| Built-in default | all | Lowest |
|
||||
|
||||
- Only keys starting with `MOBILEGL_` or `LIBGL_` are accepted from the environment and from
|
||||
`client.conf`.
|
||||
- `MOBILEGL_CONFIG_FILE` and `MOBILEGL_BACKEND_FILE` name other files instead of the two `/etc`
|
||||
files; an empty value turns a file off.
|
||||
- A server process (`MOBILEGL_IPC_ROLE=server`) reads neither file nor `debug.mobilegl.env`.
|
||||
- Settings marked **env only** below are read straight from the process environment. They ignore the
|
||||
files and `debug.mobilegl.env`.
|
||||
- On Android, use `adb shell setprop <property> <value>` (no root needed). Properties apply to every
|
||||
app on the device that loads MobileGL, and last until reboot.
|
||||
|
||||
Value rules:
|
||||
|
||||
- **Flag**: on when set to anything other than empty, `0` or `false` (case-insensitive).
|
||||
- **Auto/on/off**: unset keeps the built-in choice; a flag-true value forces it on; anything else
|
||||
forces it off.
|
||||
- **Integer**: a value outside the range is ignored with a warning in the log, and the default is used.
|
||||
|
||||
Where a setting takes effect: each process reads its own settings. When you connect to a server that
|
||||
was started separately (the plugin's render server, a Linux server), the backend settings
|
||||
(`MOBILEGL_ESPRYT_*`, `MOBILEGL_MAGMA_*`, `MOBILEGL_FRAMES_IN_FLIGHT`) belong in the **server's**
|
||||
environment too. The backend itself is the exception: the client asks for it (see
|
||||
`MOBILEGL_BACKEND_TYPE`).
|
||||
|
||||
## Backend and general
|
||||
|
||||
| Variable | Values | Default | Meaning |
|
||||
|---|---|---|---|
|
||||
| `MOBILEGL_BACKEND_TYPE` | `DirectGLES`, `DirectVulkan` | `DirectGLES` | Espryt (GLES) or Magma (Vulkan). Case-sensitive. Any other value leaves MobileGL without a backend. In a split session the client's value is sent to the server, which uses it unless the server pinned a different one. |
|
||||
| `MOBILEGL_FRAMES_IN_FLIGHT` | 1-64 | 3 | How many frames may be queued ahead of the GPU. Magma: its frame contexts. Espryt: after presenting frame N it waits for frame N+1-value to finish (1 = full CPU/GPU sync). Split topologies: the client may run `max(1, value - 2)` presents ahead of the server, so 4 gives one more frame of overlap (and of latency). The old name `MOBILEGL_MAGMA_FRAMESINFLIGHT` still works but is deprecated. |
|
||||
| `MOBILEGL_RELAXED_SEMANTICS` | flag | off | Apply legacy leniencies (for example drawing with vertex array object 0, reusing texture names after delete) even to contexts that explicitly requested a core profile. Contexts that did not request core get them anyway. |
|
||||
| `MOBILEGL_ADVERTISE_FP64` | flag | off | Advertise `GL_ARB_gpu_shader_fp64`. `double` types compile either way but run at 32-bit precision. |
|
||||
| `MOBILEGL_DISABLE_TIMERQUERY` | flag | off | Hide and disable GPU timer queries |
|
||||
| `MOBILEGL_COHERENT_AS_FLUSH` | flag | off | Treat persistent maps with `GL_MAP_FLUSH_EXPLICIT_BIT` as coherent, for engines that never flush them |
|
||||
| `MOBILEGL_ASYNC_SHADER_COMPILE` | auto/on/off | on | Compile and link shaders on worker threads. Off runs them on the calling thread and withdraws `GL_KHR_parallel_shader_compile`. |
|
||||
| `MOBILEGL_ASYNC_SHADER_COMPILE_THREADS` | 0-64 | 0 | Worker count; 0 = min(4, number of big cores) |
|
||||
| `MOBILEGL_SHADER_CACHE` | auto/on/off | on | In-memory shader translation cache. Turn it off to rule it out when a shader renders wrongly. |
|
||||
| `MOBILEGL_ES_CONTEXT_IDENTITY` | `1` | off | **env only.** Contexts created for the OpenGL ES API report themselves as OpenGL ES 3.2 instead of the desktop version |
|
||||
|
||||
## Espryt (DirectGLES)
|
||||
|
||||
| Variable | Values | Default | Meaning |
|
||||
|---|---|---|---|
|
||||
| `MOBILEGL_ESPRYT_USE_ANGLE` | flag | off | Load `libEGL_angle.so` / `libGLESv2_angle.so` instead of the system EGL/GLES. Not used on Windows, where Espryt always loads ANGLE's `libEGL.dll` / `libGLESv2.dll`. |
|
||||
| `MOBILEGL_ESPRYT_AVOID_SAMPLER_MIPMAP_MIN_FILTER` | flag | off | Avoid mipmap minification filters in samplers (a workaround for certain driver bugs) |
|
||||
| `MOBILEGL_YUV_DRIVER_CONVERSION` | `1` | off | **env only.** Convert YUV images with the driver's external-sampler conversion instead of MobileGL's own |
|
||||
|
||||
## Magma (DirectVulkan)
|
||||
|
||||
| Variable | Values | Default | Meaning |
|
||||
|---|---|---|---|
|
||||
| `MOBILEGL_MAGMA_DISABLE_SUBGROUP` | flag | off | Do not use Vulkan subgroup operations in shaders |
|
||||
| `MOBILEGL_MAGMA_R11G11B10F_FALLBACK` | flag | off | Use a fallback format for `GL_R11F_G11F_B10F` |
|
||||
| `MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER` | 0-16777216 | 16384 | Submit a command buffer mid-frame after this many draws/dispatches (0 = never). Bounds driver memory in huge loading frames. |
|
||||
| `MOBILEGL_MAGMA_DESCRIPTOR_TRIM_FRAMES` | 0-1048576 | 120 | Free grown descriptor pools after this many quiet frames (0 = never) |
|
||||
| `VK_ICD_FILENAMES` | path to an ICD JSON | loader default | Standard Vulkan loader variable: picks the Vulkan driver |
|
||||
|
||||
## Logging and diagnostics
|
||||
|
||||
| Variable | Values | Default | Meaning |
|
||||
|---|---|---|---|
|
||||
| `MOBILEGL_LOG_FILE_PATH` | path | Android: `/sdcard/MG/latest.log`; elsewhere none | **env only.** Log file. Split builds write `<name>.client<ext>` and `<name>.server<ext>` instead (for example `latest.client.log`); in a client, `.server` receives the lines the server forwards. The file is truncated when opened. On Android, logs also go to logcat with tag `MobileGL`. |
|
||||
| `MOBILEGL_FPS_LOG` | `1` | off | **env only** (Android: also `debug.mobilegl.fps_log`). One line about every two seconds with frame rate and frame time. |
|
||||
| `MOBILEGL_GPU_HANG_BUDGET_MS` | 0-600000 | 2000 | **env only** (Android: also `debug.mobilegl.gpu_hang_budget_ms`). A GPU submission running longer than this ends its session as hung. 0 turns the watchdog off; do that on slow software rasterizers. |
|
||||
|
||||
## Transport (split builds only)
|
||||
|
||||
| Variable | Values | Default | Meaning |
|
||||
|---|---|---|---|
|
||||
| `MOBILEGL_TRANSPORT` | `monolith`, `inproc`, `spawn` | `monolith` | Where the backend runs ([README.md](README.md#topologies-where-the-backend-runs)). `unix:...` / `pipe:...` are rejected (logged, and the run stays monolith); use `MOBILEGL_IPC_CONTROL`. Ignored in builds without the split layer. |
|
||||
| `MOBILEGL_IPC_CONTROL` | `fork`, `unix:<path>`, `unix:@<name>`, `tcp://<host>:<port>` | `fork` | With `spawn`: `fork` launches a private server; the others connect to a running one. (`fd:<a>,<b>` is set by the plugin's external-client helper.) |
|
||||
| `MOBILEGL_IPC_DATA` | `auto`, `shm`, `stream` | `auto` | Data plane. `auto` picks shared memory for Unix sockets and `fork`, and a stream for TCP; TCP accepts only `stream`, the others only `shm`. |
|
||||
| `MOBILEGL_IPC_SURFACE` | `offscreen`, `server` | `offscreen` | `server`: window surfaces are created on the server's own window, and the client's window handle is ignored. Needs a server with a display (the plugin's on-screen server, or an app embedding one). Only meaningful with `spawn`. |
|
||||
| `MOBILEGL_IPC_TOKEN` | string | none | **env only.** Shared secret; client and server must agree. A server listening on a non-loopback TCP address requires one of at least 16 bytes. |
|
||||
| `MOBILEGL_IPC_SERVER_PATH` | path | next to `libMobileGL.so` | Server executable for `fork` |
|
||||
| `MOBILEGL_IPC_PROBE_TIMEOUT_MS` | 0-60000 | 250 | Before starting a session, probe the configured `unix:`/`tcp://` endpoint; if nothing answers, the EGL/GLX/GBM entry points decline so the system's next GL implementation is used. 0 disables the probe. |
|
||||
| `MOBILEGL_IPC_RECOVER` | 0, 1 | 1 | After the server dies or the device is lost, let the next `eglCreateContext` / `eglCreate*Surface` / `eglInitialize` start a fresh session. 0 makes the loss final for the process. |
|
||||
| `MOBILEGL_IPC_CONTROL_TIMEOUT_MS` | 100-600000 | 5000 | How long the client waits for an answer to a surface operation |
|
||||
| `MOBILEGL_IPC_COLD_START_MS` | 100-600000 | 20000 | The same wait while the server brings its backend up (first surface and first make-current) |
|
||||
| `MOBILEGL_IPC_PRESENT_CREDIT` | 1-8 | derived from `MOBILEGL_FRAMES_IN_FLIGHT` | Explicit override of how many presents the client may run ahead |
|
||||
| `MOBILEGL_IPC_REQUIRE_SAME_BUILD` | `1` | off | **env only.** Refuse a server built from a different revision (by default that is a warning) |
|
||||
|
||||
## Server process
|
||||
|
||||
`libMobileGLServer.so` and embedding apps (see [android-plugin.md](android-plugin.md#embedding-the-server-in-your-own-apk)):
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `MOBILEGL_IPC_DIAL=no` | **Required** in the server's environment. It stops the server from acting as a client itself. |
|
||||
| `MOBILEGL_IPC_ROLE=server` | Marks the server role. `libMobileGLServer.so` sets it itself; an embedding app sets it before loading the library. |
|
||||
| `MOBILEGL_IPC_ENDPOINT` | Endpoint, when none is given on the command line |
|
||||
| `MOBILEGL_BACKEND_TYPE` | Optional: pin the server to one backend and refuse clients asking for the other |
|
||||
| `MOBILEGL_IPC_TOKEN` | Token clients must present |
|
||||
| `MOBILEGL_IPC_INPROC_MAX_SESSIONS` | Concurrent sessions of an embedded Unix-socket server (default 16, at most 256) |
|
||||
|
||||
The server refuses to start (exit code 65) if it inherited `MOBILEGL_TRANSPORT`,
|
||||
`MOBILEGL_IPC_SERVER_PATH`, `MOBILEGL_IPC_RING_MB` or `MOBILEGL_IPC_STAGE_MB`.
|
||||
|
||||
## Linux desktop
|
||||
|
||||
| Variable | Meaning |
|
||||
|---|---|
|
||||
| `MOBILEGL_CONFIG_FILE`, `MOBILEGL_BACKEND_FILE` | **env only.** Other config files (default `/etc/mobilegl/client.conf`, `/etc/mobilegl/backend`); empty = none |
|
||||
| `MOBILEGL_DEVICE_DRM_NODE` | Render node reported as MobileGL's EGL device (default `/dev/dri/renderD128`) |
|
||||
| `MOBILEGL_WAYLAND_DMABUF` | **env only.** `0` presents Wayland windows through `wl_shm` instead of dma-bufs |
|
||||
| `MOBILEGL_GLX_PRESENT` | **env only.** `readback`, `shm` or `putimage` forces a GLX readback path instead of DRI3/Present |
|
||||
| `MOBILEGL_X11_DIAL` | **env only.** Override whether MobileGL may open an X11 connection |
|
||||
| `MOBILEGL_GBM_LIBRARY` | **env only.** Where `mobilegl_gbm.so` loads `libMobileGL.so` from |
|
||||
| `__EGL_VENDOR_LIBRARY_FILENAMES`, `__GLX_VENDOR_LIBRARY_NAME`, `GBM_BACKEND` | glvnd / libgbm variables that select MobileGL; see [linux.md](linux.md) |
|
||||
@@ -0,0 +1,256 @@
|
||||
# MobileGL on Linux
|
||||
|
||||
On Linux (glibc), MobileGL builds as `libMobileGL.so`. One library provides:
|
||||
|
||||
- **EGL** for the surfaceless, Wayland and GBM platforms. On GBM it is offscreen only: window
|
||||
surfaces there are refused.
|
||||
- **GLX** for X11.
|
||||
- **glvnd vendor** entry points for both, so the system's `libEGL.so.1` / `libGL.so.1` (libglvnd) can
|
||||
route applications to it.
|
||||
- In split builds, a GBM backend module (`mobilegl_gbm.so`) and the server executable
|
||||
(`libMobileGLServer.so`).
|
||||
|
||||
There are two ways to use it:
|
||||
|
||||
| Setup | When |
|
||||
|---|---|
|
||||
| [Split client](#system-wide-split-client-glvnd-vendor-gbm-backend) talking to a MobileGL server on Android | The main Linux use case: a Linux container on Android (anland) or a Linux PC rendering on a phone's GPU |
|
||||
| [Monolith on a Linux desktop](#monolith-on-a-linux-desktop) | Experimental: running on the desktop's own GLES/Vulkan driver |
|
||||
|
||||
Build instructions: [building.md](building.md#linux).
|
||||
|
||||
## Build outputs
|
||||
|
||||
| File (in the build directory) | Build | Purpose |
|
||||
|---|---|---|
|
||||
| `libMobileGL.so` | always | The library |
|
||||
| `libEGL.so`, `libEGL.so.1`, `libGL.so`, `libGL.so.1`, `libGLX_mobilegl.so.0` | always | Symlinks to `libMobileGL.so`, for direct loading and for glvnd's GLX vendor naming |
|
||||
| `libMobileGLServer.so` | split | The server executable (despite the name, an executable) |
|
||||
| `MobileGL/MG_Gbm/mobilegl_gbm.so` | split, and only if `gbm.h` and `gbm_backend_abi.h` are installed | GBM backend module |
|
||||
|
||||
## Presentation
|
||||
|
||||
Window surfaces are drawn by the backend and then handed to the window system by the client:
|
||||
|
||||
| Window system | Zero-copy path (split client with server-allocated shared images) | Fallback |
|
||||
|---|---|---|
|
||||
| Wayland (`wl_egl_window`) | `zwp_linux_dmabuf_v1` buffers | read back into `wl_shm` buffers |
|
||||
| X11 (GLX) | DRI3 + Present | read back + MIT-SHM `PutImage`, or plain `PutImage` |
|
||||
|
||||
Shared images come from a server that can allocate them; the Android server can. The log names the
|
||||
path chosen:
|
||||
|
||||
```text
|
||||
Wayland: window surface 1280x720 presented through linux-dmabuf shared images (...)
|
||||
glx: window 0x... (...) presented through DRI3+Present shared images (...)
|
||||
```
|
||||
|
||||
`MOBILEGL_WAYLAND_DMABUF=0` forces `wl_shm`; `MOBILEGL_GLX_PRESENT=readback|shm|putimage` forces a
|
||||
GLX readback path.
|
||||
|
||||
## Topologies on Linux
|
||||
|
||||
| `MOBILEGL_TRANSPORT` | `MOBILEGL_IPC_CONTROL` | Meaning |
|
||||
|---|---|---|
|
||||
| unset / `monolith` | | Backend in the application's thread |
|
||||
| `inproc` | | Backend on a second thread (split build) |
|
||||
| `spawn` | unset / `fork` | The client starts its own `libMobileGLServer.so`, found next to `libMobileGL.so` or at `MOBILEGL_IPC_SERVER_PATH` |
|
||||
| `spawn` | `unix:/path` or `unix:@name` | Connect to a running server on a Unix socket (shared-memory data plane) |
|
||||
| `spawn` | `tcp://host:port` | Connect to a running server over TCP (stream data plane) |
|
||||
|
||||
`MOBILEGL_TRANSPORT=unix:...` and `pipe:...` are **not** valid: they log an error and run monolith.
|
||||
Put the endpoint in `MOBILEGL_IPC_CONTROL` instead.
|
||||
|
||||
Client and server must be built from the same source revision. Mismatched wire layouts are refused;
|
||||
otherwise the client logs a `compatible wire with different build` warning.
|
||||
|
||||
## Running a server on Linux
|
||||
|
||||
A Linux server is offscreen only: it has no display of its own, so clients present their windows
|
||||
themselves (table above). `MOBILEGL_IPC_SURFACE=server` is refused by a Linux server.
|
||||
|
||||
The server needs `MOBILEGL_IPC_DIAL=no` in its environment, and must **not** inherit
|
||||
`MOBILEGL_TRANSPORT`, `MOBILEGL_IPC_SERVER_PATH`, `MOBILEGL_IPC_RING_MB` or `MOBILEGL_IPC_STAGE_MB`
|
||||
(it exits with code 64 or 65 otherwise).
|
||||
|
||||
Unix socket, several clients (each session gets its own forked process and backend):
|
||||
|
||||
```sh
|
||||
env -u MOBILEGL_TRANSPORT MOBILEGL_IPC_DIAL=no ./libMobileGLServer.so @mobilegl --serve --max-sessions 16
|
||||
```
|
||||
|
||||
TCP, reachable from other machines (a token of at least 16 bytes is required for any non-loopback
|
||||
address):
|
||||
|
||||
```sh
|
||||
env -u MOBILEGL_TRANSPORT MOBILEGL_IPC_DIAL=no MOBILEGL_IPC_TOKEN=<16+ byte secret> ./libMobileGLServer.so tcp://0.0.0.0:40613 --serve
|
||||
```
|
||||
|
||||
Arguments: `<endpoint>` (or `MOBILEGL_IPC_ENDPOINT`), `--serve` (keep accepting sessions; without it
|
||||
the process serves one session and exits), `--max-sessions <1-64>` (Unix `--serve` only, default 1).
|
||||
The client picks the backend for its session; set `MOBILEGL_BACKEND_TYPE` on the server to pin one.
|
||||
The server prints `MG_Remote server: pid=<pid> listening on <endpoint>` when it is ready.
|
||||
|
||||
## TCP client
|
||||
|
||||
On a Linux machine, run any GL program against a remote server (for example a phone running the
|
||||
plugin's render server, see [android-plugin.md](android-plugin.md#tcp-server-for-remote-clients)):
|
||||
|
||||
```sh
|
||||
MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_CONTROL=tcp://192.168.1.20:40613 MOBILEGL_IPC_TOKEN=<token> MOBILEGL_LOG_FILE_PATH=/tmp/mgl.log __EGL_VENDOR_LIBRARY_FILENAMES=/opt/mobilegl/share/glvnd/egl_vendor.d/50_mobilegl.json eglinfo -B
|
||||
```
|
||||
|
||||
(`eglinfo` and `glxinfo` come with your distribution's GL utilities package; any EGL or GLX program works. The vendor file is
|
||||
described below.) The client writes `/tmp/mgl.client.log`; the server's log lines are forwarded to
|
||||
the client and written to `/tmp/mgl.server.log`. A successful connection logs
|
||||
`MG_Remote client: control=tcp data=stream server=192.168.1.20:40613 ... dial=connect`.
|
||||
|
||||
Every GL object creation, query and readback waits for a network round trip. Expect loading-heavy
|
||||
programs to be slow over Wi-Fi.
|
||||
|
||||
## System-wide split client: glvnd vendor, GBM backend
|
||||
|
||||
This makes MobileGL the GL implementation for every process on the machine, while falling back to the
|
||||
distribution's driver whenever no MobileGL server is reachable. It is how the anland container is set
|
||||
up. Use it only with a split client configuration: in monolith mode MobileGL never declines, so it
|
||||
would take over every EGL application.
|
||||
|
||||
How the fallback works: before a client starts a session, it probes the configured endpoint with one
|
||||
non-blocking connect (bounded by `MOBILEGL_IPC_PROBE_TIMEOUT_MS`, default 250 ms; `0` disables the
|
||||
probe). If nothing answers, the EGL vendor returns `EGL_NO_DISPLAY` and reports no devices, the GLX
|
||||
vendor fails to load, and `mobilegl_gbm` fails `create_device`. libglvnd and libgbm then use the next
|
||||
implementation.
|
||||
|
||||
### Files to install
|
||||
|
||||
Install the library under a directory of its own. Copy to a new file and rename it into place: never
|
||||
overwrite a `.so` that running processes have mapped.
|
||||
|
||||
| Path | Contents |
|
||||
|---|---|
|
||||
| `/opt/mobilegl/lib/libMobileGL.so` | the library |
|
||||
| `/opt/mobilegl/lib/libEGL.so.1`, `libGL.so.1` (and the unversioned names) | optional symlinks to `libMobileGL.so`, for programs started with `LD_LIBRARY_PATH=/opt/mobilegl/lib` |
|
||||
| `/usr/share/glvnd/egl_vendor.d/10_mobilegl.json` | EGL vendor, sorted ahead of the distribution's `50_*.json` |
|
||||
| `/opt/mobilegl/share/glvnd/egl_vendor.d/50_mobilegl.json` | the same JSON, for forcing MobileGL per process with `__EGL_VENDOR_LIBRARY_FILENAMES` |
|
||||
| `<libdir>/libGLX_mobilegl.so.0` | symlink to `/opt/mobilegl/lib/libMobileGL.so`; `<libdir>` is the system library directory (`/usr/lib` on Arch, `/usr/lib/<triplet>` on Debian/Ubuntu) |
|
||||
| `/etc/mobilegl/client.conf` | client settings (below) |
|
||||
| `/etc/mobilegl/backend` | optional: one line, `DirectGLES` or `DirectVulkan` |
|
||||
| `<gbm backend dir>/mobilegl_gbm.so` | GBM backend; the directory libgbm searches (`/usr/lib/gbm` on Arch; `GBM_BACKENDS_PATH` overrides it) |
|
||||
| `/etc/environment.d/10-mobilegl.conf` and `/etc/profile.d/mobilegl.sh` | `__GLX_VENDOR_LIBRARY_NAME=mobilegl` and `GBM_BACKEND=mobilegl` for the systemd user session and login shells |
|
||||
|
||||
The vendor JSON (both copies):
|
||||
|
||||
```json
|
||||
{"file_format_version":"1.0.0","ICD":{"library_path":"/opt/mobilegl/lib/libMobileGL.so"}}
|
||||
```
|
||||
|
||||
`/etc/environment.d/10-mobilegl.conf`:
|
||||
|
||||
```text
|
||||
__GLX_VENDOR_LIBRARY_NAME=mobilegl
|
||||
GBM_BACKEND=mobilegl
|
||||
```
|
||||
|
||||
`/etc/profile.d/mobilegl.sh`:
|
||||
|
||||
```sh
|
||||
export __GLX_VENDOR_LIBRARY_NAME=mobilegl
|
||||
export GBM_BACKEND=mobilegl
|
||||
```
|
||||
|
||||
glvnd picks GLX vendors per X screen, so GLX needs `__GLX_VENDOR_LIBRARY_NAME`; EGL needs only the
|
||||
JSON file.
|
||||
|
||||
### `/etc/mobilegl/client.conf`
|
||||
|
||||
Every process that loads `libMobileGL.so` reads this file. Format: `KEY=value` lines; blank lines
|
||||
and `#` comments are skipped; one pair of matching quotes around a value is removed; only
|
||||
`MOBILEGL_*` and `LIBGL_*` keys are taken. Example for a server on an abstract Unix socket:
|
||||
|
||||
```text
|
||||
MOBILEGL_TRANSPORT=spawn
|
||||
MOBILEGL_IPC_DATA=shm
|
||||
MOBILEGL_IPC_CONTROL=unix:@anland-mobilegl
|
||||
```
|
||||
|
||||
Precedence, highest first: the process environment, then `/etc/mobilegl/backend` (backend only), then
|
||||
`client.conf`, then built-in defaults. `MOBILEGL_CONFIG_FILE=<path>` and
|
||||
`MOBILEGL_BACKEND_FILE=<path>` point at other files; set either to an empty value to disable that
|
||||
file. A server process (`MOBILEGL_IPC_ROLE=server`) reads neither file.
|
||||
|
||||
### Other knobs
|
||||
|
||||
| Variable | Use |
|
||||
|---|---|
|
||||
| `MOBILEGL_DEVICE_DRM_NODE` | DRM render node MobileGL reports as its EGL device (default `/dev/dri/renderD128`). Compositors match it against the node they opened. |
|
||||
| `MOBILEGL_GBM_LIBRARY` | Path `mobilegl_gbm.so` loads `libMobileGL.so` from, if the process has not loaded it already |
|
||||
| `MOBILEGL_X11_DIAL` | Override for whether MobileGL may open an X11 connection (by default it does not dial a display that the process itself serves, such as Xwayland) |
|
||||
|
||||
### How to tell it works
|
||||
|
||||
```sh
|
||||
eglinfo -B
|
||||
```
|
||||
|
||||
```sh
|
||||
glxinfo -B
|
||||
```
|
||||
|
||||
The renderer line names `Espryt (MobileGL Core)` or `Magma (MobileGL Core)` while the server is up,
|
||||
and the distribution's driver while it is down. To see the fallback without stopping the server,
|
||||
point one process at an endpoint nobody listens on:
|
||||
|
||||
```sh
|
||||
sed 's|^MOBILEGL_IPC_CONTROL=.*|MOBILEGL_IPC_CONTROL=unix:@nobody|' /etc/mobilegl/client.conf > /tmp/down.conf
|
||||
```
|
||||
|
||||
```sh
|
||||
MOBILEGL_CONFIG_FILE=/tmp/down.conf eglinfo -B
|
||||
```
|
||||
|
||||
## The anland setup
|
||||
|
||||
anland runs a Linux desktop (for example KDE Plasma in an Arch Linux ARM container) on a rooted
|
||||
Android device. With MobileGL:
|
||||
|
||||
- the anland Android app embeds the MobileGL **server** through the C interface described in
|
||||
[android-plugin.md](android-plugin.md#embedding-the-server-in-your-own-apk): a windowed server whose
|
||||
window is the compositor's Android surface, and offscreen servers for the other applications
|
||||
(`docs/Disaggregated/guide/embedded-server.md` describes both shapes);
|
||||
- inside the container, the **client** library (built for aarch64 glibc with
|
||||
`MOBILEGL_BUILD_DISAGGREGATED=ON`) is installed system-wide exactly as above, with `client.conf`
|
||||
pointing at `unix:@anland-mobilegl`. The container shares the device's network namespace, so the
|
||||
abstract socket is reachable;
|
||||
- Wayland clients present zero-copy through `linux-dmabuf`, and GBM users (the compositor's GBM
|
||||
device, Chromium's GPU process) get MobileGL server images from `mobilegl_gbm.so`.
|
||||
|
||||
The app, its container scripts and the compositor patch belong to the anland project, not to this
|
||||
repository. Build the server library with the Android NDK and the client with an aarch64 glibc cross
|
||||
toolchain ([building.md](building.md)). The developer runbook for this exact setup is
|
||||
`docs/Disaggregated/notes/anland/runbook-plasma.md`.
|
||||
|
||||
## Monolith on a Linux desktop
|
||||
|
||||
The library also runs monolith on a desktop's own driver: Espryt on the system EGL/GLES (it opens
|
||||
`libEGL.so.1`, trying the system library directories first), Magma on the system Vulkan
|
||||
loader. CI runs MobileGL's test binaries and trace replayer this way, on software drivers. Running
|
||||
real applications this way is not covered by CI; treat it as experimental.
|
||||
|
||||
Per process, through glvnd (EGL applications):
|
||||
|
||||
```sh
|
||||
MOBILEGL_BACKEND_TYPE=DirectVulkan MOBILEGL_LOG_FILE_PATH=/tmp/mgl.log __EGL_VENDOR_LIBRARY_FILENAMES=/opt/mobilegl/share/glvnd/egl_vendor.d/50_mobilegl.json eglinfo -B
|
||||
```
|
||||
|
||||
GLX applications (with `libGLX_mobilegl.so.0` installed as above):
|
||||
|
||||
```sh
|
||||
MOBILEGL_BACKEND_TYPE=DirectVulkan __GLX_VENDOR_LIBRARY_NAME=mobilegl glxinfo -B
|
||||
```
|
||||
|
||||
Prefer Magma for EGL applications. Espryt loads the system `libEGL.so.1`, which on a glvnd system is
|
||||
the same dispatcher. When `__EGL_VENDOR_LIBRARY_FILENAMES` lists only MobileGL, that dispatcher can
|
||||
only route Espryt back to MobileGL. This combination has not been verified.
|
||||
|
||||
Without glvnd, start the program with `LD_LIBRARY_PATH` pointing at the build directory, so its
|
||||
`libEGL.so.1`/`libGL.so.1` resolve to MobileGL's symlinks.
|
||||
@@ -0,0 +1,149 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Logs
|
||||
|
||||
The default log level of all builds is INFO: info, warning, error and fatal lines are compiled in.
|
||||
Debug lines need a build with `MOBILEGL_LOG_ACTIVE_LEVEL=MOBILEGL_LOG_LEVEL_DEBUG`
|
||||
(Gradle: `-Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_DEBUG`).
|
||||
|
||||
| Setup | Where |
|
||||
|---|---|
|
||||
| Android, any app | logcat, tag `MobileGL`: `adb logcat -s MobileGL` |
|
||||
| FCL embedded (monolith build) | also `/sdcard/MG/latest.log`, if the process may write there |
|
||||
| Plugin in a launcher (split build) | also `/sdcard/MG/latest.client.log` and `latest.server.log` (the `inproc` backend thread writes the `.server` file) |
|
||||
| Plugin render server | logcat tags `MobileGL`, `MobileGLServer`, `MobileGLDisplay`; files `mgl.server.log` / `mglwin.server.log` in the app's private files directory |
|
||||
| Linux, Windows | only the file named by `MOBILEGL_LOG_FILE_PATH`. Split builds write `<name>.client.<ext>` and `<name>.server.<ext>`; a remote server's lines are forwarded into the client's `.server` file. |
|
||||
|
||||
Native crashes on Android: `adb logcat -b crash -d`.
|
||||
|
||||
Lines worth searching for:
|
||||
|
||||
| Line | Meaning |
|
||||
|---|---|
|
||||
| `Config: Active backend type set to DirectGLES` / `DirectVulkan` | Settings were read; which backend is used |
|
||||
| `Config: debug.mobilegl.env sets ...` | A setting came from the Android property |
|
||||
| `Config: MOBILEGL_TRANSPORT=inproc - ...` / `=spawn - ...` | A split topology was selected |
|
||||
| `MG_Remote client: spawn ARMED - the server role runs in pid N` | `spawn` with `fork` started its own server |
|
||||
| `MG_Remote client: control=tcp data=stream server=...` / `control=unix data=shm ...` | Connected to a running server |
|
||||
| `MG_Remote server: pid=N listening on <endpoint>` | A server is ready |
|
||||
| `Loaded GL backend library: <name>` | Espryt found the system (or ANGLE) EGL/GLES |
|
||||
|
||||
## MobileGL is not used at all
|
||||
|
||||
The renderer string does not mention Espryt or Magma.
|
||||
|
||||
- **FCL:** check the renderer selection, and that no leftover `debug.mobilegl.*` property or line in
|
||||
the Environment Variables editor points somewhere else.
|
||||
- **Windows:** the program loaded the system `opengl32.dll`. Put the copy next to the executable that
|
||||
creates the GL context (for Java, next to `java.exe`/`javaw.exe`).
|
||||
- **Linux, system-wide setup:** the log says
|
||||
`no MobileGL server answers at "<endpoint>" ... declining, so the system's next GL implementation serves this process`.
|
||||
The server is not running or the endpoint in `client.conf` is wrong. `MOBILEGL_IPC_PROBE_TIMEOUT_MS`
|
||||
raises the probe's patience (default 250 ms).
|
||||
- **Linux, GLX:** `__GLX_VENDOR_LIBRARY_NAME=mobilegl` is not set in that process, or
|
||||
`libGLX_mobilegl.so.0` is not in the system library directory.
|
||||
|
||||
## The transport setting has no effect
|
||||
|
||||
- No `Config: MOBILEGL_TRANSPORT=...` line: the library was built without the split layer. The
|
||||
FCL-embedded copy is always built that way; use the plugin or rebuild with
|
||||
`MOBILEGL_BUILD_DISAGGREGATED=ON`.
|
||||
- `Config: MOBILEGL_TRANSPORT='unix:...' names a transport ... staying on monolith`: put the endpoint
|
||||
in `MOBILEGL_IPC_CONTROL` and set `MOBILEGL_TRANSPORT=spawn`.
|
||||
- The plugin runs monolith in the launcher although you expected `inproc`: the APK was built without
|
||||
an explicit `-Pmobilegl.buildDisaggregated=ON`, so its launcher environment has no
|
||||
`MOBILEGL_TRANSPORT`. Rebuild, or add `MOBILEGL_TRANSPORT=inproc` in the launcher's environment
|
||||
editor.
|
||||
|
||||
## Out-of-process rendering on Android
|
||||
|
||||
| Message | Cause | Fix |
|
||||
|---|---|---|
|
||||
| `Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"} ... until then the spawn surface path is pbuffer/surfaceless only` | A `spawn` client created a window surface with `MOBILEGL_IPC_SURFACE=offscreen`. An Android window cannot cross processes. (The text mentions a development phase; the limitation itself is permanent.) | Use the on-screen display server and `MOBILEGL_IPC_SURFACE=server` ([android-plugin.md](android-plugin.md#out-of-process-rendering-with-a-window)), or use `inproc` |
|
||||
| `Refuse ServerOwned (NoServerDisplay)` | `MOBILEGL_IPC_SURFACE=server`, but the server is offscreen (the plugin's service, a spawned server, any Linux server) | Start the plugin's server with **On-screen window** ticked |
|
||||
| `Refuse ServerOwned (NoServerWindow) ... is the display's surface visible?` | The display server's window was not visible when the client created its window surface | Bring the MobileGL display window to the front, then start the game |
|
||||
| `SurfaceModeMismatch` | The session's first surface was a pbuffer, so the session is offscreen; a later server window surface is refused | The application must create its window surface first |
|
||||
|
||||
## Connection refusals
|
||||
|
||||
The client logs `MGPipe: peer Refuse{<code>} <detail> ...`:
|
||||
|
||||
| Code / detail | Fix |
|
||||
|---|---|
|
||||
| `Authentication` `token mismatch` | Set the same `MOBILEGL_IPC_TOKEN` on client and server |
|
||||
| `WireFingerprint` `wire layout` / `ProtocolVersion` | Client and server come from different source revisions; build both from one commit |
|
||||
| `BuildFingerprint` `build identity` | Different builds, and `MOBILEGL_IPC_REQUIRE_SAME_BUILD=1` (or `fork`, which always requires the same build). A stale `libMobileGLServer.so` next to the library, or a stale `MOBILEGL_IPC_SERVER_PATH`, causes this too. |
|
||||
| `Backend` `Hello.backendType disagrees with pinned backend` | The server is pinned to the other backend: by its `MOBILEGL_BACKEND_TYPE`, or, for the on-screen display server, by its first session. Match the client's backend, or restart the server. |
|
||||
| `Busy` | The server takes no more sessions (`--max-sessions`) |
|
||||
|
||||
A warning `compatible wire with different build` means the two ends are different builds of a
|
||||
compatible protocol. It works, but build both ends from one commit when possible.
|
||||
|
||||
## The server does not start
|
||||
|
||||
`libMobileGLServer.so` exit codes:
|
||||
|
||||
| Code | Cause |
|
||||
|---|---|
|
||||
| 64 | `MOBILEGL_IPC_DIAL=no` missing from its environment |
|
||||
| 65 | It inherited `MOBILEGL_TRANSPORT`, `MOBILEGL_IPC_SERVER_PATH`, `MOBILEGL_IPC_RING_MB` or `MOBILEGL_IPC_STAGE_MB`; unset them |
|
||||
| 71 | Bad arguments: no endpoint, an unknown option, or `--max-sessions` outside 1-64 or used with TCP or without `--serve` |
|
||||
| 72 | Could not listen. Also when `MOBILEGL_IPC_TOKEN` is shorter than 16 bytes, or a non-loopback TCP address has no token. The log says `Refuse{Authentication} ...`. |
|
||||
| 73 | Accepting a connection failed or timed out |
|
||||
|
||||
In the plugin's **Render Server** screen:
|
||||
|
||||
- `Non-loopback listen requires a token of at least 16 bytes.`: `0.0.0.0` counts as non-loopback.
|
||||
Tap **Generate token**, or listen on `tcp://127.0.0.1:<port>`.
|
||||
- `A server is already running; stop it before reconfiguring.`: tap **Stop server** first.
|
||||
- The on-screen server keeps its first configuration for the life of its process. To change it, stop
|
||||
it (or force-stop the app) and start again.
|
||||
|
||||
## Device loss and hangs
|
||||
|
||||
- `MOBILEGL_GPU_HANG_BUDGET_MS` (default 2000) ends a session whose GPU submission runs longer than
|
||||
that. Slow software rasterizers trip it; set it to `0` there.
|
||||
- When a server dies or its window goes away, the client's session is lost. With the default
|
||||
`MOBILEGL_IPC_RECOVER=1`, the application's next context or surface creation starts a fresh
|
||||
session; contexts from before the loss stay lost.
|
||||
- A GPU hang caused by one session stalls every GPU user on the device until the kernel resets the GPU
|
||||
(about 2 s, longer in some cases). This is a hardware/driver property, not something MobileGL can
|
||||
shorten.
|
||||
|
||||
## Rendering problems
|
||||
|
||||
- Try the other backend (`MOBILEGL_BACKEND_TYPE`). Backend-specific bugs are common.
|
||||
- Older or non-conformant programs: `MOBILEGL_RELAXED_SEMANTICS=1`.
|
||||
- Engines that write persistent buffer maps without flushing them: `MOBILEGL_COHERENT_AS_FLUSH=1`.
|
||||
- Suspect shader translation: `MOBILEGL_SHADER_CACHE=0` rules out the translation cache.
|
||||
- Magma on a driver with broken subgroup support: `MOBILEGL_MAGMA_DISABLE_SUBGROUP=1`.
|
||||
|
||||
## Platform-specific
|
||||
|
||||
**Windows**
|
||||
|
||||
- `Failed to open ANGLE libGLESv2.dll` (Espryt): put `libEGL.dll`, `libGLESv2.dll` and
|
||||
`d3dcompiler_47.dll` from one x64 ANGLE build next to the program.
|
||||
- Magma finds no device: install your GPU vendor's Vulkan driver; the Vulkan SDK alone has none.
|
||||
- Crashes inside a third-party overlay's Vulkan layer (often at exit): disable implicit layers
|
||||
for the program with the Vulkan loader's `VK_LOADER_LAYERS_DISABLE=~implicit~`.
|
||||
- The build fails with `error C2610` in `MG_Util/Damage/Damage.h`: see the build status note in
|
||||
[windows.md](windows.md).
|
||||
|
||||
**Linux**
|
||||
|
||||
- Windows show `presented through wl_shm` instead of `linux-dmabuf shared images`: zero-copy needs a
|
||||
server that allocates shared images (the Android server) and a compositor with `linux-dmabuf`.
|
||||
The `wl_shm` path works, but is slower.
|
||||
- `eglCreateWindowSurface` fails on a GBM display: by design. GBM displays are offscreen in MobileGL.
|
||||
- Replacing `libMobileGL.so` in place crashes running programs: install to a new file and rename it
|
||||
over the old one.
|
||||
|
||||
**Building**
|
||||
|
||||
- `ENABLE_OPT set but SPIR-V tools not found` (or similar) at configure: run
|
||||
`python3 update_glslang_sources.py` in `3rdparty/glslang`.
|
||||
- `MOBILEGL_BUILD_DISAGGREGATED=ON but 3rdparty/flatbuffers/include is missing`: run
|
||||
`git submodule update --init 3rdparty/flatbuffers`.
|
||||
- Tests run with wrong environments under CMake 4.x: build and test with CMake 3.31.x.
|
||||
- Gradle builds are slow: `-Pmobilegl.enableLto=OFF` skips ThinLTO (the library is then slower).
|
||||
@@ -0,0 +1,93 @@
|
||||
# MobileGL on Windows (WGL `opengl32.dll` drop-in)
|
||||
|
||||
On Windows, MobileGL builds as `MobileGL.dll` plus an identical copy named `opengl32.dll`. The copy
|
||||
exports the WGL entry points (`wglCreateContext`, `wglGetProcAddress`, `wglSwapBuffers`, ...) and
|
||||
the OpenGL functions. A program that loads `opengl32.dll` from its own directory gets MobileGL
|
||||
instead of the system OpenGL driver.
|
||||
|
||||
## When to use it
|
||||
|
||||
- You want to run a Windows OpenGL program (for example Minecraft through GLFW/LWJGL) on MobileGL,
|
||||
to test MobileGL or to compare its backends on desktop hardware.
|
||||
|
||||
When not to use it:
|
||||
|
||||
- Split rendering. On Windows only monolith is supported; the server executable is not built for
|
||||
Windows.
|
||||
- As a system-wide driver. Do not replace `C:\Windows\System32\opengl32.dll`. The drop-in works per
|
||||
application directory.
|
||||
|
||||
> **Build status on the current branch:** building `feat/disaggregated` with MSVC 19.38
|
||||
> (Visual Studio 2022 17.8) fails with `error C2610` in `MobileGL/MG_Util/Damage/Damage.h` (a
|
||||
> defaulted `operator==`) and the same error in several Magma headers. Newer MSVC toolsets were not
|
||||
> tested. The steps below are the ones the Windows tooling in this repository uses
|
||||
> (`tools/cts/scripts/wgl_glcts_pipeline.py`); they apply once the tree builds with your compiler.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows x64, Visual Studio 2022 with the Desktop C++ workload, CMake, Python 3, Git.
|
||||
- The Vulkan SDK, so that CMake's `find_package(Vulkan)` finds it.
|
||||
- For **Magma**: a Vulkan driver for your GPU (`vulkan-1.dll` and a vendor ICD). The SDK alone
|
||||
provides no GPU device.
|
||||
- For **Espryt**: Espryt on Windows always runs on ANGLE. Put matching x64 `libEGL.dll`,
|
||||
`libGLESv2.dll` and `d3dcompiler_47.dll` from one ANGLE build next to the program.
|
||||
|
||||
## Build
|
||||
|
||||
Prepare the sources first (submodules and glslang's external sources, see
|
||||
[building.md](building.md#get-the-sources)). Then, from the repository root:
|
||||
|
||||
```powershell
|
||||
cmake -S . -B C:\mgl-build -G "Visual Studio 17 2022" -A x64 -DMOBILEGL_BUILD_TEST=OFF -DMOBILEGL_BUILD_BENCHMARK=OFF
|
||||
```
|
||||
|
||||
```powershell
|
||||
cmake --build C:\mgl-build --config Release --target MobileGL
|
||||
```
|
||||
|
||||
Keep the build directory path short: a full build under a deep path can exceed Windows' path length
|
||||
limit. The result is `C:\mgl-build\Release\MobileGL.dll` and `C:\mgl-build\Release\opengl32.dll`
|
||||
(with the Ninja generator, both are directly in the build directory).
|
||||
|
||||
## Install
|
||||
|
||||
Copy `opengl32.dll` into the directory of the executable that creates the GL context. Windows
|
||||
searches the application's directory before `System32`, so the copy wins.
|
||||
|
||||
| Program | Where `opengl32.dll` goes |
|
||||
|---|---|
|
||||
| A native `.exe` | next to the `.exe` |
|
||||
| A Java program (Minecraft) | next to the `java.exe` / `javaw.exe` that runs it, in the runtime's `bin` directory. Use a private copy of the Java runtime so other programs are not affected. |
|
||||
|
||||
For Espryt, put the three ANGLE DLLs in the same directory.
|
||||
|
||||
## Configure and run
|
||||
|
||||
Settings are environment variables ([configuration.md](configuration.md)). Set them in the shell
|
||||
that starts the program, or in your launcher's environment settings:
|
||||
|
||||
```powershell
|
||||
$env:MOBILEGL_BACKEND_TYPE = "DirectVulkan"
|
||||
```
|
||||
|
||||
```powershell
|
||||
$env:MOBILEGL_LOG_FILE_PATH = "$PWD\mobilegl.log"
|
||||
```
|
||||
|
||||
MobileGL does not log to the console on Windows, and writes no log file unless
|
||||
`MOBILEGL_LOG_FILE_PATH` is set.
|
||||
|
||||
## How to tell it works
|
||||
|
||||
- The program reports `GL_RENDERER` = `Magma (MobileGL Core) (...)` or `Espryt (MobileGL Core) (...)`.
|
||||
In Minecraft, look at the F3 screen.
|
||||
- The log file exists and contains `Config: Active backend type set to DirectVulkan`.
|
||||
- For Espryt, the log has `Loaded GL backend library: libGLESv2.dll` / `libEGL.dll`.
|
||||
- `tools/wgl-smoke/` has two small test programs (a hand-written WGL bootstrap and a GLFW one) that
|
||||
render a triangle and check it with `glReadPixels`. Exit code 0 means pass. Build instructions are
|
||||
in `tools/wgl-smoke/README.md`.
|
||||
- `tools/cts/scripts/wgl_glcts_pipeline.py` runs the Khronos OpenGL conformance suites against the
|
||||
drop-in. Its preflight checks that the suite really loaded MobileGL.
|
||||
|
||||
If the program still reports your GPU vendor's renderer, it loaded the system `opengl32.dll`:
|
||||
check that the copy sits next to the executable that actually creates the context.
|
||||
Reference in New Issue
Block a user