egl: add initial EGL_MESA_image_dma_buf_export v2.4
authorDave Airlie <airlied@redhat.com>
Mon, 3 Mar 2014 03:57:16 +0000 (13:57 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 1 Apr 2015 04:10:04 +0000 (14:10 +1000)
At the moment to get an EGL image to a dma-buf file descriptor,
you have to use EGL_MESA_drm_image, and then use libdrm to
convert this to a file descriptor.

This extension just provides an API modelled on EGL_MESA_drm_image,
to return a dma-buf file descriptor.

v2: update spec for new API proposal
add internal queries to get the fourcc back from intel driver.

v2.1: add gallium pieces.

v2.2: add offsets to spec and API, rename fd->fds, stride->strides
in API. rewrite spec a bit more, add some q/a

v2.3:
add modifiers to query interface and 64-bit type for that (Daniel Stone)
specifiy what happens to num fds vs num planes differences. (Chad Versace)

v2.4:
fix grammar (Daniel Stone)

Signed-off-by: Dave Airlie <airlied@redhat.com>
docs/specs/MESA_image_dma_buf_export.txt [new file with mode: 0644]
include/EGL/eglmesaext.h
include/GL/internal/dri_interface.h
src/egl/drivers/dri2/egl_dri2.c
src/egl/main/eglapi.c
src/egl/main/eglapi.h
src/egl/main/egldisplay.h
src/egl/main/eglfallbacks.c
src/gallium/state_trackers/dri/dri2.c
src/mesa/drivers/dri/i965/intel_screen.c

diff --git a/docs/specs/MESA_image_dma_buf_export.txt b/docs/specs/MESA_image_dma_buf_export.txt
new file mode 100644 (file)
index 0000000..c3794ee
--- /dev/null
@@ -0,0 +1,142 @@
+Name
+
+    MESA_image_dma_buf_export
+
+Name Strings
+
+    EGL_MESA_image_dma_buf_export
+
+Contributors
+
+    Dave Airlie
+
+Contact
+
+    Dave Airlie (airlied 'at' redhat 'dot' com)
+
+Status
+
+    Proposal
+
+Version
+
+    Version 2, Mar 30, 2015
+
+Number
+
+    EGL Extension #not assigned
+
+Dependencies
+
+    Reguires EGL 1.4 or later.  This extension is written against the
+    wording of the EGL 1.4 specification.
+
+    EGL_KHR_base_image is required.
+
+    The EGL implementation must be running on a Linux kernel supporting the
+    dma_buf buffer sharing mechanism.
+
+Overview
+
+    This extension provides entry points for integrating EGLImage with the
+    dma-buf infrastructure.  The extension allows creating a Linux dma_buf
+    file descriptor or multiple file descriptors, in the case of multi-plane
+    YUV image, from an EGLImage.
+
+    It is designed to provide the complementary functionality to EGL_EXT_image_dma_buf_import.
+
+IP Status
+
+    Open-source; freely implementable.
+
+New Types
+
+    This is a 64 bit unsigned integer.
+
+    typedef khronos_uint64_t EGLuint64MESA;
+
+
+New Procedures and Functions
+
+    EGLBoolean eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
+                                  EGLImageKHR image,
+                                 int *fourcc,
+                                 int *num_planes,
+                                 EGLuint64MESA *modifiers);
+
+    EGLBoolean eglExportDMABUFImageMESA(EGLDisplay dpy,
+                                        EGLImageKHR image,
+                                        int *fds,
+                                       EGLint *strides,
+                                       EGLint *offsets);
+
+New Tokens
+
+    None
+
+
+Additions to the EGL 1.4 Specification:
+
+    To mirror the import extension, this extension attempts to return
+    enough information to enable an exported dma-buf to be imported
+    via eglCreateImageKHR and EGL_LINUX_DMA_BUF_EXT token.
+
+    Retrieving the information is a two step process, so two APIs
+    are required.
+
+    The first entrypoint
+       EGLBoolean eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
+                                  EGLImageKHR image,
+                                 int *fourcc,
+                                 int *num_planes,
+                                 EGLuint64MESA *modifiers);
+
+    is used to retrieve the pixel format of the buffer, as specified by
+    drm_fourcc.h, the number of planes in the image and the Linux
+    drm modifiers. <fourcc>, <num_planes> and <modifiers> may be NULL,
+    in which case no value is retrieved.
+
+    The second entrypoint retrieves the dma_buf file descriptors,
+    strides and offsets for the image. The caller should pass
+    arrays sized according to the num_planes values retrieved previously.
+    Passing arrays of the wrong size will have undefined results.
+    If the number of fds is less than the number of planes, then
+    subsequent fd slots should contain -1.
+
+        EGLBoolean eglExportDMABUFImageMESA(EGLDisplay dpy,
+                                         EGLImageKHR image,
+                                        int *fds,
+                                         EGLint *strides,
+                                         EGLint *offsets);
+
+    <fds>, <strides>, <offsets> can be NULL if the infomatation isn't
+    required by the caller.
+
+Issues
+
+1. Should the API look more like an attribute getting API?
+
+ANSWER: No, from a user interface pov, having to iterate across calling
+the API up to 12 times using attribs seems like the wrong solution.
+
+2. Should the API take a plane and just get the fd/stride/offset for that
+   plane?
+
+ANSWER: UNKNOWN,this might be just as valid an API.
+
+3. Does ownership of the file descriptor remain with the app?
+
+ANSWER: Yes, the app is responsible for closing any fds retrieved.
+
+4. If number of planes and number of fds differ what should we do?
+
+ANSWER: Return -1 for the secondary slots, as this avoids having
+to dup the fd extra times to make the interface sane.
+
+Revision History
+
+    Version 2, March, 2015
+        Add a query interface (Dave Airlie)
+    Version 1, June 3, 2014
+        Initial draft (Dave Airlie)
+
index 5fcc527d65e919e92fa5a0728fcf5e6654a0688b..595babd54efd9b77140cd73fbf5bdbcda53aed19 100644 (file)
@@ -170,6 +170,14 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOK) (EGLDisplay dpy, EG
 #define EGL_NO_CONFIG_MESA                     ((EGLConfig)0)
 #endif
 
+#if KHRONOS_SUPPORT_INT64
+#ifndef EGL_MESA_image_dma_buf_export
+#define EGL_MESA_image_dma_buf_export 1
+typedef khronos_uint64_t EGLuint64MESA;
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *fourcc, EGLint *nplanes, EGLuint64MESA *modifiers);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#endif
+#endif
 #ifdef __cplusplus
 }
 #endif
