Direct Rendering Manager
libdrm
September 2012
Developer
David
Herrmann
dh.herrmann@googlemail.com
drm-kms
7
drm-kms
Kernel Mode-Setting
#include <xf86drm.h>
#include <xf86drmMode.h>
Description
Each DRM device provides access to manage which monitors and displays
are currently used and what frames to be displayed. This task is
called Kernel Mode-Setting (KMS). Historically,
this was done in user-space and called
User-space Mode-Setting (UMS). Almost all
open-source drivers now provide the KMS kernel API to do this in the
kernel, however, many non-open-source binary drivers from different
vendors still do not support this. You can use
drmModeSettingSupported3
to check whether your driver supports this. To understand how KMS
works, we need to introduce 5 objects: CRTCs,
Planes, Encoders,
Connectors and
Framebuffers.
CRTCs
A CRTC short for
CRT Controller is an abstraction
representing a part of the chip that contains a pointer to a
scanout buffer. Therefore, the number of CRTCs available
determines how many independent scanout buffers can be active
at any given time. The CRTC structure contains several fields
to support this: a pointer to some video memory (abstracted as
a frame-buffer object), a list of driven connectors, a display
mode and an (x, y) offset into the video memory to support
panning or configurations where one piece of video memory
spans multiple CRTCs. A CRTC is the central point where
configuration of displays happens. You select which objects to
use, which modes and which parameters and then configure each
CRTC via
drmModeCrtcSet3
to drive the display devices.
Planes
A plane respresents an image source that
can be blended with or overlayed on top of a CRTC during the
scanout process. Planes are associated with a frame-buffer to
crop a portion of the image memory (source) and optionally
scale it to a destination size. The result is then blended
with or overlayed on top of a CRTC. Planes are not provided by
all hardware and the number of available planes is limited. If
planes are not available or if not enough planes are
available, the user should fall back to normal software
blending (via GPU or CPU).
Encoders
An encoder takes pixel data from a CRTC
and converts it to a format suitable for any attached
connectors. On some devices, it may be possible to have a CRTC
send data to more than one encoder. In that case, both
encoders would receive data from the same scanout buffer,
resulting in a cloned display
configuration across the connectors attached to each
encoder.
Connectors
A connector is the final destination of
pixel-data on a device, and usually connects directly to an
external display device like a monitor or laptop panel. A
connector can only be attached to one encoder at a time. The
connector is also the structure where information about the
attached display is kept, so it contains fields for display
data, EDID data,
DPMS and
connection status, and information about
modes supported on the attached displays.
Framebuffers
Framebuffers are abstract memory objects
that provide a source of pixel data to scanout to a CRTC.
Applications explicitly request the creation of framebuffers
and can control their behavior. Framebuffers rely on the
underneath memory manager for low-level memory operations.
When creating a framebuffer, applications pass a memory handle
through the API which is used as backing storage. The
framebuffer itself is only an abstract object with no data. It
just refers to memory buffers that must be created with the
drm-memory7
API.
Mode-Setting
Before mode-setting can be performed, an application needs to call
drmSetMaster3
to become DRM-Master. It then has exclusive
access to the KMS API. A call to
drmModeGetResources3
returns a list of CRTCs,
Connectors, Encoders and
Planes.
Normal procedure now includes: First, you select which connectors
you want to use. Users are mostly interested in which monitor or
display-panel is active so you need to make sure to arrange them in
the correct logical order and select the correct ones to use. For
each connector, you need to find a CRTC to drive this connector. If
you want to clone output to two or more connectors, you may use a
single CRTC for all cloned connectors (if the hardware supports
this). To find a suitable CRTC, you need to iterate over the list of
encoders that are available for each connector. Each encoder
contains a list of CRTCs that it can work with and you simply select
one of these CRTCs. If you later program the CRTC to control a
connector, it automatically selects the best encoder. However, this
procedure is needed so your CRTC has at least one working encoder
for the selected connector. See the Examples
section below for more information.
All valid modes for a connector can be retrieved with a call to
drmModeGetConnector3
You need to select the mode you want to use and save it. The first
mode in the list is the default mode with the highest resolution
possible and often a suitable choice.
After you have a working connector+CRTC+mode combination, you need
to create a framebuffer that is used for scanout. Memory buffer
allocation is driver-depedent and described in
drm-memory7.
You need to create a buffer big enough for your selected mode. Now
you can create a framebuffer object that uses your memory-buffer as
scanout buffer. You can do this with
drmModeAddFB3
and
drmModeAddFB23.
As a last step, you want to program your CRTC to drive your selected
connector. You can do this with a call to
drmModeSetCrtc3.
Page-Flipping
A call to
drmModeSetCrtc3
is executed immediately and forces the CRTC to use the new scanout
buffer. If you want smooth-transitions without tearing, you probably
use double-buffering. You need to create one framebuffer object for
each buffer you use. You can then call
drmModeSetCrtc3
on the next buffer to flip. If you want to synchronize your flips
with vertical-blanks, you can use
drmModePageFlip3
which schedules your page-flip for the next
vblank.
Planes
Planes are controlled independently from CRTCs. That is, a call to
drmModeSetCrtc3
does not affect planes. Instead, you need to call
drmModeSetPlane3
to configure a plane. This requires the plane ID, a CRTC, a
framebuffer and offsets into the plane-framebuffer and the
CRTC-framebuffer. The CRTC then blends the content from the plane
over the CRTC framebuffer buffer during scanout. As this does not
involve any software-blending, it is way faster than traditional
blending. However, plane resources are limited. See
drmModeGetPlaneResources3
for more information.
Cursors
Similar to planes, many hardware also supports cursors. A cursor is
a very small buffer with an image that is blended over the CRTC
framebuffer. You can set a different cursor for each CRTC with
drmModeSetCursor3
and move it on the screen with
drmModeMoveCursor3.
This allows to move the cursor on the screen without rerendering. If
no hardware cursors are supported, you need to rerender for each
frame the cursor is moved.
Examples
Some examples of how basic mode-setting can be done. See the man-page
of each DRM function for more information.
CRTC/Encoder Selection
If you retrieved all display configuration information via
drmModeGetResources3
as drmModeRes *res,
selected a connector from the list in
res->connectors
and retrieved the connector-information as
drmModeConnector *conn
via
drmModeGetConnector3
then this example shows, how you can find a suitable CRTC id to
drive this connector. This function takes a file-descriptor to the
DRM device (see
drmOpen3)
as fd, a pointer to the retrieved resources as
res and a pointer to the selected connector as
conn. It returns an integer smaller than 0 on
failure, otherwise, a valid CRTC id is returned.
static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn)
{
drmModeEncoder *enc;
unsigned int i, j;
/* iterate all encoders of this connector */
for (i = 0; i < conn->count_encoders; ++i) {
enc = drmModeGetEncoder(fd, conn->encoders[i]);
if (!enc) {
/* cannot retrieve encoder, ignoring... */
continue;
}
/* iterate all global CRTCs */
for (j = 0; j < res->count_crtcs; ++j) {
/* check whether this CRTC works with the encoder */
if (!(enc->possible_crtcs & (1 << j)))
continue;
/* Here you need to check that no other connector
* currently uses the CRTC with id "crtc". If you intend
* to drive one connector only, then you can skip this
* step. Otherwise, simply scan your list of configured
* connectors and CRTCs whether this CRTC is already
* used. If it is, then simply continue the search here. */
if (res->crtcs[j] "is unused") {
drmModeFreeEncoder(enc);
return res->crtcs[j];
}
}
drmModeFreeEncoder(enc);
}
/* cannot find a suitable CRTC */
return -ENOENT;
}
Reporting Bugs
Bugs in this manual should be reported to
https://gitlab.freedesktop.org/mesa/drm/-/issues
See Also
drm7,
drm-memory7,
drmModeGetResources3,
drmModeGetConnector3,
drmModeGetEncoder3,
drmModeGetCrtc3,
drmModeSetCrtc3,
drmModeGetFB3,
drmModeAddFB3,
drmModeAddFB23,
drmModeRmFB3,
drmModePageFlip3,
drmModeGetPlaneResources3,
drmModeGetPlane3,
drmModeSetPlane3,
drmModeSetCursor3,
drmModeMoveCursor3,
drmSetMaster3,
drmAvailable3,
drmCheckModesettingSupported3,
drmOpen3