Provided by: libdrm-dev_2.4.122-1~ubuntu0.24.04.1_amd64 bug

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 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)

                                                 September 2012                                    DRM-MEMORY(7)