EGL texture 0-copy

Revision as of 19:22, 5 January 2021 by Registered User





This article explain how to use the EGL texture 0-copy in a 3D application.

1. What is texture 0-copy?[edit source]

The texture 0-copy consists in using specific OpenGLES interfaces to avoid to copy the texture from the EGL application environment to the GPU execution environment.
The OpenGLES interfaces to be used (instead of the standard glTexImage2D interface) are:

  • eglCreateImageKHR (create a reference on the image texture)
  • eglDestroyImageKHR (destroy the reference of the image texture)
  • glEGLImageTargetTexture2DOES (upload the texture)


The texture 0-copy procedure assumes that the texture buffer could be shared (e.g.: using DMABUF) and that the application will lock the texture until the OpenGLES draw procedure is completed.

The texture 0-copy is very useful when the texture to apply on a 3D object is refreshed with a high rate (e.g: video texture).

2. Example of implementation[edit source]

In this example we consider that the GPU natively support NV12 pixel format.

      EGLint eglImgAttrs[30];
      EGLImageKHR image;
      GLenum target;

      if (meta) {
        switch (meta->format) {
        case GST_VIDEO_FORMAT_NV12:
          format = DRM_FORMAT_NV12;
          n_planes = 2;
          target = GL_TEXTURE_EXTERNAL_OES;
          break;
        case GST_VIDEO_FORMAT_RGB16:
          format = DRM_FORMAT_RGB565;
        case GST_VIDEO_FORMAT_BGRx:
          format = DRM_FORMAT_XRGB8888;
          n_planes = 1;
          target = GL_TEXTURE_2D;
          break;
        default:
          fprintf(stdout, "%s: buffer format (0x%x) not supported for texture\n", __func__, meta->format);
          return;
        }
      } else {
        fprintf(stdout, "%s: no meta data found\n", __func__);
        return;
      }

      eglImgAttrs[atti++] = EGL_WIDTH;
      eglImgAttrs[atti++] = meta->width;
      eglImgAttrs[atti++] = EGL_HEIGHT;
      eglImgAttrs[atti++] = meta->height;
      eglImgAttrs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
      eglImgAttrs[atti++] = format;

      if (n_planes > 0) {
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
        eglImgAttrs[atti++] = fd_mem;
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
        eglImgAttrs[atti++] = meta->offset[0];
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
        eglImgAttrs[atti++] = meta->stride[0];
      }

      if (n_planes > 1) {
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
        eglImgAttrs[atti++] = fd_mem;
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
        eglImgAttrs[atti++] = meta->offset[1];
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
        eglImgAttrs[atti++] = meta->stride[1];
      }

      if (n_planes > 2) {
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
        eglImgAttrs[atti++] = fd_mem;
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
        eglImgAttrs[atti++] = meta->offset[2];
        eglImgAttrs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
        eglImgAttrs[atti++] = meta->stride[2];
      }

      eglImgAttrs[atti++] = EGL_NONE;

      image = eglCreateImageKHR(display,
                EGL_NO_CONTEXT,
                EGL_LINUX_DMA_BUF_EXT,
                NULL,
                eglImgAttrs);

      /* Updating the related input texture. */
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(target, input_textures_handle[stream_index]);
      glEGLImageTargetTexture2DOES(target, image);
 
      eglDestroyImageKHR(display, image);