354 lines
14 KiB
Groff
354 lines
14 KiB
Groff
.\" Man page generated from reStructuredText.
|
|
.
|
|
.
|
|
.nr rst2man-indent-level 0
|
|
.
|
|
.de1 rstReportMargin
|
|
\\$1 \\n[an-margin]
|
|
level \\n[rst2man-indent-level]
|
|
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
-
|
|
\\n[rst2man-indent0]
|
|
\\n[rst2man-indent1]
|
|
\\n[rst2man-indent2]
|
|
..
|
|
.de1 INDENT
|
|
.\" .rstReportMargin pre:
|
|
. RS \\$1
|
|
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
|
. nr rst2man-indent-level +1
|
|
.\" .rstReportMargin post:
|
|
..
|
|
.de UNINDENT
|
|
. RE
|
|
.\" indent \\n[an-margin]
|
|
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
.nr rst2man-indent-level -1
|
|
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
|
..
|
|
.TH "DRM-MEMORY" 7 "September 2012" "" "Direct Rendering Manager"
|
|
.SH NAME
|
|
drm-memory \- DRM Memory Management
|
|
.SH SYNOPSIS
|
|
.sp
|
|
\fB#include <xf86drm.h>\fP
|
|
.SH DESCRIPTION
|
|
.sp
|
|
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.
|
|
.sp
|
|
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.
|
|
.SS Dumb\-Buffers
|
|
.sp
|
|
Almost all in\-kernel DRM hardware drivers support an API called \fIDumb\-Buffers\fP\&.
|
|
This API allows to create buffers of arbitrary size that can be used for
|
|
scanout. These buffers can be memory mapped via \fBmmap\fP(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.
|
|
.sp
|
|
The \fBDRM_IOCTL_MODE_CREATE_DUMB\fP ioctl can be used to create a dumb buffer.
|
|
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 \fBdrmModeAddFB\fP(3) and
|
|
use it for mode\-setting and scanout. To access the buffer, you first need to
|
|
retrieve the offset of the buffer. The \fBDRM_IOCTL_MODE_MAP_DUMB\fP ioctl
|
|
requests the DRM subsystem to prepare the buffer for memory\-mapping and returns
|
|
a fake\-offset that can be used with \fBmmap\fP(2).
|
|
.sp
|
|
The \fBDRM_IOCTL_MODE_CREATE_DUMB\fP ioctl takes as argument a structure of type
|
|
\fBstruct drm_mode_create_dumb\fP:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
struct drm_mode_create_dumb {
|
|
__u32 height;
|
|
__u32 width;
|
|
__u32 bpp;
|
|
__u32 flags;
|
|
|
|
__u32 handle;
|
|
__u32 pitch;
|
|
__u64 size;
|
|
};
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
The fields \fIheight\fP, \fIwidth\fP, \fIbpp\fP and \fIflags\fP have to be provided by the
|
|
caller. The other fields are filled by the kernel with the return values.
|
|
\fIheight\fP and \fIwidth\fP are the dimensions of the rectangular buffer that is
|
|
created. \fIbpp\fP is the number of bits\-per\-pixel and must be a multiple 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 behavior may be added in the
|
|
future. After calling the ioctl, the handle, pitch and size fields are filled
|
|
by the kernel. \fIhandle\fP 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 \fIpitch\fP 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
|
|
\fB(height * pitch + width) * bpp / 4\fP\&.
|
|
.sp
|
|
To prepare the buffer for \fBmmap\fP(2) you need to use the
|
|
\fBDRM_IOCTL_MODE_MAP_DUMB\fP ioctl. It takes as argument a structure of type
|
|
\fBstruct drm_mode_map_dumb\fP:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
struct drm_mode_map_dumb {
|
|
__u32 handle;
|
|
__u32 pad;
|
|
|
|
__u64 offset;
|
|
};
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
You need to put the gem\-handle that was previously retrieved via
|
|
\fBDRM_IOCTL_MODE_CREATE_DUMB\fP into the \fIhandle\fP field. The \fIpad\fP field is
|
|
unused padding and must be zeroed. After completion, the \fIoffset\fP field will
|
|
contain an offset that can be used with \fBmmap\fP(2) on the DRM
|
|
file\-descriptor.
|
|
.sp
|
|
If you don\(aqt need your dumb\-buffer, anymore, you have to destroy it with
|
|
\fBDRM_IOCTL_MODE_DESTROY_DUMB\fP\&. If you close the DRM file\-descriptor, all open
|
|
dumb\-buffers are automatically destroyed. This ioctl takes as argument a
|
|
structure of type \fBstruct drm_mode_destroy_dumb\fP:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
struct drm_mode_destroy_dumb {
|
|
__u32 handle;
|
|
};
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
You only need to put your handle into the \fIhandle\fP field. After this call, the
|
|
handle is invalid and may be reused for new buffers by the dumb\-API.
|
|
.SS TTM
|
|
.sp
|
|
\fITTM\fP stands for \fITranslation Table Manager\fP 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 man pages for more information on memory\-management with radeon and TTM.
|
|
.SS GEM
|
|
.sp
|
|
\fIGEM\fP stands for \fIGraphics Execution Manager\fP 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.
|
|
.sp
|
|
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.
|
|
.sp
|
|
All GEM APIs are defined as \fBioctl\fP(2) on the DRM file descriptor. An
|
|
application must be authorized via \fBdrmAuthMagic\fP(3) to the current
|
|
DRM\-Master to access the GEM subsystem. A driver that does not support GEM will
|
|
return \fBENODEV\fP for all these ioctls. Invalid object handles return
|
|
\fBEINVAL\fP and invalid object names return \fBENOENT\fP\&.
|
|
.sp
|
|
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.
|
|
.sp
|
|
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 \fBdrm\-prime\fP (7) 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.
|
|
.sp
|
|
GEM\-buffers cannot be created with a generic API. Each driver provides its own
|
|
API to create GEM\-buffers. See for example \fBDRM_I915_GEM_CREATE\fP,
|
|
\fBDRM_NOUVEAU_GEM_NEW\fP or \fBDRM_RADEON_GEM_CREATE\fP\&. Each of these ioctls
|
|
returns a GEM\-handle that can be passed to different generic ioctls. The
|
|
\fIlibgbm\fP library from the \fImesa3D\fP 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 \fBdrm\-intel\fP(7) or
|
|
\fBdrm\-radeon\fP(7)).
|
|
.sp
|
|
GEM\-buffers can be closed with \fBdrmCloseBufferHandle\fP(3). It takes as
|
|
argument the GEM\-handle to be closed. 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.
|
|
.sp
|
|
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\-object, every other client
|
|
that has access to the DRM device and is authenticated via
|
|
\fBdrmAuthMagic\fP(3) to the current DRM\-Master, can \fIguess\fP the name and open
|
|
or access the GEM\-object. If you want more fine\-grained access control, you can
|
|
use the new \fBdrm\-prime\fP(7) API to retrieve file\-descriptors for
|
|
GEM\-handles. To create a name for a GEM\-handle, you use the
|
|
\fBDRM_IOCTL_GEM_FLINK\fP ioctl. It takes as argument a structure of type
|
|
\fBstruct drm_gem_flink\fP:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
struct drm_gem_flink {
|
|
__u32 handle;
|
|
__u32 name;
|
|
};
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
You have to put your handle into the \fIhandle\fP 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
|
|
\fBDRM_IOCTL_GEM_OPEN\fP ioctl. It takes as argument a structure of type
|
|
\fBstruct drm_gem_open\fP:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
struct drm_gem_open {
|
|
__u32 name;
|
|
|
|
__u32 handle;
|
|
__u32 size;
|
|
};
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
You have to fill in the \fIname\fP field with the name of the GEM\-object that you
|
|
want to open. The kernel will fill in the \fIhandle\fP and \fIsize\fP 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.
|
|
.sp
|
|
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 \fIOpenGL\fP\&. So if you want to use more
|
|
GPU features, you should use the \fImesa3D\fP library to create OpenGL contexts on
|
|
DRM devices. This does \fInot\fP 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
|
|
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 \fBdrm\-intel\fP(7), \fBdrm\-radeon\fP(7) and
|
|
\fBdrm\-nouveau\fP(7). However, the \fBdrm\-prime\fP(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 allows to move objects between GPUs and implement
|
|
complex display\-servers that don\(aqt do any rendering on their own. See its
|
|
man\-page for more information.
|
|
.SH EXAMPLES
|
|
.sp
|
|
This section includes examples for basic memory\-management tasks.
|
|
.SS Dumb\-Buffers
|
|
.sp
|
|
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 \fBdrm\-kms\fP(7)).
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.nf
|
|
.ft C
|
|
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 \(dqerrno\(dq 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 \(dqerrno\(dq */
|
|
...
|
|
}
|
|
/* the framebuffer \(dqfb\(dq 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 \(dqerrno\(dq */
|
|
...
|
|
}
|
|
/* 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 \(dqerrno\(dq */
|
|
...
|
|
}
|
|
|
|
/* clear the framebuffer to 0 */
|
|
memset(map, 0, creq.size);
|
|
.ft P
|
|
.fi
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.SH REPORTING BUGS
|
|
.sp
|
|
Bugs in this manual should be reported to
|
|
\fI\%https://gitlab.freedesktop.org/mesa/drm/\-/issues\fP
|
|
.SH SEE ALSO
|
|
.sp
|
|
\fBdrm\fP(7), \fBdrm\-kms\fP(7), \fBdrm\-prime\fP(7), \fBdrmAvailable\fP(3),
|
|
\fBdrmOpen\fP(3), \fBdrm\-intel\fP(7), \fBdrm\-radeon\fP(7), \fBdrm\-nouveau\fP(7)
|
|
.\" Generated by docutils manpage writer.
|
|
.
|