Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Smithay/gbm.rs/llms.txt
Use this file to discover all available pages before exploring further.
Surface<T> is a GBM rendering surface — a managed pool of GPU buffers that cycles through a produce/consume loop driven by EGL and the display hardware. Its primary role is to serve as the native window type when creating an EGL surface on a DRM platform: you pass the raw gbm_surface pointer to eglCreateWindowSurface, and from that point EGL renders into the surface’s internal buffers while your compositor code reads completed frames out of the front buffer and hands them to KMS for display.
Surface vs BufferObject: When to Use Which
Use Surface<T> when…
- You are integrating with EGL (
eglCreateWindowSurface). - You want EGL/Mesa to manage the buffer pool automatically.
- Your pipeline follows the GBM swap-chain protocol: render → swap → lock → flip.
Use BufferObject<T> when…
- You are managing buffers manually (e.g. software rendering, video import, cursor images).
- You need explicit control over allocation flags and modifiers.
- You are importing external DMA-BUF memory from another API.
Creating a Surface
All surface creation methods live onDevice. They accept width, height, format, and either usage flags or explicit modifiers.
create_surface
Basic creation with usage flags. The driver chooses the buffer layout.
create_surface_with_modifiers
Accepts an iterator of Modifier values and lets the driver select the best supported one. No usage flags — the driver infers intent from the modifiers.
create_surface_with_modifiers2
Combines explicit modifiers and usage flags. This is the most expressive variant and maps to gbm_surface_create_with_modifiers2.
The Front Buffer Protocol
GBM surfaces manage a small internal pool of buffers (typically two or three). At any moment some buffers are free (available for rendering) and some are locked (held by the compositor, in flight to the display). The protocol for each frame is strict and must be followed exactly:Check for free buffers
Before starting a new frame, call
has_free_buffers(). If it returns
false, all internal buffers are locked and you must wait for a
previous page flip to complete and release a buffer before rendering.Render via EGL
Bind the GBM surface as the current EGL draw surface and issue your
OpenGL (or Vulkan) drawing commands. EGL renders into one of the
surface’s free internal buffers.
Call eglSwapBuffers
This submits the rendered frame and advances the surface’s front buffer.
After this call, the next
lock_front_buffer will return the just-rendered image.Lock the front buffer
Call
lock_front_buffer() exactly once after eglSwapBuffers. It
returns a BufferObject<T> whose underlying memory holds the completed
frame. The buffer remains locked until the returned BufferObject is
dropped.has_free_buffers()
Returns true if the surface has at least one buffer not currently locked. A newly created surface always has free buffers. After locking one or more buffers without releasing them, this method will return false and you must not start rendering a new frame.
lock_front_buffer()
Returns the surface’s current front buffer as a BufferObject<T>. The buffer is released (returned to the pool) when the BufferObject is dropped.
Err(FrontBufferError) if libgbm cannot lock the front buffer. FrontBufferError is a unit struct that implements std::error::Error.
The T Generic: Userdata on Locked Buffers
The T in Surface<T> flows through to BufferObject<T> returned by lock_front_buffer. This lets you attach state to front buffers — for example, a DRM framebuffer handle:
Full Rendering Loop Sketch
The pattern of passing the locked
BufferObject as page-flip callback
data (so it is dropped exactly when the flip completes) is the canonical
approach used in compositors like Smithay. It ties the GBM buffer release
directly to the display hardware’s acknowledgement that it is done scanning
out the frame.