[PATCH mesa v3] wayland: Add an extension to create wl_buffers from EGLImages

Neil Roberts neil at linux.intel.com
Mon Oct 28 16:07:03 CET 2013


Here is an updated version of the patch to address Axel Davy's
concerns and change the wording of the extension to make it clear that
the function can return EGL_BAD_MATCH for any reason which prevents
the buffer from being represented as a wl_buffer and not just due to
differences in the format. This should make it clear that it is
acceptable for the function to fail if the compositor is running on a
different graphics card from the compositor and the buffer is using an
unsupported tiling format.

I haven't made any changes to the implementation because as far as I
understand the Wayland backend currently always uses the same device
as the compositor which is the one that is passed down in the device
event in the wl_drm interface so it can't have problems with tiling
layouts yets.

There is still some ongoing discussion about whether to add
wl_display_get_main_queue(). Kristian had two alternative proposals.
The first was to make Mesa internally bind a second wl_drm object
which wouldn't have a queue set on it and use that to create the
wl_buffers. I couldn't get that to work because that would also need a
second wl_registry with the default queue but we wouldn't be able to
read the events from that without messing up the application. The
second proposal was to make wl_proxy_set_queue take a NULL argument
which would reset the queue back to the default. I'm not really a big
fan of that because it's not very obvious and I don't see a good
reason to hide the main queue.

Regards,
- Neil

------- >8 --------------- (use git am --scissors to automatically chop here)

This adds an extension called EGL_WL_create_wayland_buffer_from_image
which adds the following single function:

struct wl_buffer *
eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);

The function creates a wl_buffer which shares its contents with the given
EGLImage. The expected use case for this is in a nested Wayland compositor
which is using subsurfaces to present buffers from its clients. Using this
extension it can attach the client buffers directly to the subsurface without
having to blit the contents into an intermediate buffer. The compositing can
then be done in the parent compositor.

The extension is only implemented in the Wayland EGL platform because of
course it wouldn't make sense anywhere else.
---
 .../specs/WL_create_wayland_buffer_from_image.spec | 101 +++++++++++++++++++++
 include/EGL/eglmesaext.h                           |  10 ++
 src/egl/drivers/dri2/platform_wayland.c            |  79 ++++++++++++++++
 src/egl/main/eglapi.c                              |  25 +++++
 src/egl/main/eglapi.h                              |   8 ++
 src/egl/main/egldisplay.h                          |   1 +
 src/egl/main/eglmisc.c                             |   1 +
 7 files changed, 225 insertions(+)
 create mode 100644 docs/specs/WL_create_wayland_buffer_from_image.spec

