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