1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
=======
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
**drmModeGetConnector**\ (3) 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-dependent and described in **drm-memory**\ (7). 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
**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)
|