index 1d670b1e0834727a9b4f4a4f8d4ad5338f737fe8..eb7da23f7ba0c58d95977c8c7cd0c0ce45044202 100644 (file)
@@ -1006,7 +1006,7 @@ struct __DRIdri2ExtensionRec {
  * extensions.
  */
 #define __DRI_IMAGE "DRI_IMAGE"
-#define __DRI_IMAGE_VERSION 10
+#define __DRI_IMAGE_VERSION 11
 
 /**
  * These formats correspond to the similarly named MESA_FORMAT_*
@@ -1097,6 +1097,8 @@ struct __DRIdri2ExtensionRec {
 #define __DRI_IMAGE_ATTRIB_FD           0x2007 /* available in versions
                                                 * 7+. Each query will return a
                                                 * new fd. */
+#define __DRI_IMAGE_ATTRIB_FOURCC       0x2008 /* available in versions 11 */
+#define __DRI_IMAGE_ATTRIB_NUM_PLANES   0x2009 /* available in versions 11 */
 
 enum __DRIYUVColorSpace {
    __DRI_YUV_COLOR_SPACE_UNDEFINED = 0,
index d5031961ce08a8239eaaf77855306678f3685f51..a428f284ae7d9f20139b8308c43815ab94d49cf1 100644 (file)
@@ -525,8 +525,14 @@ dri2_setup_screen(_EGLDisplay *disp)
 
          capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen);
          disp->Extensions.MESA_drm_image = (capabilities & __DRI_IMAGE_CAP_GLOBAL_NAMES) != 0;
-      } else
+
+         if (dri2_dpy->image->base.version >= 11)
+            disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
+      } else {
          disp->Extensions.MESA_drm_image = EGL_TRUE;
+         if (dri2_dpy->image->base.version >= 11)
+            disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
+      }
 
       disp->Extensions.KHR_image_base = EGL_TRUE;
       disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
