Firefox Shared Memory Buffers and the GPU Compositor

This article provides a technical overview of how the Firefox web browser manages shared memory (Shmem) buffers between isolated content processes and the GPU compositor. It covers the creation of shared memory via Firefox's Inter-Process Communication (IPC) layer, the abstractions used to represent graphical textures, the integration with the WebRender engine, and the synchronization and security mechanisms that keep data transfers fast and safe.

The Role of Shared Memory in Multi-Process Firefox

Firefox uses a multi-process architecture where web pages run in sandboxed content processes, while final rendering happens in a privileged GPU (or compositor) process. Because standard IPC pipes are too slow for transferring megabytes of decoded images, fonts, and rendering commands at 60 frames per second or higher, Firefox relies on shared memory (Shmem).

Shared memory allows both the content process and the GPU compositor to map the same physical RAM into their respective virtual address spaces. The content process writes graphical data into this memory block, and the GPU process reads it directly to upload it to the graphics card's Video RAM (VRAM).

IPDL and Shmem Allocation

Firefox defines its inter-process communication using a custom language called IPDL (Inter-Process Communication Definition Language). IPDL provides a built-in Shmem type that abstracts the underlying operating system's shared memory APIs:

  • Windows: CreateFileMapping and MapViewOfFile
  • Linux/Android: memfd_create or shm_open with mmap
  • macOS: mach_vm_allocate and Mach ports

When a content process needs a shared memory buffer, it calls an allocation method on an IPDL protocol actor, such as PCompositorBridge or PImageBridge. This creates the OS-level shared memory segment and duplicates the file descriptor or handle across the IPC boundary. Once both processes map the handle, they share a raw memory buffer without needing to copy bytes over the IPC pipe itself.

TextureClient and TextureHost

To manage graphical data like decoded video frames, canvas elements, and rasterized blobs, Firefox uses a pair of C++ abstractions over raw Shmem buffers:

  • TextureClient: Resides in the content process. It represents the producer side of the buffer. The content process locks the TextureClient, writes pixel data into the underlying Shmem, unlocks it, and notifies the compositor.
  • TextureHost: Resides in the GPU process. It represents the consumer side. When notified, the TextureHost reads the pixel data from the mapped Shmem and uploads it to a hardware texture on the GPU.

Note that while Firefox uses OS-specific hardware buffers (like DXGI shared surfaces on Windows or DMABuf on Linux) whenever possible to keep data entirely on the GPU, Shmem-backed textures remain essential for software-decoded media, fallback rendering paths, and transferring raw buffer data that has not yet been uploaded to the GPU.

WebRender and Display List Serialization

Firefox’s GPU-based rendering engine, WebRender, relies heavily on Shmem to receive instructions from content processes. Instead of sending individual drawing commands over IPC, the content process builds a WebRender Display List—a serialized stream of layout primitives like rectangles, text runs, borders, and shadows.

This serialized display list, alongside resource updates (such as raw font data and un-cached image bytes), is written into large Shmem buffers. The content process then sends a lightweight IPC message containing only the metadata and references to the Shmem segments. The GPU process's WebRender instance reads the display list directly out of the shared memory, parses it, builds the frame, and issues the final GPU draw calls.

Synchronization and Buffer Recycling

Sharing memory between two asynchronous processes requires strict synchronization to prevent tearing and data corruption. Firefox uses an ownership model combined with read/write locks and GPU fences:

  1. Write Phase: The content process allocates or acquires a Shmem buffer, writes data to it, and transfers logical ownership to the GPU process via an IPC message.
  2. Read Phase: The content process is forbidden from modifying the buffer while the GPU process owns it. The GPU process reads the Shmem and transfers the contents to VRAM.
  3. Recycling Phase: Allocating and mapping OS shared memory is computationally expensive, as it requires kernel transitions and page table updates. Instead of destroying the Shmem after one use, the GPU process sends an IPC message back to the content process to return ownership once the GPU upload is complete. The content process places the buffer into a pool to be reused for the next frame.

Security and Untrusted Content

In Firefox's threat model, content processes are considered untrusted because they parse arbitrary code from the web. If a content process is compromised, an attacker might try to corrupt the GPU process via shared memory. Firefox mitigates this through two primary mechanisms:

  • Strict Access Rights: IPDL enforces ownership rules. When a Shmem is sent from one process to another, the sender can be configured to lose mapping access, or the receiver can map it as read-only.
  • Preventing TOCTOU Attacks: A compromised content process might attempt a Time-of-Check to Time-of-Use (TOCTOU) attack by altering data inside the Shmem buffer while the GPU process is validating and reading it. For critical data structures like WebRender display lists or metadata descriptors, the GPU process either validates data after copying it into private memory or relies on Rust’s memory-safe parsing within WebRender to gracefully reject malformed streams without crashing or executing arbitrary code.