David Herrmann | fd6b369 | 2012-09-28 23:44:22 +0200 | [diff] [blame] | 1 | <?xml version='1.0'?> <!--*-nxml-*--> |
| 2 | <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
| 3 | "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> |
| 4 | |
| 5 | <!-- |
| 6 | Written 2012 by David Herrmann <dh.herrmann@googlemail.com> |
| 7 | Dedicated to the Public Domain |
| 8 | --> |
| 9 | |
| 10 | <refentry id="drm-memory"> |
| 11 | <refentryinfo> |
| 12 | <title>Direct Rendering Manager</title> |
| 13 | <productname>libdrm</productname> |
| 14 | <date>September 2012</date> |
| 15 | <authorgroup> |
| 16 | <author> |
| 17 | <contrib>Developer</contrib> |
| 18 | <firstname>David</firstname> |
| 19 | <surname>Herrmann</surname> |
| 20 | <email>dh.herrmann@googlemail.com</email> |
| 21 | </author> |
| 22 | </authorgroup> |
| 23 | </refentryinfo> |
| 24 | |
| 25 | <refmeta> |
| 26 | <refentrytitle>drm-memory</refentrytitle> |
| 27 | <manvolnum>7</manvolnum> |
| 28 | </refmeta> |
| 29 | |
| 30 | <refnamediv> |
| 31 | <refname>drm-memory</refname> |
| 32 | <refname>drm-mm</refname> |
| 33 | <refname>drm-gem</refname> |
| 34 | <refname>drm-ttm</refname> |
| 35 | <refpurpose>DRM Memory Management</refpurpose> |
| 36 | </refnamediv> |
| 37 | |
| 38 | <refsynopsisdiv> |
| 39 | <funcsynopsis> |
| 40 | <funcsynopsisinfo>#include <xf86drm.h></funcsynopsisinfo> |
| 41 | </funcsynopsis> |
| 42 | </refsynopsisdiv> |
| 43 | |
| 44 | <refsect1> |
| 45 | <title>Description</title> |
| 46 | <para>Many modern high-end GPUs come with their own memory managers. They |
| 47 | even include several different caches that need to be synchronized |
| 48 | during access. Textures, framebuffers, command buffers and more need |
| 49 | to be stored in memory that can be accessed quickly by the GPU. |
| 50 | Therefore, memory management on GPUs is highly driver- and |
| 51 | hardware-dependent.</para> |
| 52 | |
| 53 | <para>However, there are several frameworks in the kernel that are used by |
| 54 | more than one driver. These can be used for trivial mode-setting |
| 55 | without requiring driver-dependent code. But for |
| 56 | hardware-accelerated rendering you need to read the manual pages for |
| 57 | the driver you want to work with.</para> |
| 58 | |
| 59 | <refsect2> |
| 60 | <title>Dumb-Buffers</title> |
| 61 | <para>Almost all in-kernel DRM hardware drivers support an API called |
| 62 | <emphasis>Dumb-Buffers</emphasis>. This API allows to create buffers |
| 63 | of arbitrary size that can be used for scanout. These buffers can be |
| 64 | memory mapped via |
| 65 | <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
| 66 | so you can render into them on the CPU. However, GPU access to these |
| 67 | buffers is often not possible. Therefore, they are fine for simple |
| 68 | tasks but not suitable for complex compositions and |
| 69 | renderings.</para> |
| 70 | |
| 71 | <para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl can be |
| 72 | used to create a dumb buffer. The kernel will return a 32bit handle |
| 73 | that can be used to manage the buffer with the DRM API. You can |
| 74 | create framebuffers with |
| 75 | <citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| 76 | and use it for mode-setting and scanout. To access the buffer, you |
| 77 | first need to retrieve the offset of the buffer. The |
| 78 | <constant>DRM_IOCTL_MODE_MAP_DUMB</constant> ioctl requests the DRM |
| 79 | subsystem to prepare the buffer for memory-mapping and returns a |
| 80 | fake-offset that can be used with |
| 81 | <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para> |
| 82 | |
| 83 | <para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl takes as |
| 84 | argument a structure of type |
| 85 | <structname>struct drm_mode_create_dumb</structname>: |
| 86 | |
| 87 | <programlisting> |
| 88 | struct drm_mode_create_dumb { |
| 89 | __u32 height; |
| 90 | __u32 width; |
| 91 | __u32 bpp; |
| 92 | __u32 flags; |
| 93 | |
| 94 | __u32 handle; |
| 95 | __u32 pitch; |
| 96 | __u64 size; |
| 97 | }; |
| 98 | </programlisting> |
| 99 | |
| 100 | The fields <structfield>height</structfield>, |
| 101 | <structfield>width</structfield>, <structfield>bpp</structfield> and |
| 102 | <structfield>flags</structfield> have to be provided by the caller. |
| 103 | The other fields are filled by the kernel with the return values. |
| 104 | <structfield>height</structfield> and |
| 105 | <structfield>width</structfield> are the dimensions of the |
| 106 | rectangular buffer that is created. <structfield>bpp</structfield> |
| 107 | is the number of bits-per-pixel and must be a multiple of |
| 108 | <literal>8</literal>. You most commonly want to pass |
| 109 | <literal>32</literal> here. The <structfield>flags</structfield> |
| 110 | field is currently unused and must be zeroed. Different flags to |
| 111 | modify the behavior may be added in the future. After calling the |
| 112 | ioctl, the <structfield>handle</structfield>, |
| 113 | <structfield>pitch</structfield> and <structfield>size</structfield> |
| 114 | fields are filled by the kernel. <structfield>handle</structfield> |
| 115 | is a 32bit gem handle that identifies the buffer. This is used by |
| 116 | several other calls that take a gem-handle or memory-buffer as |
| 117 | argument. The <structfield>pitch</structfield> field is the |
| 118 | pitch (or stride) of the new buffer. Most drivers use 32bit or 64bit |
| 119 | aligned stride-values. The <structfield>size</structfield> field |
| 120 | contains the absolute size in bytes of the buffer. This can normally |
| 121 | also be computed with |
| 122 | <emphasis>(height * pitch + width) * bpp / 4</emphasis>.</para> |
| 123 | |
| 124 | <para>To prepare the buffer for |
| 125 | <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
| 126 | you need to use the <constant>DRM_IOCTL_MODE_MAP_DUMB</constant> |
| 127 | ioctl. It takes as argument a structure of type |
| 128 | <structname>struct drm_mode_map_dumb</structname>: |
| 129 | |
| 130 | <programlisting> |
| 131 | struct drm_mode_map_dumb { |
| 132 | __u32 handle; |
| 133 | __u32 pad; |
| 134 | |
| 135 | __u64 offset; |
| 136 | }; |
| 137 | </programlisting> |
| 138 | |
| 139 | You need to put the gem-handle that was previously retrieved via |
| 140 | <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> into the |
| 141 | <structfield>handle</structfield> field. The |
| 142 | <structfield>pad</structfield> field is unused padding and must be |
| 143 | zeroed. After completion, the <structfield>offset</structfield> |
| 144 | field will contain an offset that can be used with |
| 145 | <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
| 146 | on the DRM file-descriptor.</para> |
| 147 | |
| 148 | <para>If you don't need your dumb-buffer, anymore, you have to destroy it |
| 149 | with <constant>DRM_IOCTL_MODE_DESTROY_DUMB</constant>. If you close |
| 150 | the DRM file-descriptor, all open dumb-buffers are automatically |
| 151 | destroyed. This ioctl takes as argument a structure of type |
| 152 | <structname>struct drm_mode_destroy_dumb</structname>: |
| 153 | |
| 154 | <programlisting> |
| 155 | struct drm_mode_destroy_dumb { |
| 156 | __u32 handle; |
| 157 | }; |
| 158 | </programlisting> |
| 159 | |
| 160 | You only need to put your handle into the |
| 161 | <structfield>handle</structfield> field. After this call, the handle |
| 162 | is invalid and may be reused for new buffers by the dumb-API.</para> |
| 163 | |
| 164 | </refsect2> |
| 165 | |
| 166 | <refsect2> |
| 167 | <title>TTM</title> |
| 168 | <para><emphasis>TTM</emphasis> stands for |
| 169 | <emphasis>Translation Table Manager</emphasis> and is a generic |
| 170 | memory-manager provided by the kernel. It does not provide a common |
| 171 | user-space API so you need to look at each driver interface if you |
| 172 | want to use it. See for instance the radeon manpages for more |
| 173 | information on memory-management with radeon and TTM.</para> |
| 174 | </refsect2> |
| 175 | |
| 176 | <refsect2> |
| 177 | <title>GEM</title> |
| 178 | <para><emphasis>GEM</emphasis> stands for |
| 179 | <emphasis>Graphics Execution Manager</emphasis> and is a generic DRM |
| 180 | memory-management framework in the kernel, that is used by many |
| 181 | different drivers. Gem is designed to manage graphics memory, |
| 182 | control access to the graphics device execution context and handle |
| 183 | essentially NUMA environment unique to modern graphics hardware. Gem |
| 184 | allows multiple applications to share graphics device resources |
| 185 | without the need to constantly reload the entire graphics card. Data |
| 186 | may be shared between multiple applications with gem ensuring that |
| 187 | the correct memory synchronization occurs.</para> |
| 188 | |
| 189 | <para>Gem provides simple mechanisms to manage graphics data and control |
| 190 | execution flow within the linux DRM subsystem. However, gem is not a |
| 191 | complete framework that is fully driver independent. Instead, if |
| 192 | provides many functions that are shared between many drivers, but |
| 193 | each driver has to implement most of memory-management with |
| 194 | driver-dependent ioctls. This manpage tries to describe the |
| 195 | semantics (and if it applies, the syntax) that is shared between all |
| 196 | drivers that use gem.</para> |
| 197 | |
| 198 | <para>All GEM APIs are defined as |
| 199 | <citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
| 200 | on the DRM file descriptor. An application must be authorized via |
| 201 | <citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| 202 | to the current DRM-Master to access the GEM subsystem. A driver that |
| 203 | does not support gem will return <constant>ENODEV</constant> for all |
| 204 | these ioctls. Invalid object handles return |
| 205 | <constant>EINVAL</constant> and invalid object names return |
| 206 | <constant>ENOENT</constant>.</para> |
| 207 | |
| 208 | <para>Gem provides explicit memory management primitives. System pages are |
| 209 | allocated when the object is created, either as the fundamental |
| 210 | storage for hardware where system memory is used by the graphics |
| 211 | processor directly, or as backing store for graphics-processor |
| 212 | resident memory.</para> |
| 213 | |
| 214 | <para>Objects are referenced from user-space using handles. These are, for |
| 215 | all intents and purposes, equivalent to file descriptors but avoid |
| 216 | the overhead. Newer kernel drivers also support the |
| 217 | <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 218 | infrastructure which can return real file-descriptor for gem-handles |
| 219 | using the linux dma-buf API. Objects may be published with a name so |
| 220 | that other applications and processes can access them. The name |
| 221 | remains valid as long as the object exists. Gem-objects are |
| 222 | reference counted in the kernel. The object is only destroyed when |
| 223 | all handles from user-space were closed.</para> |
| 224 | |
| 225 | <para>Gem-buffers cannot be created with a generic API. Each driver |
| 226 | provides its own API to create gem-buffers. See for example |
| 227 | <constant>DRM_I915_GEM_CREATE</constant>, |
| 228 | <constant>DRM_NOUVEAU_GEM_NEW</constant> or |
| 229 | <constant>DRM_RADEON_GEM_CREATE</constant>. Each of these ioctls |
| 230 | returns a gem-handle that can be passed to different generic ioctls. |
| 231 | The <emphasis>libgbm</emphasis> library from the |
| 232 | <emphasis>mesa3D</emphasis> distribution tries to provide a |
| 233 | driver-independent API to create gbm buffers and retrieve a |
| 234 | gbm-handle to them. It allows to create buffers for different |
| 235 | use-cases including scanout, rendering, cursors and CPU-access. See |
| 236 | the libgbm library for more information or look at the |
| 237 | driver-dependent man-pages (for example |
| 238 | <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 239 | or |
| 240 | <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para> |
| 241 | |
| 242 | <para>Gem-buffers can be closed with the |
| 243 | <constant>DRM_IOCTL_GEM_CLOSE</constant> ioctl. It takes as argument |
| 244 | a structure of type <structname>struct drm_gem_close</structname>: |
| 245 | |
| 246 | <programlisting> |
| 247 | struct drm_gem_close { |
| 248 | __u32 handle; |
| 249 | __u32 pad; |
| 250 | }; |
| 251 | </programlisting> |
| 252 | |
| 253 | The <structfield>handle</structfield> field is the gem-handle to be |
| 254 | closed. The <structfield>pad</structfield> field is unused padding. |
| 255 | It must be zeroed. After this call the gem handle cannot be used by |
| 256 | this process anymore and may be reused for new gem objects by the |
| 257 | gem API.</para> |
| 258 | |
| 259 | <para>If you want to share gem-objects between different processes, you |
| 260 | can create a name for them and pass this name to other processes |
| 261 | which can then open this gem-object. Names are currently 32bit |
| 262 | integer IDs and have no special protection. That is, if you put a |
| 263 | name on your gem-object, every other client that has access to the |
| 264 | DRM device and is authenticated via |
| 265 | <citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
| 266 | to the current DRM-Master, can <emphasis>guess</emphasis> the name |
| 267 | and open or access the gem-object. If you want more fine-grained |
| 268 | access control, you can use the new |
| 269 | <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 270 | API to retrieve file-descriptors for gem-handles. To create a name |
| 271 | for a gem-handle, you use the |
| 272 | <constant>DRM_IOCTL_GEM_FLINK</constant> ioctl. It takes as argument |
| 273 | a structure of type <structname>struct drm_gem_flink</structname>: |
| 274 | |
| 275 | <programlisting> |
| 276 | struct drm_gem_flink { |
| 277 | __u32 handle; |
| 278 | __u32 name; |
| 279 | }; |
| 280 | </programlisting> |
| 281 | |
| 282 | You have to put your handle into the |
| 283 | <structfield>handle</structfield> field. After completion, the |
| 284 | kernel has put the new unique name into the |
| 285 | <structfield>name</structfield> field. You can now pass this name to |
| 286 | other processes which can then import the name with the |
| 287 | <constant>DRM_IOCTL_GEM_OPEN</constant> ioctl. It takes as argument |
| 288 | a structure of type <structname>struct drm_gem_open</structname>: |
| 289 | |
| 290 | <programlisting> |
| 291 | struct drm_gem_open { |
| 292 | __u32 name; |
| 293 | |
| 294 | __u32 handle; |
| 295 | __u32 size; |
| 296 | }; |
| 297 | </programlisting> |
| 298 | |
| 299 | You have to fill in the <structfield>name</structfield> field with |
| 300 | the name of the gem-object that you want to open. The kernel will |
| 301 | fill in the <structfield>handle</structfield> and |
| 302 | <structfield>size</structfield> fields with the new handle and size |
| 303 | of the gem-object. You can now access the gem-object via the handle |
| 304 | as if you created it with the gem API.</para> |
| 305 | |
| 306 | <para>Besides generic buffer management, the GEM API does not provide any |
| 307 | generic access. Each driver implements its own functionality on top |
| 308 | of this API. This includes execution-buffers, GTT management, |
| 309 | context creation, CPU access, GPU I/O and more. The next |
| 310 | higher-level API is <emphasis>OpenGL</emphasis>. So if you want to |
| 311 | use more GPU features, you should use the |
| 312 | <emphasis>mesa3D</emphasis> library to create OpenGL contexts on DRM |
| 313 | devices. This does <emphasis>not</emphasis> require any |
| 314 | windowing-system like X11, but can also be done on raw DRM devices. |
| 315 | However, this is beyond the scope of this man-page. You may have a |
| 316 | look at other mesa3D manpages, including libgbm and libEGL. 2D |
| 317 | software-rendering (rendering with the CPU) can be achieved with the |
| 318 | dumb-buffer-API in a driver-independent fashion, however, for |
| 319 | hardware-accelerated 2D or 3D rendering you must use OpenGL. Any |
| 320 | other API that tries to abstract the driver-internals to access |
| 321 | GEM-execution-buffers and other GPU internals, would simply reinvent |
| 322 | OpenGL so it is not provided. But if you need more detailed |
| 323 | information for a specific driver, you may have a look into the |
| 324 | driver-manpages, including |
| 325 | <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 326 | <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 327 | and |
| 328 | <citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry>. |
| 329 | However, the |
| 330 | <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 331 | infrastructure and the generic gem API as described here allow |
| 332 | display-managers to handle graphics-buffers and render-clients |
| 333 | without any deeper knowledge of the GPU that is used. Moreover, it |
| 334 | allows to move objects between GPUs and implement complex |
| 335 | display-servers that don't do any rendering on their own. See its |
| 336 | man-page for more information.</para> |
| 337 | </refsect2> |
| 338 | </refsect1> |
| 339 | |
| 340 | <refsect1> |
| 341 | <title>Examples</title> |
| 342 | <para>This section includes examples for basic memory-management |
| 343 | tasks.</para> |
| 344 | |
| 345 | <refsect2> |
| 346 | <title>Dumb-Buffers</title> |
| 347 | <para>This examples shows how to create a dumb-buffer via the generic |
| 348 | DRM API. This is driver-independent (as long as the driver |
| 349 | supports dumb-buffers) and provides memory-mapped buffers that can |
| 350 | be used for scanout. This example creates a full-HD 1920x1080 |
| 351 | buffer with 32 bits-per-pixel and a color-depth of 24 bits. The |
| 352 | buffer is then bound to a framebuffer which can be used for |
| 353 | scanout with the KMS API (see |
| 354 | <citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para> |
| 355 | |
| 356 | <programlisting> |
| 357 | struct drm_mode_create_dumb creq; |
| 358 | struct drm_mode_destroy_dumb dreq; |
| 359 | struct drm_mode_map_dumb mreq; |
| 360 | uint32_t fb; |
| 361 | int ret; |
| 362 | void *map; |
| 363 | |
| 364 | /* create dumb buffer */ |
| 365 | memset(&creq, 0, sizeof(creq)); |
| 366 | creq.width = 1920; |
| 367 | creq.height = 1080; |
| 368 | creq.bpp = 32; |
| 369 | ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); |
| 370 | if (ret < 0) { |
| 371 | /* buffer creation failed; see "errno" for more error codes */ |
| 372 | ... |
| 373 | } |
| 374 | /* creq.pitch, creq.handle and creq.size are filled by this ioctl with |
| 375 | * the requested values and can be used now. */ |
| 376 | |
| 377 | /* create framebuffer object for the dumb-buffer */ |
| 378 | ret = drmModeAddFB(fd, 1920, 1080, 24, 32, creq.pitch, creq.handle, &fb); |
| 379 | if (ret) { |
| 380 | /* frame buffer creation failed; see "errno" */ |
| 381 | ... |
| 382 | } |
| 383 | /* the framebuffer "fb" can now used for scanout with KMS */ |
| 384 | |
| 385 | /* prepare buffer for memory mapping */ |
| 386 | memset(&mreq, 0, sizeof(mreq)); |
| 387 | mreq.handle = creq.handle; |
| 388 | ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); |
| 389 | if (ret) { |
| 390 | /* DRM buffer preparation failed; see "errno" */ |
| 391 | ... |
| 392 | } |
| 393 | /* mreq.offset now contains the new offset that can be used with mmap() */ |
| 394 | |
| 395 | /* perform actual memory mapping */ |
| 396 | map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); |
| 397 | if (map == MAP_FAILED) { |
| 398 | /* memory-mapping failed; see "errno" */ |
| 399 | ... |
| 400 | } |
| 401 | |
| 402 | /* clear the framebuffer to 0 */ |
| 403 | memset(map, 0, creq.size); |
| 404 | </programlisting> |
| 405 | |
| 406 | </refsect2> |
| 407 | |
| 408 | </refsect1> |
| 409 | |
| 410 | <refsect1> |
| 411 | <title>Reporting Bugs</title> |
| 412 | <para>Bugs in this manual should be reported to |
| 413 | http://bugs.freedesktop.org under the "Mesa" product, with "Other" or |
| 414 | "libdrm" as the component.</para> |
| 415 | </refsect1> |
| 416 | |
| 417 | <refsect1> |
| 418 | <title>See Also</title> |
| 419 | <para> |
| 420 | <citerefentry><refentrytitle>drm</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 421 | <citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 422 | <citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 423 | <citerefentry><refentrytitle>drmAvailable</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| 424 | <citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
| 425 | <citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 426 | <citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
| 427 | <citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
| 428 | </para> |
| 429 | </refsect1> |
| 430 | </refentry> |