@@ -1965,6 +1971,55 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
 
    return EGL_TRUE;
 }
+
+static EGLBoolean
+dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp,
+                                     _EGLImage *img,
+                                     EGLint *fourcc, EGLint *nplanes,
+                                     EGLuint64MESA *modifiers)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
+
+   (void) drv;
+
+
+   if (nplanes)
+      dri2_dpy->image->queryImage(dri2_img->dri_image,
+                                 __DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes);
+   if (fourcc)
+      dri2_dpy->image->queryImage(dri2_img->dri_image,
+                                 __DRI_IMAGE_ATTRIB_FOURCC, fourcc);
+
+   if (modifiers)
+      *modifiers = 0;
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
+                               int *fds, EGLint *strides, EGLint *offsets)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
+
+   (void) drv;
+
+   /* rework later to provide multiple fds/strides/offsets */
+   if (fds)
+      dri2_dpy->image->queryImage(dri2_img->dri_image,
+                                 __DRI_IMAGE_ATTRIB_FD, fds);
+
+   if (strides)
+      dri2_dpy->image->queryImage(dri2_img->dri_image,
+                                 __DRI_IMAGE_ATTRIB_STRIDE, strides);
+
+   if (offsets)
+      offsets[0] = 0;
+
+   return EGL_TRUE;
+}
 #endif
 
 #ifdef HAVE_WAYLAND_PLATFORM
@@ -2219,6 +2274,8 @@ _eglBuiltInDriverDRI2(const char *args)
 #ifdef HAVE_LIBDRM
    dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
    dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
+   dri2_drv->base.API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa;
+   dri2_drv->base.API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa;
 #endif
 #ifdef HAVE_WAYLAND_PLATFORM
    dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
index 6031a7ad8dca9f1a5785a4eeb1c929f766d28ab4..ea2ee734a213ab521632e35900e836023f34ae51 100644 (file)
@@ -423,6 +423,8 @@ _eglCreateExtensionsString(_EGLDisplay *dpy)
    _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import);
 
    _EGL_CHECK_EXTENSION(NV_post_sub_buffer);
+
+   _EGL_CHECK_EXTENSION(MESA_image_dma_buf_export);
 #undef _EGL_CHECK_EXTENSION
 }
 
@@ -1239,6 +1241,10 @@ eglGetProcAddress(const char *procname)
       { "eglCreatePlatformWindowSurfaceEXT", (_EGLProc) eglCreatePlatformWindowSurfaceEXT },
       { "eglCreatePlatformPixmapSurfaceEXT", (_EGLProc) eglCreatePlatformPixmapSurfaceEXT },
       { "eglGetSyncValuesCHROMIUM", (_EGLProc) eglGetSyncValuesCHROMIUM },
+#ifdef EGL_MESA_drm_buf_image_export
+      { "eglExportDMABUFImageQueryMESA", (_EGLProc) eglExportDMABUFImageQueryMESA },
+      { "eglExportDMABUFImageMESA", (_EGLProc) eglExportDMABUFImageMESA },
+#endif
       { NULL, NULL }
    };
    EGLint i;
@@ -1926,3 +1932,47 @@ eglGetSyncValuesCHROMIUM(EGLDisplay display, EGLSurface surface,
 
    RETURN_EGL_EVAL(disp, ret);
 }
