You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
20 KiB
430 lines
20 KiB
<?xml version='1.0'?> <!--*-nxml-*--> |
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> |
|
|
|
<!-- |
|
Written 2012 by David Herrmann <dh.herrmann@googlemail.com> |
|
Dedicated to the Public Domain |
|
--> |
|
|
|
<refentry id="drm-memory"> |
|
<refentryinfo> |
|
<title>Direct Rendering Manager</title> |
|
<productname>libdrm</productname> |
|
<date>September 2012</date> |
|
<authorgroup> |
|
<author> |
|
<contrib>Developer</contrib> |
|
<firstname>David</firstname> |
|
<surname>Herrmann</surname> |
|
<email>dh.herrmann@googlemail.com</email> |
|
</author> |
|
</authorgroup> |
|
</refentryinfo> |
|
|
|
<refmeta> |
|
<refentrytitle>drm-memory</refentrytitle> |
|
<manvolnum>7</manvolnum> |
|
</refmeta> |
|
|
|
<refnamediv> |
|
<refname>drm-memory</refname> |
|
<refname>drm-mm</refname> |
|
<refname>drm-gem</refname> |
|
<refname>drm-ttm</refname> |
|
<refpurpose>DRM Memory Management</refpurpose> |
|
</refnamediv> |
|
|
|
<refsynopsisdiv> |
|
<funcsynopsis> |
|
<funcsynopsisinfo>#include <xf86drm.h></funcsynopsisinfo> |
|
</funcsynopsis> |
|
</refsynopsisdiv> |
|
|
|
<refsect1> |
|
<title>Description</title> |
|
<para>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.</para> |
|
|
|
<para>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.</para> |
|
|
|
<refsect2> |
|
<title>Dumb-Buffers</title> |
|
<para>Almost all in-kernel DRM hardware drivers support an API called |
|
<emphasis>Dumb-Buffers</emphasis>. This API allows to create buffers |
|
of arbitrary size that can be used for scanout. These buffers can be |
|
memory mapped via |
|
<citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
|
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.</para> |
|
|
|
<para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl can be |
|
used to create a dumb buffer. The kernel will return a 32bit handle |
|
that can be used to manage the buffer with the DRM API. You can |
|
create framebuffers with |
|
<citerefentry><refentrytitle>drmModeAddFB</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
|
and use it for mode-setting and scanout. To access the buffer, you |
|
first need to retrieve the offset of the buffer. The |
|
<constant>DRM_IOCTL_MODE_MAP_DUMB</constant> ioctl requests the DRM |
|
subsystem to prepare the buffer for memory-mapping and returns a |
|
fake-offset that can be used with |
|
<citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para> |
|
|
|
<para>The <constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> ioctl takes as |
|
argument a structure of type |
|
<structname>struct drm_mode_create_dumb</structname>: |
|
|
|
<programlisting> |
|
struct drm_mode_create_dumb { |
|
__u32 height; |
|
__u32 width; |
|
__u32 bpp; |
|
__u32 flags; |
|
|
|
__u32 handle; |
|
__u32 pitch; |
|
__u64 size; |
|
}; |
|
</programlisting> |
|
|
|
The fields <structfield>height</structfield>, |
|
<structfield>width</structfield>, <structfield>bpp</structfield> and |
|
<structfield>flags</structfield> have to be provided by the caller. |
|
The other fields are filled by the kernel with the return values. |
|
<structfield>height</structfield> and |
|
<structfield>width</structfield> are the dimensions of the |
|
rectangular buffer that is created. <structfield>bpp</structfield> |
|
is the number of bits-per-pixel and must be a multiple of |
|
<literal>8</literal>. You most commonly want to pass |
|
<literal>32</literal> here. The <structfield>flags</structfield> |
|
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 <structfield>handle</structfield>, |
|
<structfield>pitch</structfield> and <structfield>size</structfield> |
|
fields are filled by the kernel. <structfield>handle</structfield> |
|
is a 32bit gem handle that identifies the buffer. This is used by |
|
several other calls that take a gem-handle or memory-buffer as |
|
argument. The <structfield>pitch</structfield> field is the |
|
pitch (or stride) of the new buffer. Most drivers use 32bit or 64bit |
|
aligned stride-values. The <structfield>size</structfield> field |
|
contains the absolute size in bytes of the buffer. This can normally |
|
also be computed with |
|
<emphasis>(height * pitch + width) * bpp / 4</emphasis>.</para> |
|
|
|
<para>To prepare the buffer for |
|
<citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
|
you need to use the <constant>DRM_IOCTL_MODE_MAP_DUMB</constant> |
|
ioctl. It takes as argument a structure of type |
|
<structname>struct drm_mode_map_dumb</structname>: |
|
|
|
<programlisting> |
|
struct drm_mode_map_dumb { |
|
__u32 handle; |
|
__u32 pad; |
|
|
|
__u64 offset; |
|
}; |
|
</programlisting> |
|
|
|
You need to put the gem-handle that was previously retrieved via |
|
<constant>DRM_IOCTL_MODE_CREATE_DUMB</constant> into the |
|
<structfield>handle</structfield> field. The |
|
<structfield>pad</structfield> field is unused padding and must be |
|
zeroed. After completion, the <structfield>offset</structfield> |
|
field will contain an offset that can be used with |
|
<citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
|
on the DRM file-descriptor.</para> |
|
|
|
<para>If you don't need your dumb-buffer, anymore, you have to destroy it |
|
with <constant>DRM_IOCTL_MODE_DESTROY_DUMB</constant>. If you close |
|
the DRM file-descriptor, all open dumb-buffers are automatically |
|
destroyed. This ioctl takes as argument a structure of type |
|
<structname>struct drm_mode_destroy_dumb</structname>: |
|
|
|
<programlisting> |
|
struct drm_mode_destroy_dumb { |
|
__u32 handle; |
|
}; |
|
</programlisting> |
|
|
|
You only need to put your handle into the |
|
<structfield>handle</structfield> field. After this call, the handle |
|
is invalid and may be reused for new buffers by the dumb-API.</para> |
|
|
|
</refsect2> |
|
|
|
<refsect2> |
|
<title>TTM</title> |
|
<para><emphasis>TTM</emphasis> stands for |
|
<emphasis>Translation Table Manager</emphasis> 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 manpages for more |
|
information on memory-management with radeon and TTM.</para> |
|
</refsect2> |
|
|
|
<refsect2> |
|
<title>GEM</title> |
|
<para><emphasis>GEM</emphasis> stands for |
|
<emphasis>Graphics Execution Manager</emphasis> 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.</para> |
|
|
|
<para>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.</para> |
|
|
|
<para>All GEM APIs are defined as |
|
<citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> |
|
on the DRM file descriptor. An application must be authorized via |
|
<citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
|
to the current DRM-Master to access the GEM subsystem. A driver that |
|
does not support gem will return <constant>ENODEV</constant> for all |
|
these ioctls. Invalid object handles return |
|
<constant>EINVAL</constant> and invalid object names return |
|
<constant>ENOENT</constant>.</para> |
|
|
|
<para>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.</para> |
|
|
|
<para>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 |
|
<citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
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.</para> |
|
|
|
<para>Gem-buffers cannot be created with a generic API. Each driver |
|
provides its own API to create gem-buffers. See for example |
|
<constant>DRM_I915_GEM_CREATE</constant>, |
|
<constant>DRM_NOUVEAU_GEM_NEW</constant> or |
|
<constant>DRM_RADEON_GEM_CREATE</constant>. Each of these ioctls |
|
returns a gem-handle that can be passed to different generic ioctls. |
|
The <emphasis>libgbm</emphasis> library from the |
|
<emphasis>mesa3D</emphasis> 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 |
|
<citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
or |
|
<citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para> |
|
|
|
<para>Gem-buffers can be closed with the |
|
<constant>DRM_IOCTL_GEM_CLOSE</constant> ioctl. It takes as argument |
|
a structure of type <structname>struct drm_gem_close</structname>: |
|
|
|
<programlisting> |
|
struct drm_gem_close { |
|
__u32 handle; |
|
__u32 pad; |
|
}; |
|
</programlisting> |
|
|
|
The <structfield>handle</structfield> field is the gem-handle to be |
|
closed. The <structfield>pad</structfield> field is unused padding. |
|
It must be zeroed. 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.</para> |
|
|
|
<para>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 32bit |
|
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 |
|
<citerefentry><refentrytitle>drmAuthMagic</refentrytitle><manvolnum>3</manvolnum></citerefentry> |
|
to the current DRM-Master, can <emphasis>guess</emphasis> the name |
|
and open or access the gem-object. If you want more fine-grained |
|
access control, you can use the new |
|
<citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
API to retrieve file-descriptors for gem-handles. To create a name |
|
for a gem-handle, you use the |
|
<constant>DRM_IOCTL_GEM_FLINK</constant> ioctl. It takes as argument |
|
a structure of type <structname>struct drm_gem_flink</structname>: |
|
|
|
<programlisting> |
|
struct drm_gem_flink { |
|
__u32 handle; |
|
__u32 name; |
|
}; |
|
</programlisting> |
|
|
|
You have to put your handle into the |
|
<structfield>handle</structfield> field. After completion, the |
|
kernel has put the new unique name into the |
|
<structfield>name</structfield> field. You can now pass this name to |
|
other processes which can then import the name with the |
|
<constant>DRM_IOCTL_GEM_OPEN</constant> ioctl. It takes as argument |
|
a structure of type <structname>struct drm_gem_open</structname>: |
|
|
|
<programlisting> |
|
struct drm_gem_open { |
|
__u32 name; |
|
|
|
__u32 handle; |
|
__u32 size; |
|
}; |
|
</programlisting> |
|
|
|
You have to fill in the <structfield>name</structfield> field with |
|
the name of the gem-object that you want to open. The kernel will |
|
fill in the <structfield>handle</structfield> and |
|
<structfield>size</structfield> 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.</para> |
|
|
|
<para>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 <emphasis>OpenGL</emphasis>. So if you want to |
|
use more GPU features, you should use the |
|
<emphasis>mesa3D</emphasis> library to create OpenGL contexts on DRM |
|
devices. This does <emphasis>not</emphasis> 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 manpages, 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 |
|
<citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
and |
|
<citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry>. |
|
However, the |
|
<citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
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't do any rendering on their own. See its |
|
man-page for more information.</para> |
|
</refsect2> |
|
</refsect1> |
|
|
|
<refsect1> |
|
<title>Examples</title> |
|
<para>This section includes examples for basic memory-management |
|
tasks.</para> |
|
|
|
<refsect2> |
|
<title>Dumb-Buffers</title> |
|
<para>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 |
|
<citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para> |
|
|
|
<programlisting> |
|
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); |
|
</programlisting> |
|
|
|
</refsect2> |
|
|
|
</refsect1> |
|
|
|
<refsect1> |
|
<title>Reporting Bugs</title> |
|
<para>Bugs in this manual should be reported to |
|
https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm |
|
under the "DRI" product, component "libdrm"</para> |
|
</refsect1> |
|
|
|
<refsect1> |
|
<title>See Also</title> |
|
<para> |
|
<citerefentry><refentrytitle>drm</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-kms</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-prime</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drmAvailable</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drmOpen</refentrytitle><manvolnum>3</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-intel</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-radeon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, |
|
<citerefentry><refentrytitle>drm-nouveau</refentrytitle><manvolnum>7</manvolnum></citerefentry> |
|
</para> |
|
</refsect1> |
|
</refentry>
|
|
|