Looking from the right ANGLE

ANGLE is Google's OpenGL ES implementation that runs on top of a native graphics API. Here its Metal backend is built from source and packaged as a deb, exposing libEGL and libGLESv2. A GLES program links against those and its draw calls become Metal.

The build is not stock. One local patch admits Apple GPU Family 3, the A10's family, to ES3 in the Metal backend. Upstream stops at ES2, and GTK4's GL renderer wants ES3. Without that patch most of this page does not happen.

The part that matters most is where ANGLE puts its results. It can render directly into IOSurfaces, so a client's frame lands in a surface the compositor already knows how to adopt as a texture. That shared surface is what removes the copy.

The shim in front of ANGLE

ANGLE has no Wayland platform on iOS, and iOS has no dma-buf, so the normal Linux way for a toolkit to get a GPU surface does not exist here. That gap is filled by a small library, libiosc_egl, which is installed in ANGLE's place as libEGL.dylib; real ANGLE stays next to it as libEGL.angle.dylib.

It is a shim, not a renderer. It dlopens the real ANGLE and forwards nearly every EGL call straight through. It intercepts four: creating a display (it returns an ANGLE Metal display and remembers the wl_display), creating a window surface (it allocates IOSurfaces and wraps them as ANGLE pbuffers), making one current, and swapping buffers (it fences the finished surface, hands it to the compositor over iosc_iosurface, and rotates to the next free one).

So is it really hardware?

Yes. Every draw call still executes in ANGLE on Metal on the A10 GPU. The shim never touches pixels; it decides which IOSurface the GPU draws into and who owns it next. What it buys is that an unmodified toolkit doing the standard wayland-egl dance renders zero-copy into a buffer the compositor can use as-is.

Zero-copy compositing

Figure 03. The zero-copy pathno CPU copy

A GTK4 window renders once, on the GPU, into its own IOSurface. iosc binds that surface as a GL texture and blends it with the other windows into the output surface, itself through ANGLE. The app then scans out that output. The same GPU that drew the window draws it to the screen.

Not everything is on that path. Clients that still paint into wl_shm buffers, which includes anything falling back to software Qt, are drawn by the CPU and uploaded as a texture per damaged region. The compositor says so loudly in its log if GL initialization fails and it has to composite that way for everyone.

GTK4 on the A10

GTK4's modern GL renderer works through this chain on the device. The renderer realizes on an ES3 ANGLE-to-Metal context, reached through the shim above, and draws into IOSurfaces.

KWin, the second GPU compositor

Plasma does not use iosc's compositing. KWin brings its own EGL backend, so under the KDE flavor there are two GPU compositors stacked: KWin renders Plasma's windows into an IOSurface of its own, and iosc treats that surface like any other client buffer. The work to make that land was most of July, and every bug was in a seam and not in the drawing:

  • The bundled copy of the iosc_iosurface protocol was a version behind the compositor's, so the connection died on an event the client had never heard of.
  • A one-hex-digit mistake in EGL_TEXTURE_TYPE_ANGLE made every IOSurface pbuffer fail to allocate.
  • KWin rendered into framebuffer zero, which for an ANGLE IOSurface pbuffer is not the IOSurface. The screen stayed black until the surface was bound as a texture and hung off an explicit framebuffer.
  • With no frame callback requested on present, the render loop drew exactly one frame and then waited forever.

With those closed, Plasma's QtQuick shell came off its software fallback and KWin now ships its effects, scripts and window decorations, with blur and background contrast active on device.

Signing is part of the GPU path

On iOS a process cannot create a Metal device without the GPU entitlement, and entitlements attach to a process, not to a library. Linking ANGLE is not enough: every binary that will touch the GPU has to be signed for it, so the publish step re-signs graphics packages by classifying each Mach-O into a capability profile instead of stamping every binary the same way.

Where the CPU still gets used

X11 compatibility is on the GPU path now. Xwayland is the only X route that ships: glamor renders X pixmaps with ANGLE into IOSurfaces, then iosc composites them like any other Wayland surface. The software X server that used to sit beside it — no hardware GLX or DRI route exists on iOS, so its clients drew on the CPU — was retired on 2026-07-29.

What is left on the CPU is narrower than it used to be. iOS exposes no DRM/KMS device at all, so nothing here goes through the Linux display stack; apps that insist on desktop OpenGL rather than GLES still fall back to llvmpipe; and Xvfb and Xvnc remain software servers, kept for headless bring-up and debugging rather than for running a desktop.