diff --git a/docs/specs/WL_create_wayland_buffer_from_image.spec b/docs/specs/WL_create_wayland_buffer_from_image.spec
new file mode 100644
index 0000000..aa5eb4d
--- /dev/null
+++ b/docs/specs/WL_create_wayland_buffer_from_image.spec
@@ -0,0 +1,101 @@
+Name
+
+    WL_create_wayland_buffer_from_image
+
+Name Strings
+
+    EGL_WL_create_wayland_buffer_from_image
+
+Contributors
+
+    Neil Roberts
+    Axel Davy
+    Daniel Stone
+
+Contact
+
+    Neil Roberts <neil.s.roberts at intel.com>
+
+Status
+
+    Proposal
+
+Version
+
+    Version 2, October 25, 2013
+
+Number
+
+    EGL Extension #not assigned
+
+Dependencies
+
+    Requires EGL 1.4 or later.  This extension is written against the
+    wording of the EGL 1.4 specification.
+
+    EGL_KHR_base_image is required.
+
+Overview
+
+    This extension provides an entry point to create a wl_buffer which shares
+    its contents with a given EGLImage. The expected use case for this is in a
+    nested Wayland compositor which is using subsurfaces to present buffers
+    from its clients. Using this extension it can attach the client buffers
+    directly to the subsurface without having to blit the contents into an
+    intermediate buffer. The compositing can then be done in the parent
+    compositor.
+
+    The nested compositor can create an EGLImage from a client buffer resource
+    using the existing WL_bind_wayland_display extension. It should also be
+    possible to create buffers using other types of images although there is
+    no expected use case for that.
+
+IP Status
+
+    Open-source; freely implementable.
+
+New Procedures and Functions
+
+    struct wl_buffer *eglCreateWaylandBufferFromImageWL(EGLDisplay dpy,
+                                                        EGLImageKHR image);
+
+New Tokens
+
+    None.
+
+Additions to the EGL 1.4 Specification:
+
+    To create a client-side wl_buffer from an EGLImage call
+
+      struct wl_buffer *eglCreateWaylandBufferFromImageWL(EGLDisplay dpy,
+                                                          EGLImageKHR image);
+
+    The returned buffer will share the contents with the given EGLImage. Any
+    updates to the image will also be updated in the wl_buffer. Typically the
+    EGLImage will be generated in a nested Wayland compositor using a buffer
+    resource from a client via the EGL_WL_bind_wayland_display extension.
+
+    If there was an error then the function will return NULL. In particular it
+    will generate EGL_BAD_MATCH if the implementation is not able to represent
+    the image as a wl_buffer. The possible reasons for this error are
+    implementation-dependant but may include problems such as an unsupported
+    format or tiling mode or that the buffer is in memory that is inaccessible
+    to the GPU that the given EGLDisplay is using.
+
+Issues
+
+    1) Under what circumstances can the EGL_BAD_MATCH error be generated? Does
+       this include for example unsupported tiling modes?
+
+       RESOLVED: Yes, the EGL_BAD_MATCH error can be generated for any reason
+       which prevents the implementation from representing the image as a
+       wl_buffer. For example, these problems can be but are not limited to
+       unsupported tiling modes, inaccessible memory or an unsupported pixel
+       format.
+
+Revision History
+
+    Version 1, September 6, 2013
+        Initial draft (Neil Roberts)
+    Version 2, October 25, 2013
+        Added a note about more possible reasons for returning EGL_BAD_FORMAT.
diff --git a/include/EGL/eglmesaext.h b/include/EGL/eglmesaext.h
index 1f07d4c..14fb07a 100644
--- a/include/EGL/eglmesaext.h
+++ b/include/EGL/eglmesaext.h
@@ -134,6 +134,16 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, st
 
 #endif
 
+#ifndef EGL_WL_create_wayland_buffer_from_image
+#define EGL_WL_create_wayland_buffer_from_image 1
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
+#endif
+typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
+
+#endif
+
 #ifndef EGL_NOK_swap_region
 #define EGL_NOK_swap_region 1
 
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index c0de16b..bb8d113 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -589,6 +589,82 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    return dri2_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
 }
 
+static struct wl_buffer *
+dri2_create_wayland_buffer_from_image_wl(_EGLDriver *drv,
+                                         _EGLDisplay *disp,
+                                         _EGLImage *img)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
+   __DRIimage *image = dri2_img->dri_image;
+   struct wl_buffer *buffer;
+   int width, height, format, pitch;
+   enum wl_drm_format wl_format;
+
+   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
+
+   switch (format) {
+   case __DRI_IMAGE_FORMAT_ARGB8888:
+      if (!(dri2_dpy->formats & HAS_ARGB8888))
+         goto bad_format;
+      wl_format = WL_DRM_FORMAT_ARGB8888;
+      break;
+   case __DRI_IMAGE_FORMAT_XRGB8888:
+      if (!(dri2_dpy->formats & HAS_XRGB8888))
+         goto bad_format;
+      wl_format = WL_DRM_FORMAT_XRGB8888;
+      break;
+   default:
+      goto bad_format;
+   }
+
+   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
+   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
+   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
+
+   if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
+      int fd;
+
+      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
+
+      buffer =
+         wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
+                                    fd,
+                                    width, height,
+                                    wl_format,
+                                    0, pitch,
+                                    0, 0,
+                                    0, 0);
+
+      close(fd);
+   } else {
+      int name;
+
+      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
+
+      buffer =
+         wl_drm_create_buffer(dri2_dpy->wl_drm,
+                              name,
+                              width, height,
+                              pitch,
+                              wl_format);
+   }
+
+   /* The buffer object will have been created with our internal event queue
+    * because it is using the wl_drm object as a proxy factory. We want the
+    * buffer to be used by the application so we'll reset it to the display's
+    * default event queue */
+   if (buffer)
+      wl_proxy_set_queue((struct wl_proxy *) buffer,
+                         wl_display_get_main_queue(dri2_dpy->wl_dpy));
+
+   return buffer;
+
+bad_format:
+   _eglError(EGL_BAD_MATCH, "unsupported image format");
+   return NULL;
+}
+
 static int
 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
 {
@@ -750,6 +826,8 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
    drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
    drv->API.Terminate = dri2_terminate;
    drv->API.QueryBufferAge = dri2_query_buffer_age;
+   drv->API.CreateWaylandBufferFromImageWL =
+      dri2_create_wayland_buffer_from_image_wl;
 
    dri2_dpy = calloc(1, sizeof *dri2_dpy);
    if (!dri2_dpy)
@@ -829,6 +907,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
    }
 
    disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
