xref: /aosp_15_r20/external/libdrm/man/drm-memory.7.rst (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1==========
2drm-memory
3==========
4
5---------------------
6DRM Memory Management
7---------------------
8
9:Date: September 2012
10:Manual section: 7
11:Manual group: Direct Rendering Manager
12
13Synopsis
14========
15
16``#include <xf86drm.h>``
17
18Description
19===========
20
21Many modern high-end GPUs come with their own memory managers. They even
22include several different caches that need to be synchronized during access.
23Textures, framebuffers, command buffers and more need to be stored in memory
24that can be accessed quickly by the GPU. Therefore, memory management on GPUs
25is highly driver- and hardware-dependent.
26
27However, there are several frameworks in the kernel that are used by more than
28one driver. These can be used for trivial mode-setting without requiring
29driver-dependent code. But for hardware-accelerated rendering you need to read
30the manual pages for the driver you want to work with.
31
32Dumb-Buffers
33------------
34
35Almost all in-kernel DRM hardware drivers support an API called *Dumb-Buffers*.
36This API allows to create buffers of arbitrary size that can be used for
37scanout. These buffers can be memory mapped via **mmap**\ (2) so you can render
38into them on the CPU. However, GPU access to these buffers is often not
39possible. Therefore, they are fine for simple tasks but not suitable for
40complex compositions and renderings.
41
42The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl can be used to create a dumb buffer.
43The kernel will return a 32-bit handle that can be used to manage the buffer
44with the DRM API. You can create framebuffers with **drmModeAddFB**\ (3) and
45use it for mode-setting and scanout. To access the buffer, you first need to
46retrieve the offset of the buffer. The ``DRM_IOCTL_MODE_MAP_DUMB`` ioctl
47requests the DRM subsystem to prepare the buffer for memory-mapping and returns
48a fake-offset that can be used with **mmap**\ (2).
49
50The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl takes as argument a structure of type
51``struct drm_mode_create_dumb``:
52
53::
54
55   struct drm_mode_create_dumb {
56       __u32 height;
57       __u32 width;
58       __u32 bpp;
59       __u32 flags;
60
61       __u32 handle;
62       __u32 pitch;
63       __u64 size;
64   };
65
66The fields *height*, *width*, *bpp* and *flags* have to be provided by the
67caller. The other fields are filled by the kernel with the return values.
68*height* and *width* are the dimensions of the rectangular buffer that is
69created. *bpp* is the number of bits-per-pixel and must be a multiple of 8. You
70most commonly want to pass 32 here. The flags field is currently unused and
71must be zeroed. Different flags to modify the behavior may be added in the
72future. After calling the ioctl, the handle, pitch and size fields are filled
73by the kernel. *handle* is a 32-bit gem handle that identifies the buffer. This
74is used by several other calls that take a gem-handle or memory-buffer as
75argument. The *pitch* field is the pitch (or stride) of the new buffer. Most
76drivers use 32-bit or 64-bit aligned stride-values. The size field contains the
77absolute size in bytes of the buffer. This can normally also be computed with
78``(height * pitch + width) * bpp / 4``.
79
80To prepare the buffer for **mmap**\ (2) you need to use the
81``DRM_IOCTL_MODE_MAP_DUMB`` ioctl. It takes as argument a structure of type
82``struct drm_mode_map_dumb``:
83
84::
85
86   struct drm_mode_map_dumb {
87       __u32 handle;
88       __u32 pad;
89
90       __u64 offset;
91   };
92
93You need to put the gem-handle that was previously retrieved via
94``DRM_IOCTL_MODE_CREATE_DUMB`` into the *handle* field. The *pad* field is
95unused padding and must be zeroed. After completion, the *offset* field will
96contain an offset that can be used with **mmap**\ (2) on the DRM
97file-descriptor.
98
99If you don't need your dumb-buffer, anymore, you have to destroy it with
100``DRM_IOCTL_MODE_DESTROY_DUMB``. If you close the DRM file-descriptor, all open
101dumb-buffers are automatically destroyed. This ioctl takes as argument a
102structure of type ``struct drm_mode_destroy_dumb``:
103
104::
105
106   struct drm_mode_destroy_dumb {
107       __u32 handle;
108   };
109
110You only need to put your handle into the *handle* field. After this call, the
111handle is invalid and may be reused for new buffers by the dumb-API.
112
113TTM
114---
115
116*TTM* stands for *Translation Table Manager* and is a generic memory-manager
117provided by the kernel. It does not provide a common user-space API so you need
118to look at each driver interface if you want to use it. See for instance the
119radeon man pages for more information on memory-management with radeon and TTM.
120
121GEM
122---
123
124*GEM* stands for *Graphics Execution Manager* and is a generic DRM
125memory-management framework in the kernel, that is used by many different
126drivers. GEM is designed to manage graphics memory, control access to the
127graphics device execution context and handle essentially NUMA environment
128unique to modern graphics hardware. GEM allows multiple applications to share
129graphics device resources without the need to constantly reload the entire
130graphics card. Data may be shared between multiple applications with gem
131ensuring that the correct memory synchronization occurs.
132
133GEM provides simple mechanisms to manage graphics data and control execution
134flow within the linux DRM subsystem. However, GEM is not a complete framework
135that is fully driver independent. Instead, if provides many functions that are
136shared between many drivers, but each driver has to implement most of
137memory-management with driver-dependent ioctls. This manpage tries to describe
138the semantics (and if it applies, the syntax) that is shared between all
139drivers that use GEM.
140
141All GEM APIs are defined as **ioctl**\ (2) on the DRM file descriptor. An
142application must be authorized via **drmAuthMagic**\ (3) to the current
143DRM-Master to access the GEM subsystem. A driver that does not support GEM will
144return ``ENODEV`` for all these ioctls. Invalid object handles return
145``EINVAL`` and invalid object names return ``ENOENT``.
146
147Gem provides explicit memory management primitives. System pages are allocated
148when the object is created, either as the fundamental storage for hardware
149where system memory is used by the graphics processor directly, or as backing
150store for graphics-processor resident memory.
151
152Objects are referenced from user-space using handles. These are, for all
153intents and purposes, equivalent to file descriptors but avoid the overhead.
154Newer kernel drivers also support the **drm-prime** (7) infrastructure which
155can return real file-descriptor for GEM-handles using the linux DMA-BUF API.
156Objects may be published with a name so that other applications and processes
157can access them. The name remains valid as long as the object exists.
158GEM-objects are reference counted in the kernel. The object is only destroyed
159when all handles from user-space were closed.
160
161GEM-buffers cannot be created with a generic API. Each driver provides its own
162API to create GEM-buffers. See for example ``DRM_I915_GEM_CREATE``,
163``DRM_NOUVEAU_GEM_NEW`` or ``DRM_RADEON_GEM_CREATE``. Each of these ioctls
164returns a GEM-handle that can be passed to different generic ioctls. The
165*libgbm* library from the *mesa3D* distribution tries to provide a
166driver-independent API to create GBM buffers and retrieve a GBM-handle to them.
167It allows to create buffers for different use-cases including scanout,
168rendering, cursors and CPU-access. See the libgbm library for more information
169or look at the driver-dependent man-pages (for example **drm-intel**\ (7) or
170**drm-radeon**\ (7)).
171
172GEM-buffers can be closed with **drmCloseBufferHandle**\ (3). It takes as
173argument the GEM-handle to be closed. After this call the GEM handle cannot be
174used by this process anymore and may be reused for new GEM objects by the GEM
175API.
176
177If you want to share GEM-objects between different processes, you can create a
178name for them and pass this name to other processes which can then open this
179GEM-object. Names are currently 32-bit integer IDs and have no special
180protection. That is, if you put a name on your GEM-object, every other client
181that has access to the DRM device and is authenticated via
182**drmAuthMagic**\ (3) to the current DRM-Master, can *guess* the name and open
183or access the GEM-object. If you want more fine-grained access control, you can
184use the new **drm-prime**\ (7) API to retrieve file-descriptors for
185GEM-handles. To create a name for a GEM-handle, you use the
186``DRM_IOCTL_GEM_FLINK`` ioctl. It takes as argument a structure of type
187``struct drm_gem_flink``:
188
189::
190
191   struct drm_gem_flink {
192       __u32 handle;
193       __u32 name;
194   };
195
196You have to put your handle into the *handle* field. After completion, the
197kernel has put the new unique name into the name field. You can now pass
198this name to other processes which can then import the name with the
199``DRM_IOCTL_GEM_OPEN`` ioctl. It takes as argument a structure of type
200``struct drm_gem_open``:
201
202::
203
204   struct drm_gem_open {
205       __u32 name;
206
207       __u32 handle;
208       __u32 size;
209   };
210
211You have to fill in the *name* field with the name of the GEM-object that you
212want to open. The kernel will fill in the *handle* and *size* fields with the
213new handle and size of the GEM-object. You can now access the GEM-object via
214the handle as if you created it with the GEM API.
215
216Besides generic buffer management, the GEM API does not provide any generic
217access. Each driver implements its own functionality on top of this API. This
218includes execution-buffers, GTT management, context creation, CPU access, GPU
219I/O and more. The next higher-level API is *OpenGL*. So if you want to use more
220GPU features, you should use the *mesa3D* library to create OpenGL contexts on
221DRM devices. This does *not* require any windowing-system like X11, but can
222also be done on raw DRM devices. However, this is beyond the scope of this
223man-page. You may have a look at other mesa3D man pages, including libgbm and
224libEGL. 2D software-rendering (rendering with the CPU) can be achieved with the
225dumb-buffer-API in a driver-independent fashion, however, for
226hardware-accelerated 2D or 3D rendering you must use OpenGL. Any other API that
227tries to abstract the driver-internals to access GEM-execution-buffers and
228other GPU internals, would simply reinvent OpenGL so it is not provided. But if
229you need more detailed information for a specific driver, you may have a look
230into the driver-manpages, including **drm-intel**\ (7), **drm-radeon**\ (7) and
231**drm-nouveau**\ (7). However, the **drm-prime**\ (7) infrastructure and the
232generic GEM API as described here allow display-managers to handle
233graphics-buffers and render-clients without any deeper knowledge of the GPU
234that is used. Moreover, it allows to move objects between GPUs and implement
235complex display-servers that don't do any rendering on their own. See its
236man-page for more information.
237
238Examples
239========
240
241This section includes examples for basic memory-management tasks.
242
243Dumb-Buffers
244------------
245
246This examples shows how to create a dumb-buffer via the generic DRM API.
247This is driver-independent (as long as the driver supports dumb-buffers)
248and provides memory-mapped buffers that can be used for scanout. This
249example creates a full-HD 1920x1080 buffer with 32 bits-per-pixel and a
250color-depth of 24 bits. The buffer is then bound to a framebuffer which
251can be used for scanout with the KMS API (see **drm-kms**\ (7)).
252
253::
254
255   struct drm_mode_create_dumb creq;
256   struct drm_mode_destroy_dumb dreq;
257   struct drm_mode_map_dumb mreq;
258   uint32_t fb;
259   int ret;
260   void *map;
261
262   /* create dumb buffer */
263   memset(&creq, 0, sizeof(creq));
264   creq.width = 1920;
265   creq.height = 1080;
266   creq.bpp = 32;
267   ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
268   if (ret < 0) {
269       /* buffer creation failed; see "errno" for more error codes */
270       ...
271   }
272   /* creq.pitch, creq.handle and creq.size are filled by this ioctl with
273    * the requested values and can be used now. */
274
275   /* create framebuffer object for the dumb-buffer */
276   ret = drmModeAddFB(fd, 1920, 1080, 24, 32, creq.pitch, creq.handle, &fb);
277   if (ret) {
278       /* frame buffer creation failed; see "errno" */
279       ...
280   }
281   /* the framebuffer "fb" can now used for scanout with KMS */
282
283   /* prepare buffer for memory mapping */
284   memset(&mreq, 0, sizeof(mreq));
285   mreq.handle = creq.handle;
286   ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
287   if (ret) {
288       /* DRM buffer preparation failed; see "errno" */
289       ...
290   }
291   /* mreq.offset now contains the new offset that can be used with mmap() */
292
293   /* perform actual memory mapping */
294   map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
295   if (map == MAP_FAILED) {
296       /* memory-mapping failed; see "errno" */
297       ...
298   }
299
300   /* clear the framebuffer to 0 */
301   memset(map, 0, creq.size);
302
303Reporting Bugs
304==============
305
306Bugs in this manual should be reported to
307https://gitlab.freedesktop.org/mesa/drm/-/issues
308
309See Also
310========
311
312**drm**\ (7), **drm-kms**\ (7), **drm-prime**\ (7), **drmAvailable**\ (3),
313**drmOpen**\ (3), **drm-intel**\ (7), **drm-radeon**\ (7), **drm-nouveau**\ (7)
314