Mali 400 Headless rendering


Headless rendering includes use cases when GPU is utilized without window display system attached. Rendering is ongoing into offscreen buffers and result is accessible by other components in the system, rather by display output. To achieve such access offscreen buffers are backed by the Linux dmabuf. This allows to exercise features:

  • Compatible buffer data format layout between different components in the system: GPU, CPU, Video, Encoder, etc.

  • Zero-copy access bypassing expensive memory copying to/from internal GPU memory.

  • Sharing data between processes in the system.

  • Control lifetime of the buffer through the Kernel file descriptor duplication.

GPU use cases

There are two typical dmabuf use cases for the GPU:

  • Accept dmabuf memory as sampler image data, to be used as an input in fragment shaders.

  • Use dmabuf memory as an offscreen framebuffer attachment image data, to be used as rendering output.

Both use cases use next EGL and GL extensions to wrap dmabuf into EGLImage:

  • EGL_EXT_image_dma_buf_import

Additionally sampler use case requires next GL extension:

  • GL_OES_EGL_image_external

Memory formats

Supported dmabuf memory formats are different depending on which of the above use case is targeted.

  • Sampler use case (dmabuf input):

    • RGB formats, e.g. DRM_FORMAT_RGBA8888

    • YUV formats, e.g. DRM_FORMAT_YUYV

  • Framebuffer use case (dmabuf output):

    • DRM_FORMAT_RGBA8888 corresponding the the GL_RGBA

Software Stack

Usage sequence

Common steps between the use cases may include at least dmabuf allocation and wrapping it into the EGLImage handle to be used in EGL and GL API.

Allocating dmabuf

Allocation of dmabuf goes through the DRM Kernel module, exposed via /dev/dri/* nodes and handled by the libdrm library in userspace:

In the example below we are allocating DUMB buffers, mapping its memory into the application address space, and retrieve file descriptors to be shared with other processes.

drm_mode_create_dumb creq; std::memset(&creq, 0, sizeof(creq)); creq.width = 800; creq.height = 600; creq.bpp = 32; drmIoctl(devFd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); drm_prime_handle prime; std::memset(&prime, 0, sizeof(prime)); prime.handle = creq.handle; drmIoctl(devFd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); drm_mode_map_dumb mreq; std::memset(&mreq, 0, sizeof(mreq)); mreq.handle = creq.handle; drmIoctl(devFd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); void * data = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, devFd, mreq.offset);

Creating EGLImage

DUMB buffer allows to manually bind raw memory into the appropriate DRM_FORMAT. Different formats might require additional attributes to be specified, e.g. multiple planes, offset, color space, color range.

EGLint attributes[] = { EGL_WIDTH, 800, EGL_HEIGHT, 600, EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_RGBA8888, EGL_DMA_BUF_PLANE0_FD_EXT, prime.fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 800 * 4, EGL_NONE, }; EGLImageKHR eglImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attributes);

Sampler use case (dmabuf input)

Sampler use case includes creating OES texture to be used as an input in the fragment shader.

Creating OES texture

OES texture should be bound to the GL_TEXTURE_EXTERNAL_OES target.

GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);

Using texture as uniform sampler in GLSL

Sequence diagram

Framebuffer use case (dmabuf output)

Texture is bound to the GL_TEXTURE_2D target, which is attached to the framebuffer as GL_COLOR_ATTACHMENT0.

Sequence diagram



© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy