drm-memory(7)

SECCIÓN: 7 - Miscelánea

DRM-MEMORY(7) Direct Rendering Manager DRM-MEMORY(7)

NAME

drm-memory - DRM Memory Management

SYNOPSIS

#include <xf86drm.h>

DESCRIPTION

Many modern high-end GPUs come with their own memory managers. They

even include several different caches that need to be synchronized dur‐

ing 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.

However, there are several frameworks in the kernel that are used by

more than one driver. These can be used for trivial mode-setting with‐

out requiring driver-dependent code. But for hardware-accelerated ren‐

dering you need to read the manual pages for the driver you want to

work with.

Dumb-Buffers

Almost all in-kernel DRM hardware drivers support an API called

Dumb-Buffers. This API allows to create buffers of arbitrary size that

can be used for scanout. These buffers can be memory mapped via mmap(2)

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.

The DRM_IOCTL_MODE_CREATE_DUMB ioctl can be used to create a dumb buf‐

fer. The kernel will return a 32-bit handle that can be used to manage

the buffer with the DRM API. You can create framebuffers with drmMod‐

eAddFB(3) and use it for mode-setting and scanout. To access the buf‐

fer, you first need to retrieve the offset of the buffer. The

DRM_IOCTL_MODE_MAP_DUMB ioctl requests the DRM subsystem to prepare the

buffer for memory-mapping and returns a fake-offset that can be used

with mmap(2).

The DRM_IOCTL_MODE_CREATE_DUMB ioctl takes as argument a structure of

type struct drm_mode_create_dumb:

struct drm_mode_create_dumb {

__u32 height;

__u32 width;

__u32 bpp;

__u32 flags;

__u32 handle;

__u32 pitch;

__u64 size;

};

The fields height, width, bpp and flags have to be provided by the

caller. The other fields are filled by the kernel with the return val‐

ues. height and width are the dimensions of the rectangular buffer

that is created. bpp is the number of bits-per-pixel and must be a mul‐

tiple of 8. You most commonly want to pass 32 here. The flags field is

currently unused and must be zeroed. Different flags to modify the be‐

havior may be added in the future. After calling the ioctl, the handle,

pitch and size fields are filled by the kernel. handle is a 32-bit gem

handle that identifies the buffer. This is used by several other calls

that take a gem-handle or memory-buffer as argument. The pitch field is

the pitch (or stride) of the new buffer. Most drivers use 32-bit or

64-bit aligned stride-values. The size field contains the absolute size

in bytes of the buffer. This can normally also be computed with (height

* pitch + width) * bpp / 4.

To prepare the buffer for mmap(2) you need to use the

DRM_IOCTL_MODE_MAP_DUMB ioctl. It takes as argument a structure of type

struct drm_mode_map_dumb:

struct drm_mode_map_dumb {

__u32 handle;

__u32 pad;

__u64 offset;

};

You need to put the gem-handle that was previously retrieved via

DRM_IOCTL_MODE_CREATE_DUMB into the handle field. The pad field is un‐

used padding and must be zeroed. After completion, the offset field

will contain an offset that can be used with mmap(2) on the DRM

file-descriptor.

If you don't need your dumb-buffer, anymore, you have to destroy it

with DRM_IOCTL_MODE_DESTROY_DUMB. If you close the DRM file-descriptor,

all open dumb-buffers are automatically destroyed. This ioctl takes as

argument a structure of type struct drm_mode_destroy_dumb:

struct drm_mode_destroy_dumb {

__u32 handle;

};

You only need to put your handle into the handle field. After this

call, the handle is invalid and may be reused for new buffers by the

dumb-API.

TTM

TTM stands for Translation Table Manager and is a generic memory-man‐

ager 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 man pages for more information on mem‐

ory-management with radeon and TTM.

GEM

GEM stands for Graphics Execution Manager and is a generic DRM mem‐

ory-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 envi‐

ronment unique to modern graphics hardware. GEM allows multiple appli‐