+   disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
    disp->Extensions.EXT_buffer_age = EGL_TRUE;
    dri2_dpy->authenticate = dri2_wayland_authenticate;
 
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 2d8653f..5399932 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -967,6 +967,9 @@ eglGetProcAddress(const char *procname)
       { "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL },
       { "eglQueryWaylandBufferWL", (_EGLProc) eglQueryWaylandBufferWL },
 #endif
+#ifdef EGL_WL_create_wayland_buffer_from_image
+      { "eglCreateWaylandBufferFromImageWL", (_EGLProc) eglCreateWaylandBufferFromImageWL },
+#endif
       { "eglPostSubBufferNV", (_EGLProc) eglPostSubBufferNV },
 #ifdef EGL_EXT_swap_buffers_with_damage
       { "eglSwapBuffersWithDamageEXT", (_EGLProc) eglSwapBuffersWithDamageEXT },
@@ -1595,6 +1598,28 @@ eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer,
 }
 #endif
 
+#ifdef EGL_WL_create_wayland_buffer_from_image
+struct wl_buffer * EGLAPIENTRY
+eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLImage *img;
+   _EGLDriver *drv;
+   struct wl_buffer *ret;
+
+   _EGL_CHECK_DISPLAY(disp, NULL, drv);
+   assert(disp->Extensions.WL_create_wayland_buffer_from_image);
+
+   img = _eglLookupImage(image, disp);
+
+   if (!img)
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, NULL);
+
+   ret = drv->API.CreateWaylandBufferFromImageWL(drv, disp, img);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+#endif
 
 EGLBoolean EGLAPIENTRY
 eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface,
diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h
index 4a4f976..0580344 100644
--- a/src/egl/main/eglapi.h
+++ b/src/egl/main/eglapi.h
@@ -126,6 +126,10 @@ typedef EGLBoolean (*UnbindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *dis
 typedef EGLBoolean (*QueryWaylandBufferWL_t)(_EGLDriver *drv, _EGLDisplay *displ, struct wl_resource *buffer, EGLint attribute, EGLint *value);
 #endif
 
+#ifdef EGL_WL_create_wayland_buffer_from_image
+typedef struct wl_buffer * (*CreateWaylandBufferFromImageWL_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img);
+#endif
+
 typedef EGLBoolean (*PostSubBufferNV_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surface, EGLint x, EGLint y, EGLint width, EGLint height);
 
 typedef EGLint (*QueryBufferAge_t)(_EGLDriver *drv,
@@ -210,6 +214,10 @@ struct _egl_api
    QueryWaylandBufferWL_t QueryWaylandBufferWL;
 #endif
 
+#ifdef EGL_WL_create_wayland_buffer_from_image
+   CreateWaylandBufferFromImageWL_t CreateWaylandBufferFromImageWL;
+#endif
+
 #ifdef EGL_EXT_swap_buffers_with_damage
    SwapBuffersWithDamageEXT_t SwapBuffersWithDamageEXT;
 #endif /* EGL_EXT_swap_buffers_with_damage */
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index fefd19c..b95b2f7 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -91,6 +91,7 @@ struct _egl_extensions
    EGLBoolean MESA_drm_image;
 
    EGLBoolean WL_bind_wayland_display;
+   EGLBoolean WL_create_wayland_buffer_from_image;
 
    EGLBoolean KHR_image_base;
    EGLBoolean KHR_image_pixmap;
diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c
index 2decc1b..cff6166 100644
--- a/src/egl/main/eglmisc.c
+++ b/src/egl/main/eglmisc.c
@@ -92,6 +92,7 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy)
    _EGL_CHECK_EXTENSION(MESA_drm_image);
 
    _EGL_CHECK_EXTENSION(WL_bind_wayland_display);
+   _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image);
 
    _EGL_CHECK_EXTENSION(KHR_image_base);
    _EGL_CHECK_EXTENSION(KHR_image_pixmap);
-- 
1.8.3.1



More information about the wayland-devel mailing list