2020-06-03 03:58:07 -06:00
|
|
|
=======
|
|
|
|
drm-kms
|
|
|
|
=======
|
|
|
|
|
|
|
|
-------------------
|
|
|
|
Kernel Mode-Setting
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
:Date: September 2012
|
|
|
|
:Manual section: 7
|
|
|
|
:Manual group: Direct Rendering Manager
|
|
|
|
|
|
|
|
Synopsis
|
|
|
|
========
|
|
|
|
|
|
|
|
``#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
|
|
|
|
**drmModeSettingSupported**\ (3) 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
|
|
|
|
**drmModeCrtcSet**\ (3) 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-memory**\ (7) API.
|
|
|
|
|
|
|
|
Mode-Setting
|
|
|
|
------------
|
|
|
|
|
|
|
|
Before mode-setting can be performed, an application needs to call
|
|
|
|
**drmSetMaster**\ (3) to become *DRM-Master*. It then has exclusive access to
|
|
|
|
the KMS API. A call to **drmModeGetResources**\ (3) 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
|
2022-04-19 14:10:57 -06:00
|
|
|
**drmModeGetConnector**\ (3) You need to select the mode you want to use and save it.
|
2020-06-03 03:58:07 -06:00
|
|
|
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
|
2022-04-19 12:53:55 -06:00
|
|
|
driver-dependent and described in **drm-memory**\ (7). You need to create a
|
2020-06-03 03:58:07 -06:00
|
|
|
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
|
|
|
|
**drmModeAddFB**\ (3) and **drmModeAddFB2**\ (3).
|
|
|
|
|
|
|
|
As a last step, you want to program your CRTC to drive your selected connector.
|
|
|
|
You can do this with a call to **drmModeSetCrtc**\ (3).
|
|
|
|
|
|
|
|
Page-Flipping
|
|
|
|
-------------
|
|
|
|
|
|
|
|
A call to **drmModeSetCrtc**\ (3) 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 **drmModeSetCrtc**\ (3) on the next
|
|
|
|
buffer to flip. If you want to synchronize your flips with *vertical-blanks*,
|
|
|
|
you can use **drmModePageFlip**\ (3) which schedules your page-flip for the
|
|
|
|
next *vblank*.
|
|
|
|
|
|
|
|
Planes
|
|
|
|
------
|
|
|
|
|
|
|
|
Planes are controlled independently from CRTCs. That is, a call to
|
|
|
|
**drmModeSetCrtc**\ (3) does not affect planes. Instead, you need to call
|
|
|
|
**drmModeSetPlane**\ (3) 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 **drmModeGetPlaneResources**\ (3) 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 **drmModeSetCursor**\ (3) and move it
|
|
|
|
on the screen with **drmModeMoveCursor**\ (3). 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
|
|
|
|
**drmModeGetResources**\ (3) as ``drmModeRes *res``, selected a connector from
|
|
|
|
the list in ``res->connectors`` and retrieved the connector-information as
|
|
|
|
``drmModeConnector *conn`` via **drmModeGetConnector**\ (3) 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 **drmOpen**\ (3)) 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
|
|
|
|
========
|
|
|
|
|
|
|
|
**drm**\ (7), **drm-memory**\ (7), **drmModeGetResources**\ (3),
|
|
|
|
**drmModeGetConnector**\ (3), **drmModeGetEncoder**\ (3),
|
|
|
|
**drmModeGetCrtc**\ (3), **drmModeSetCrtc**\ (3), **drmModeGetFB**\ (3),
|
|
|
|
**drmModeAddFB**\ (3), **drmModeAddFB2**\ (3), **drmModeRmFB**\ (3),
|
|
|
|
**drmModePageFlip**\ (3), **drmModeGetPlaneResources**\ (3),
|
|
|
|
**drmModeGetPlane**\ (3), **drmModeSetPlane**\ (3), **drmModeSetCursor**\ (3),
|
|
|
|
**drmModeMoveCursor**\ (3), **drmSetMaster**\ (3), **drmAvailable**\ (3),
|
|
|
|
**drmCheckModesettingSupported**\ (3), **drmOpen**\ (3)
|