aboutsummaryrefslogtreecommitdiffstats
blob: eb04c263acd138e1a9fadad71fda00032fe10ed8 (plain) (blame)
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
          "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">

<!--
  Written 2012 by David Herrmann <dh.herrmann@googlemail.com>
  Dedicated to the Public Domain
-->

<refentry id="drm-kms">
  <refentryinfo>
    <title>Direct Rendering Manager</title>
    <productname>libdrm</productname>
    <date>September 2012</date>
    <authorgroup>
      <author>
        <contrib>Developer</contrib>
        <firstname>David</firstname>
        <surname>Herrmann</surname>
        <email>dh.herrmann@googlemail.com</email>
      </author>
    </authorgroup>
  </refentryinfo>

  <refmeta>
    <refentrytitle>drm-kms</refentrytitle>
    <manvolnum>7</manvolnum>
  </refmeta>

  <refnamediv>
    <refname>drm-kms</refname>
    <refpurpose>Kernel Mode-Setting</refpurpose>
  </refnamediv>

  <refsynopsisdiv>
    <funcsynopsis>
      <funcsynopsisinfo>#include &lt;xf86drm.h&gt;</funcsynopsisinfo>
      <funcsynopsisinfo>#include &lt;xf86drmMode.h&gt;</funcsynopsisinfo>
    </funcsynopsis>
  </refsynopsisdiv>

  <refsect1>
    <title>Description</title>
    <para>Each DRM device provides access to manage which monitors and displays
          are currently used and what frames to be displayed. This task is
          called <emphasis>Kernel Mode-Setting</emphasis> (KMS). Historically,
          this was done in user-space and called 
          <emphasis>User-space Mode-Setting</emphasis> (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
          <citerefentry><refentrytitle>drmModeSettingSupported</refentrytitle><manvolnum>3</manvolnum></citerefentry>
          to check whether your driver supports this. To understand how KMS
          works, we need to introduce 5 objects: <emphasis>CRTCs</emphasis>,
          <emphasis>Planes</emphasis>, <emphasis>Encoders</emphasis>,
          <emphasis>Connectors</emphasis> and
          <emphasis>Framebuffers</emphasis>.

      <variablelist>
        <varlistentry>
          <term>CRTCs</term>
          <listitem>
            <para>A <emphasis>CRTC</emphasis> short for
                  <emphasis>CRT Controller</emphasis> 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
                  <citerefentry><refentrytitle>drmModeCrtcSet</refentrytitle><manvolnum>3</manvolnum></citerefentry>
                  to drive the display devices.</para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Planes</term>
          <listitem>
            <para>A <emphasis>plane</emphasis> 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).</para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Encoders</term>
          <listitem>
            <para>An <emphasis>encoder</emphasis> 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 <emphasis>cloned</emphasis> display
                  configuration across the connectors attached to each
                  encoder.</para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Connectors</term>
          <listitem>
            <para>A <emphasis>connector</emphasis> 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, <emphasis>EDID</emphasis> data,
                  <emphasis>DPMS</emphasis> and
                  <emphasis>connection status</emphasis>, and information about
                  modes supported on the attached displays.</para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>Framebuffers</term>
          <listitem>
            <para><emphasis>Framebuffers</emphasis> 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
                  <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry>
                  API.</para>
          </listitem>
        </varlistentry>
      </variablelist>
    </para>

    <refsect2>
      <title>Mode-Setting</title>
      <para>Before mode-setting can be performed, an application needs to call
            <citerefentry><refentrytitle>drmSetMaster</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            to become <emphasis>DRM-Master</emphasis>. It then has exclusive
            access to the KMS API. A call to
            <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            returns a list of <emphasis>CRTCs</emphasis>,
            <emphasis>Connectors</emphasis>, <emphasis>Encoders</emphasis> and
            <emphasis>Planes</emphasis>.</para>

      <para>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 <emphasis>Examples</emphasis>
            section below for more information.</para>

      <para>All valid modes for a connector can be retrieved with a call to
            <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            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.</para>

      <para>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
            <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
            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
            <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            and
            <citerefentry><refentrytitle>drmModeAddFB2</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>

      <para>As a last step, you want to program your CRTC to drive your selected
            connector. You can do this with a call to
            <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
    </refsect2>

    <refsect2>
      <title>Page-Flipping</title>
      <para>A call to
            <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            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
            <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            on the next buffer to flip. If you want to synchronize your flips
            with <emphasis>vertical-blanks</emphasis>, you can use
            <citerefentry><refentrytitle>drmModePageFlip</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            which schedules your page-flip for the next
            <emphasis>vblank</emphasis>.</para>
    </refsect2>

    <refsect2>
      <title>Planes</title>
      <para>Planes are controlled independently from CRTCs. That is, a call to
            <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            does not affect planes. Instead, you need to call
            <citerefentry><refentrytitle>drmModeSetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            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
            <citerefentry><refentrytitle>drmModeGetPlaneResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            for more information.</para>
    </refsect2>

    <refsect2>
      <title>Cursors</title>
      <para>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
            <citerefentry><refentrytitle>drmModeSetCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            and move it on the screen with
            <citerefentry><refentrytitle>drmModeMoveCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
            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.</para>
    </refsect2>

  </refsect1>

  <refsect1>
    <title>Examples</title>
    <para>Some examples of how basic mode-setting can be done. See the man-page
          of each DRM function for more information.</para>

    <refsect2>
      <title>CRTC/Encoder Selection</title>
      <para>If you retrieved all display configuration information via
            <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            as <structname>drmModeRes</structname> *<varname>res</varname>,
            selected a connector from the list in
            <varname>res</varname>-><structfield>connectors</structfield>
            and retrieved the connector-information as
            <structname>drmModeConnector</structname> *<varname>conn</varname>
            via
            <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            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
            <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
            as <varname>fd</varname>, a pointer to the retrieved resources as
            <varname>res</varname> and a pointer to the selected connector as
            <varname>conn</varname>. It returns an integer smaller than 0 on
            failure, otherwise, a valid CRTC id is returned.</para>

<programlisting>
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 &lt; 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 &lt; res->count_crtcs; ++j) {
			/* check whether this CRTC works with the encoder */
			if (!(enc->possible_crtcs &amp; (1 &lt;&lt; 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;
}
</programlisting>

    </refsect2>

  </refsect1>

  <refsect1>
    <title>Reporting Bugs</title>
    <para>Bugs in this manual should be reported to
      https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&amp;component=libdrm
      under the "DRI" product, component "libdrm"</para>
  </refsect1>

  <refsect1>
    <title>See Also</title>
    <para>
      <citerefentry><refentrytitle>drm</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-memory</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetConnector</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetEncoder</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeSetCrtc</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeAddFB2</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeRmFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModePageFlip</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetPlaneResources</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeGetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeSetPlane</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeSetCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmModeMoveCursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmSetMaster</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmAvailable</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmCheckModesettingSupported</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>
    </para>
  </refsect1>
</refentry>