+
+#ifdef EGL_MESA_image_dma_buf_export
+EGLBoolean EGLAPIENTRY
+eglExportDMABUFImageQueryMESA(EGLDisplay dpy, EGLImageKHR image,
+                              EGLint *fourcc, EGLint *nplanes,
+                              EGLuint64MESA *modifiers)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLImage *img = _eglLookupImage(image, disp);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
+   assert(disp->Extensions.MESA_image_dma_buf_export);
+
+   if (!img)
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
+
+   ret = drv->API.ExportDMABUFImageQueryMESA(drv, disp, img, fourcc, nplanes,
+                                             modifiers);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+
+EGLBoolean EGLAPIENTRY
+eglExportDMABUFImageMESA(EGLDisplay dpy, EGLImageKHR image,
+                         int *fds, EGLint *strides, EGLint *offsets)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLImage *img = _eglLookupImage(image, disp);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
+   assert(disp->Extensions.MESA_image_dma_buf_export);
+
+   if (!img)
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
+
+   ret = drv->API.ExportDMABUFImageMESA(drv, disp, img, fds, strides, offsets);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+#endif
index 0626719ae70a058999e1f2104dc7b05a99bdd000..eb5f58e6fa98b2e999b380d7d6a97fcd7608c579 100644 (file)
@@ -140,6 +140,11 @@ typedef EGLBoolean (*SwapBuffersWithDamageEXT_t) (_EGLDriver *drv, _EGLDisplay *
 
 typedef EGLBoolean (*GetSyncValuesCHROMIUM_t) (_EGLDisplay *dpy, _EGLSurface *surface, EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc);
 
+#ifdef EGL_MESA_image_dma_buf_export
+typedef EGLBoolean (*ExportDMABUFImageQueryMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *fourcc, EGLint *stride, EGLuint64MESA *modifiers);
+typedef EGLBoolean (*ExportDMABUFImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *fds, EGLint *strides, EGLint *offsets);
+#endif
+
 /**
  * The API dispatcher jumps through these functions
  */
@@ -226,6 +231,11 @@ struct _egl_api
 
    QueryBufferAge_t QueryBufferAge;
    GetSyncValuesCHROMIUM_t GetSyncValuesCHROMIUM;
+
+#ifdef EGL_MESA_image_dma_buf_export
+   ExportDMABUFImageQueryMESA_t ExportDMABUFImageQueryMESA;
+   ExportDMABUFImageMESA_t ExportDMABUFImageMESA;
+#endif
 };
 
 #endif /* EGLAPI_INCLUDED */
index d7f5dbacde6789beac8feff6cbcdffafca1da902..4a1fb4ab15c16bd133aa7f7d2ee61827df80f9b2 100644 (file)
@@ -123,6 +123,8 @@ struct _egl_extensions
    EGLBoolean EXT_buffer_age;
    EGLBoolean EXT_swap_buffers_with_damage;
    EGLBoolean EXT_image_dma_buf_import;
+
+   EGLBoolean MESA_image_dma_buf_export;
 };
 
 
index be5964306848d1b5768b12ae7dda57d38be93f35..c108ca7687ce58a99d457eb226ef4e112dc80e04 100644 (file)
@@ -118,4 +118,9 @@ _eglInitDriverFallbacks(_EGLDriver *drv)
 #ifdef EGL_NOK_swap_region
    drv->API.SwapBuffersRegionNOK = NULL;
 #endif
+
+#ifdef EGL_MESA_dma_buf_image_export
+   drv->API.ExportDMABUFImageQueryMESA = NULL;
+   drv->API.ExportDMABUFImageMESA = NULL;
+#endif
 }
index 7d65ba30f293aea9c62009f5a8d2e47a8cc54db5..f8f4ecf36d77e4764aefe8d00f2db634652e8489 100644 (file)
@@ -76,6 +76,30 @@ static int convert_fourcc(int format, int *dri_components_p)
    return format;
 }
 
