sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
313
lib/libdrm/man/drm-memory.7.rst
Normal file
313
lib/libdrm/man/drm-memory.7.rst
Normal file
|
@ -0,0 +1,313 @@
|
|||
==========
|
||||
drm-memory
|
||||
==========
|
||||
|
||||
---------------------
|
||||
DRM Memory Management
|
||||
---------------------
|
||||
|
||||
:Date: September 2012
|
||||
:Manual section: 7
|
||||
:Manual group: Direct Rendering Manager
|
||||
|
||||
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 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.
|
||||
|
||||
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.
|
||||
|
||||
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 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 **drmModeAddFB**\ (3) and
|
||||
use it for mode-setting and scanout. To access the buffer, 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 values.
|
||||
*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 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. *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
|
||||
unused 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-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.
|
||||
|
||||
GEM
|
||||
---
|
||||
|
||||
*GEM* stands for *Graphics Execution Manager* 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.
|
||||
|
||||
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.
|
||||
|
||||
All GEM APIs are defined as **ioctl**\ (2) on the DRM file descriptor. An
|
||||
application 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 return
|
||||
``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 directly, 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) 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.
|
||||
|
||||
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
|
||||
returns 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
|
||||
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.
|
||||
|
||||
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
|
||||
**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 creation, 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
|
||||
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 **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 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.
|
||||
|
||||
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-intel**\ (7), **drm-radeon**\ (7), **drm-nouveau**\ (7)
|
Loading…
Add table
Add a link
Reference in a new issue