Skip to content

Linux Graphics Architecture

Overview

Unlike most device drivers in Linux, graphics device drivers are
divided into two parts. One part is implemented in the kernel
space
as usual, and the other part is implemented in the user
space
. This is due to graphics processing units (GPUs) being
special kind of hardware. Indeed, GPUs are perhaps the most complex
peripherals you can add in to your computer. Modern GPUs are essentially
computers within your computer with general-purpose massively parallel
processors that can execute instructions, fixed-function hardware blocks
related to rendering (e.g. rasterizer and ray tracer units) and video
processing (e.g. codecs for AVC and HEVC). Naturally GPUs also host
sizeable amounts of memory in the form of SDRAM blocks. User space
programs control GPUs using various APIs such as OpenGL and
Vulkan for real-time graphics, OpenCL and
CUDA for general purpose computing, and VAAPI for
video acceleration.

Linux graphics architecture resembles an inverted pyramid.

In short, the user space driver transforms API calls (e.g.
glDrawArrays) into system calls (i.e. ioctls),
the kernel space driver in turn executes these system calls and
communicates with the GPU.

Kernel Space

The main structure of interest in any DRM driver is the following
defined in include/drm/drm_drv.h:

struct drm_driver {
    int (*load) (struct drm_device *, unsigned long flags);
    int (*open) (struct drm_device *, struct drm_file *);
    void (*postclose) (struct drm_device *, struct drm_file *);
    void (*lastclose) (struct drm_device *);
    void (*unload) (struct drm_device *);
    void (*release) (struct drm_device *);
    void (*master_set)(struct drm_device *dev, struct drm_file *file_priv,
               bool from_open);
    void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
    void (*debugfs_init)(struct drm_minor *minor);
    struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
                            size_t size);
    int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
                uint32_t handle, uint32_t flags, int *prime_fd);
    int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
                int prime_fd, uint32_t *handle);
    struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
                struct dma_buf *dma_buf);
    struct drm_gem_object *(*gem_prime_import_sg_table)(
                struct drm_device *dev,
                struct dma_buf_attachment *attach,
                struct sg_table *sgt);
    int (*gem_prime_mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
    int (*dumb_create)(struct drm_file *file_priv,
               struct drm_device *dev,
               struct drm_mode_create_dumb *args);
    int (*dumb_map_offset)(struct drm_file *file_priv,
                   struct drm_device *dev, uint32_t handle,
                   uint64_t *offset);
    int (*dumb_destroy)(struct drm_file *file_priv,
                struct drm_device *dev,
                uint32_t handle);
    int major;
    int minor;
    int patchlevel;
    char *name;
    char *desc;
    char *date;
    u32 driver_features;
    const struct drm_ioctl_desc *ioctls;
    int num_ioctls;
    const struct file_operations *fops;
};

(Doğru mu?) ıf a computer system uses DRM to manage its monitor, then any user program (kernel driver??) that wants to put anything on the screen will either call the functions/IOCTL’s described in this structure or some other driver-specific ones. There is no other way.

Wayland/Weston use only the function calls/IOCTL’s described in drm_driver. 3D derivers like mesa may also use driver-specific function calls, in addition to these.

User Space