+static int convert_to_fourcc(int format)
+{
+   switch(format) {
+   case __DRI_IMAGE_FORMAT_RGB565:
+      format = __DRI_IMAGE_FOURCC_RGB565;
+      break;
+   case __DRI_IMAGE_FORMAT_ARGB8888:
+      format = __DRI_IMAGE_FOURCC_ARGB8888;
+      break;
+   case __DRI_IMAGE_FORMAT_XRGB8888:
+      format = __DRI_IMAGE_FOURCC_XRGB8888;
+      break;
+   case __DRI_IMAGE_FORMAT_ABGR8888:
+      format = __DRI_IMAGE_FOURCC_ABGR8888;
+      break;
+   case __DRI_IMAGE_FORMAT_XBGR8888:
+      format = __DRI_IMAGE_FOURCC_XBGR8888;
+      break;
+   default:
+      return -1;
+   }
+   return format;
+}
+
 /**
  * DRI2 flush extension.
  */
@@ -909,6 +933,12 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
          return GL_FALSE;
       *value = image->dri_components;
       return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_FOURCC:
+      *value = convert_to_fourcc(image->dri_format);
+      return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
+      *value = 1;
+      return GL_TRUE;
    default:
       return GL_FALSE;
    }
@@ -1203,7 +1233,7 @@ dri2_get_capabilities(__DRIscreen *_screen)
 
 /* The extension is modified during runtime if DRI_PRIME is detected */
 static __DRIimageExtension dri2ImageExtension = {
-    .base = { __DRI_IMAGE, 10 },
+    .base = { __DRI_IMAGE, 11 },
 
     .createImageFromName          = dri2_create_image_from_name,
     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
index 3640b675471eabfe4fb17338703c00225746b3bd..cb9710fc6e664beebc5220230d972f880a78b42d 100644 (file)
@@ -300,6 +300,17 @@ intel_image_format_lookup(int fourcc)
    return f;
 }
 
+static boolean intel_lookup_fourcc(int dri_format, int *fourcc)
+{
+   for (unsigned i = 0; i < ARRAY_SIZE(intel_image_formats); i++) {
+      if (intel_image_formats[i].planes[0].dri_format == dri_format) {
+         *fourcc = intel_image_formats[i].fourcc;
+         return true;
+      }
+   }
+   return false;
+}
+
 static __DRIimage *
 intel_allocate_image(int dri_format, void *loaderPrivate)
 {
@@ -559,6 +570,14 @@ intel_query_image(__DRIimage *image, int attrib, int *value)
       if (drm_intel_bo_gem_export_to_prime(image->bo, value) == 0)
          return true;
       return false;
+   case __DRI_IMAGE_ATTRIB_FOURCC:
+      if (intel_lookup_fourcc(image->dri_format, value))
+         return true;
+      return false;
+   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
+      *value = 1;
+      return true;
+
   default:
       return false;
    }
@@ -784,7 +803,7 @@ intel_from_planar(__DRIimage *parent, int plane, void *loaderPrivate)
 }
 
 static const __DRIimageExtension intelImageExtension = {
-    .base = { __DRI_IMAGE, 8 },
+    .base = { __DRI_IMAGE, 11 },
 
     .createImageFromName                = intel_create_image_from_name,
     .createImageFromRenderbuffer        = intel_create_image_from_renderbuffer,
@@ -797,7 +816,9 @@ static const __DRIimageExtension intelImageExtension = {
     .fromPlanar                         = intel_from_planar,
     .createImageFromTexture             = intel_create_image_from_texture,
     .createImageFromFds                 = intel_create_image_from_fds,
-    .createImageFromDmaBufs             = intel_create_image_from_dma_bufs
+    .createImageFromDmaBufs             = intel_create_image_from_dma_bufs,
+    .blitImage                          = NULL,
+    .getCapabilities                    = NULL
 };
 
 static int