aboutsummaryrefslogblamecommitdiffstats
blob: 6b4f0759b00b291440c7d79e9d47bf286b6174b6 (plain) (tree)
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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430













































































































































































































































































































































































































































                                                                                                                   
<?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-memory">
  <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-memory</refentrytitle>
    <manvolnum>7</manvolnum>
  </refmeta>

  <refnamediv>
    <refname>drm-memory</refname>
    <refname>drm-mm</refname>
    <refname>drm-gem</refname>
    <refname>drm-ttm</refname>
    <refpurpose>DRM Memory Management</refpurpose>
  </refnamediv>

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

  <refsect1>
    <title>Description</title>
      <para>Many modern high-end GPUs come with their own memory managers. They
            even include several different caches that need to be synchronized
            during access. Textures, framebuffers, command buffers and more need
            to be stored in memory that can be accessed quickly by the GPU.
            Therefore, memory management on GPUs is highly driver- and
            hardware-dependent.</para>

      <para>However, there are several frameworks in the kernel that are used by
            more than one driver. These can be used for trivial mode-setting
            without requiring driver-dependent code. But for
            hardware-accelerated rendering you need to read the manual pages for
            the driver you want to work with.</para>

    <refsect2>
      <title>Dumb-Buffers</title>
      <para>Almost all in-kernel DRM hardware drivers support an API called
            <emphasis>Dumb-Buffers</emphasis>. This API allows to create buffers
            of arbitrary size that can be used for scanout. These buffers can be
            memory mapped via
            <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>
            so you can render into them on the CPU. However, GPU access to these
            buffers is often not possible. Therefore, they are fine for simple
            tasks but not suitable for complex compositions and
            renderings.</para>

      <para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl can be
            used to create a dumb buffer. The kernel will return a 32bit handle
            that can be used to manage the buffer with the DRM API. You can
            create framebuffers with
            <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            and use it for mode-setting and scanout. To access the buffer, you
            first need to retrieve the offset of the buffer. The
            <constant>DRM_IOCTL_MODE_MAP_DUMB</constant> ioctl requests the DRM
            subsystem to prepare the buffer for memory-mapping and returns a
            fake-offset that can be used with
            <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>

      <para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl takes as
            argument a structure of type
            <structname>struct drm_mode_create_dumb</structname>:

<programlisting>
struct drm_mode_create_dumb {
	__u32 height;
	__u32 width;
	__u32 bpp;
	__u32 flags;

	__u32 handle;
	__u32 pitch;
	__u64 size;
};
</programlisting>

            The fields <structfield>height</structfield>,
            <structfield>width</structfield>, <structfield>bpp</structfield> and
            <structfield>flags</structfield> have to be provided by the caller.
            The other fields are filled by the kernel with the return values.
            <structfield>height</structfield> and
            <structfield>width</structfield> are the dimensions of the
            rectangular buffer that is created. <structfield>bpp</structfield>
            is the number of bits-per-pixel and must be a multiple of
            <literal>8</literal>. You most commonly want to pass
            <literal>32</literal> here. The <structfield>flags</structfield>
            field is currently unused and must be zeroed. Different flags to
            modify the behavior may be added in the future. After calling the
            ioctl, the <structfield>handle</structfield>,
            <structfield>pitch</structfield> and <structfield>size</structfield>
            fields are filled by the kernel. <structfield>handle</structfield>
            is a 32bit gem handle that identifies the buffer. This is used by
            several other calls that take a gem-handle or memory-buffer as
            argument. The <structfield>pitch</structfield> field is the
            pitch (or stride) of the new buffer. Most drivers use 32bit or 64bit
            aligned stride-values. The <structfield>size</structfield> field
            contains the absolute size in bytes of the buffer. This can normally
            also be computed with
            <emphasis>(height * pitch + width) * bpp / 4</emphasis>.</para>

      <para>To prepare the buffer for
            <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>
            you need to use the <constant>DRM_IOCTL_MODE_MAP_DUMB</constant>
            ioctl. It takes as argument a structure of type
            <structname>struct drm_mode_map_dumb</structname>:

<programlisting>
struct drm_mode_map_dumb {
	__u32 handle;
	__u32 pad;

	__u64 offset;
};
</programlisting>

            You need to put the gem-handle that was previously retrieved via
            <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> into the
            <structfield>handle</structfield> field. The
            <structfield>pad</structfield> field is unused padding and must be
            zeroed. After completion, the <structfield>offset</structfield>
            field will contain an offset that can be used with
            <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>
            on the DRM file-descriptor.</para>

      <para>If you don't need your dumb-buffer, anymore, you have to destroy it
            with <constant>DRM_IOCTL_MODE_DESTROY_DUMB</constant>. If you close
            the DRM file-descriptor, all open dumb-buffers are automatically
            destroyed. This ioctl takes as argument a structure of type
            <structname>struct drm_mode_destroy_dumb</structname>:

<programlisting>
struct drm_mode_destroy_dumb {
	__u32 handle;
};
</programlisting>

            You only need to put your handle into the
            <structfield>handle</structfield> field. After this call, the handle
            is invalid and may be reused for new buffers by the dumb-API.</para>

    </refsect2>

    <refsect2>
      <title>TTM</title>
      <para><emphasis>TTM</emphasis> stands for
            <emphasis>Translation Table Manager</emphasis> and is a generic
            memory-manager provided by the kernel. It does not provide a common
            user-space API so you need to look at each driver interface if you
            want to use it. See for instance the radeon manpages for more
            information on memory-management with radeon and TTM.</para>
    </refsect2>

    <refsect2>
      <title>GEM</title>
      <para><emphasis>GEM</emphasis> stands for
            <emphasis>Graphics Execution Manager</emphasis> and is a generic DRM
            memory-management framework in the kernel, that is used by many
            different drivers. Gem is designed to manage graphics memory,
            control access to the graphics device execution context and handle
            essentially NUMA environment unique to modern graphics hardware. Gem
            allows multiple applications to share graphics device resources
            without the need to constantly reload the entire graphics card. Data
            may be shared between multiple applications with gem ensuring that
            the correct memory synchronization occurs.</para>

      <para>Gem provides simple mechanisms to manage graphics data and control
            execution flow within the linux DRM subsystem. However, gem is not a
            complete framework that is fully driver independent. Instead, if
            provides many functions that are shared between many drivers, but
            each driver has to implement most of memory-management with
            driver-dependent ioctls. This manpage tries to describe the
            semantics (and if it applies, the syntax) that is shared between all
            drivers that use gem.</para>

      <para>All GEM APIs are defined as
            <citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
            on the DRM file descriptor. An application must be authorized via
            <citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            to the current DRM-Master to access the GEM subsystem. A driver that
            does not support gem will return <constant>ENODEV</constant> for all
            these ioctls. Invalid object handles return
            <constant>EINVAL</constant> and invalid object names return
            <constant>ENOENT</constant>.</para>

      <para>Gem provides explicit memory management primitives. System pages are
            allocated when the object is created, either as the fundamental
            storage for hardware where system memory is used by the graphics
            processor directly, or as backing store for graphics-processor
            resident memory.</para>

      <para>Objects are referenced from user-space using handles. These are, for
            all intents and purposes, equivalent to file descriptors but avoid
            the overhead. Newer kernel drivers also support the
            <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>
            infrastructure which can return real file-descriptor for gem-handles
            using the linux dma-buf API. Objects may be published with a name so
            that other applications and processes can access them. The name
            remains valid as long as the object exists. Gem-objects are
            reference counted in the kernel. The object is only destroyed when
            all handles from user-space were closed.</para>

      <para>Gem-buffers cannot be created with a generic API. Each driver
            provides its own API to create gem-buffers. See for example
            <constant>DRM_I915_GEM_CREATE</constant>,
            <constant>DRM_NOUVEAU_GEM_NEW</constant> or
            <constant>DRM_RADEON_GEM_CREATE</constant>. Each of these ioctls
            returns a gem-handle that can be passed to different generic ioctls.
            The <emphasis>libgbm</emphasis> library from the
            <emphasis>mesa3D</emphasis> distribution tries to provide a
            driver-independent API to create gbm buffers and retrieve a
            gbm-handle to them. It allows to create buffers for different
            use-cases including scanout, rendering, cursors and CPU-access. See
            the libgbm library for more information or look at the
            driver-dependent man-pages (for example
            <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>
            or
            <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para>

      <para>Gem-buffers can be closed with the
            <constant>DRM_IOCTL_GEM_CLOSE</constant> ioctl. It takes as argument
            a structure of type <structname>struct drm_gem_close</structname>:

<programlisting>
struct drm_gem_close {
	__u32 handle;
	__u32 pad;
};
</programlisting>

            The <structfield>handle</structfield> field is the gem-handle to be
            closed. The <structfield>pad</structfield> field is unused padding.
            It must be zeroed. After this call the gem handle cannot be used by
            this process anymore and may be reused for new gem objects by the
            gem API.</para>

      <para>If you want to share gem-objects between different processes, you
            can create a name for them and pass this name to other processes
            which can then open this gem-object. Names are currently 32bit
            integer IDs and have no special protection. That is, if you put a
            name on your gem-object, every other client that has access to the
            DRM device and is authenticated via
            <citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry>
            to the current DRM-Master, can <emphasis>guess</emphasis> the name
            and open or access the gem-object. If you want more fine-grained
            access control, you can use the new
            <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>
            API to retrieve file-descriptors for gem-handles. To create a name
            for a gem-handle, you use the
            <constant>DRM_IOCTL_GEM_FLINK</constant> ioctl. It takes as argument
            a structure of type <structname>struct drm_gem_flink</structname>:

<programlisting>
struct drm_gem_flink {
	__u32 handle;
	__u32 name;
};
</programlisting>

            You have to put your handle into the
            <structfield>handle</structfield> field. After completion, the
            kernel has put the new unique name into the
            <structfield>name</structfield> field. You can now pass this name to
            other processes which can then import the name with the
            <constant>DRM_IOCTL_GEM_OPEN</constant> ioctl. It takes as argument
            a structure of type <structname>struct drm_gem_open</structname>:

<programlisting>
struct drm_gem_open {
	__u32 name;

	__u32 handle;
	__u32 size;
};
</programlisting>

            You have to fill in the <structfield>name</structfield> field with
            the name of the gem-object that you want to open. The kernel will
            fill in the <structfield>handle</structfield> and
            <structfield>size</structfield> fields with the new handle and size
            of the gem-object. You can now access the gem-object via the handle
            as if you created it with the gem API.</para>

      <para>Besides generic buffer management, the GEM API does not provide any
            generic access. Each driver implements its own functionality on top
            of this API. This includes execution-buffers, GTT management,
            context creation, CPU access, GPU I/O and more. The next
            higher-level API is <emphasis>OpenGL</emphasis>. So if you want to
            use more GPU features, you should use the
            <emphasis>mesa3D</emphasis> library to create OpenGL contexts on DRM
            devices. This does <emphasis>not</emphasis> require any
            windowing-system like X11, but can also be done on raw DRM devices.
            However, this is beyond the scope of this man-page. You may have a
            look at other mesa3D manpages, including libgbm and libEGL. 2D
            software-rendering (rendering with the CPU) can be achieved with the
            dumb-buffer-API in a driver-independent fashion, however, for
            hardware-accelerated 2D or 3D rendering you must use OpenGL. Any
            other API that tries to abstract the driver-internals to access
            GEM-execution-buffers and other GPU internals, would simply reinvent
            OpenGL so it is not provided. But if you need more detailed
            information for a specific driver, you may have a look into the
            driver-manpages, including
            <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
            <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>
            and
            <citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
            However, the
            <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>
            infrastructure and the generic gem API as described here allow
            display-managers to handle graphics-buffers and render-clients
            without any deeper knowledge of the GPU that is used. Moreover, it
            allows to move objects between GPUs and implement complex
            display-servers that don't do any rendering on their own. See its
            man-page for more information.</para>
    </refsect2>
  </refsect1>

  <refsect1>
    <title>Examples</title>
      <para>This section includes examples for basic memory-management
            tasks.</para>

    <refsect2>
      <title>Dumb-Buffers</title>
        <para>This examples shows how to create a dumb-buffer via the generic
              DRM API. This is driver-independent (as long as the driver
              supports dumb-buffers) and provides memory-mapped buffers that can
              be used for scanout. This example creates a full-HD 1920x1080
              buffer with 32 bits-per-pixel and a color-depth of 24 bits. The
              buffer is then bound to a framebuffer which can be used for
              scanout with the KMS API (see
              <citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para>

<programlisting>
struct drm_mode_create_dumb creq;
struct drm_mode_destroy_dumb dreq;
struct drm_mode_map_dumb mreq;
uint32_t fb;
int ret;
void *map;

/* create dumb buffer */
memset(&amp;creq, 0, sizeof(creq));
creq.width = 1920;
creq.height = 1080;
creq.bpp = 32;
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &amp;creq);
if (ret &lt; 0) {
	/* buffer creation failed; see "errno" for more error codes */
	...
}
/* creq.pitch, creq.handle and creq.size are filled by this ioctl with
 * the requested values and can be used now. */

/* create framebuffer object for the dumb-buffer */
ret = drmModeAddFB(fd, 1920, 1080, 24, 32, creq.pitch, creq.handle, &amp;fb);
if (ret) {
	/* frame buffer creation failed; see "errno" */
	...
}
/* the framebuffer "fb" can now used for scanout with KMS */

/* prepare buffer for memory mapping */
memset(&amp;mreq, 0, sizeof(mreq));
mreq.handle = creq.handle;
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &amp;mreq);
if (ret) {
	/* DRM buffer preparation failed; see "errno" */
	...
}
/* mreq.offset now contains the new offset that can be used with mmap() */

/* perform actual memory mapping */
map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
if (map == MAP_FAILED) {
	/* memory-mapping failed; see "errno" */
	...
}

/* clear the framebuffer to 0 */
memset(map, 0, creq.size);
</programlisting>

    </refsect2>

  </refsect1>

  <refsect1>
    <title>Reporting Bugs</title>
    <para>Bugs in this manual should be reported to
          http://bugs.freedesktop.org under the "Mesa" product, with "Other" or
          "libdrm" as the component.</para>
  </refsect1>

  <refsect1>
    <title>See Also</title>
    <para>
      <citerefentry><refentrytitle>drm</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmAvailable</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
      <citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry>
    </para>
  </refsect1>
</refentry>