libliftoff/doc/compositor.md
Simon Ser 6321e7c5aa Add needs_composition APIs
Right now, compositors are expected to query liftoff_layer_get_plane_id to
decide whether a layer needs to be composited.

However there are cases where a layer has no plane, but still doesn't need
composition (e.g. when FB_ID is zero or when alpha is zero, in the future when
the layer is out of CRTC bounds etc).

Add a new API to make users' life simpler.

Closes: https://github.com/emersion/libliftoff/issues/54
2021-08-09 11:56:55 +02:00

4.2 KiB

Using libliftoff for a compositor

This document explains how to use libliftoff for a full-blown compositor.

A compositor receives buffers coming from clients and displays them on screen. Client buffers are attached to surfaces. For instance a Wayland compositor receives shared-memory buffers via wl_shm and DMA-BUFs via wp_linux_dmabuf. Shared memory buffers are stored in main memory, DMA-BUFs are stored directly on the GPU.

Compositors which can't take advantage of hardware planes will always perform composition for all client buffers. In other words, such compositors will copy client buffers to their own buffer, then display their own buffer on screen. Typically the copying is done via OpenGL.

Compositors which can take advantage of hardware planes will sometimes avoid composition (because the hardware can directly scan-out client buffers), but sometimes they'll need to fallback to composition (because of hardware limitations). libliftoff can help with this decision-making.

Setting up layers

A compositor will want to create one layer per surface. That way, in the best-case scenario, all client buffers will make it into a hardware plane and composition won't be necessary. The layers effectively describe the compositor's scene-graph.

The compositor will need to set standard plane properties on the buffer, in particular the CRTC_*, SRC_* and zpos properties. These properties define the position and size of the layer.

DMA-BUFs

Each time a client submits a new DMA-BUF for a surface, the compositor should import the buffer and update the layer's FB_ID. libliftoff will try to put this layer in a plane.

Buffers that can't be directly scanned out

Buffers using shared memory can't be directly scanned out by the hardware.

These will need to be composited, the compositor should call liftoff_layer_set_fb_composited. libliftoff will never try to put this layer in a plane.

Elements drawn by the compositor

Sometimes compositors want to draw UI elements themselves, for instance window decorations. The compositor could allocate buffers for these UI elements, but sometimes it may want not to. libliftoff needs to know about this to avoid putting a layer which is underneath in a hardware plane.

For each of those elements, the compositor can create a layer, set the CRTC_* and zpos properties to indicate the geometry of the element, and call liftoff_layer_set_fb_composited to indicate that this region needs to be composited.

Composition layer

A compositor must always be prepared to fallback to composition. There are a lot of potential reasons why composition is needed, for instance:

  • The client uses a buffer which can't be directly scanned out, or the compositor wants to draw a UI element itself
  • The format or modifier used by the client isn't compatible with any of the hardware planes
  • The client buffer isn't compatible with any of the planes, e.g. because of a format or modifier mismatch
  • Putting a client buffer into a hardware plane would exceed the hardware bandwidth limits

The compositor needs to prepare a special buffer where client buffers will be copied to if composition is necessary. Because it's not possible to know in advance whether composition will be necessary, the compositor needs to setup this "composition buffer" before libliftoff does its job.

The composition buffer should be allocated with a format and modifier compatible with the primary plane.

The compositor should create a special layer, the "composition layer". The layer should cover the whole CRTC. liftoff_output_set_composition_layer should be used to tell libliftoff that composition will happen on this special layer.

If all regular layers can be put into a plane, the composition layer won't be used. Otherwise, the compositor needs to perform the composition prior to performing a page-flip. Each layer that didn't make it into a hardware plane (ie. liftoff_layer_needs_composition returns true) needs to be composited.

Disabling layers

When the compositor needs to hide a surface, it's not very handy to destroy the layer (and re-create it when the surface is visible again). Instead, the compositor can disable a layer by setting FB_ID to zero.

The layer will be ignored by libliftoff.