cations to share graphics device resources without the need to con‐

stantly reload the entire graphics card. Data may be shared between

multiple applications with gem ensuring that the correct memory syn‐

chronization occurs.

GEM provides simple mechanisms to manage graphics data and control exe‐

cution flow within the linux DRM subsystem. However, GEM is not a com‐

plete 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 ap‐

plies, the syntax) that is shared between all drivers that use GEM.

All GEM APIs are defined as ioctl(2) on the DRM file descriptor. An ap‐

plication must be authorized via drmAuthMagic(3) to the current

DRM-Master to access the GEM subsystem. A driver that does not support

GEM will return ENODEV for all these ioctls. Invalid object handles re‐

turn EINVAL and invalid object names return ENOENT.

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 di‐

rectly, or as backing store for graphics-processor resident memory.

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 drm-prime (7) infra‐

structure 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.

GEM-buffers cannot be created with a generic API. Each driver provides

its own API to create GEM-buffers. See for example DRM_I915_GEM_CREATE,

DRM_NOUVEAU_GEM_NEW or DRM_RADEON_GEM_CREATE. Each of these ioctls re‐

turns a GEM-handle that can be passed to different generic ioctls. The

libgbm library from the mesa3D 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

drm-intel(7) or drm-radeon(7)).

GEM-buffers can be closed with drmCloseBufferHandle(3). It takes as ar‐

gument the GEM-handle to be closed. After this call the GEM handle can‐

not be used by this process anymore and may be reused for new GEM ob‐

jects by the GEM API.

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 32-bit integer IDs and

have no special protection. That is, if you put a name on your GEM-ob‐

ject, every other client that has access to the DRM device and is au‐

thenticated via drmAuthMagic(3) to the current DRM-Master, can guess

the name and open or access the GEM-object. If you want more

fine-grained access control, you can use the new drm-prime(7) API to

retrieve file-descriptors for GEM-handles. To create a name for a

GEM-handle, you use the DRM_IOCTL_GEM_FLINK ioctl. It takes as argument

a structure of type struct drm_gem_flink:

struct drm_gem_flink {

__u32 handle;

__u32 name;

};

You have to put your handle into the handle field. After completion,

the kernel has put the new unique name into the name field. You can now

pass this name to other processes which can then import the name with

the DRM_IOCTL_GEM_OPEN ioctl. It takes as argument a structure of type

struct drm_gem_open:

struct drm_gem_open {

__u32 name;

__u32 handle;

__u32 size;

};

You have to fill in the name field with the name of the GEM-object that

you want to open. The kernel will fill in the handle and size 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.

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 cre‐

ation, CPU access, GPU I/O and more. The next higher-level API is

OpenGL. So if you want to use more GPU features, you should use the

mesa3D library to create OpenGL contexts on DRM devices. This does not

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 man pages, 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 hard‐

ware-accelerated 2D or 3D rendering you must use OpenGL. Any other API

that tries to abstract the driver-internals to access GEM-execu‐

tion-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, includ‐

ing drm-intel(7), drm-radeon(7) and drm-nouveau(7). However, the

drm-prime(7) 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 al‐

lows 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 in‐

formation.

EXAMPLES

This section includes examples for basic memory-management tasks.

Dumb-Buffers

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

drm-kms(7)).

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(&creq, 0, sizeof(creq));

creq.width = 1920;

creq.height = 1080;

creq.bpp = 32;

ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);

if (ret < 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, &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(&mreq, 0, sizeof(mreq));

mreq.handle = creq.handle;

ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &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);

REPORTING BUGS

Bugs in this manual should be reported to

https://gitlab.freedesktop.org/mesa/drm/-/issues

SEE ALSO

drm(7), drm-kms(7), drm-prime(7), drmAvailable(3), drmOpen(3), drm-in‐

tel(7), drm-radeon(7), drm-nouveau(7)

September 2012 DRM-MEMORY(7)

***

Índice de la Sección 7

Índice General