Mesa (master): egl: Add EGL_WAYLAND_PLANE_WL attribute

Kristian Høgsberg krh at kemper.freedesktop.org
Wed Jul 11 19:34:00 UTC 2012


Module: Mesa
Branch: master
Commit: e6a33570b73aa56c87818d7f67a122d4427b7841
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=e6a33570b73aa56c87818d7f67a122d4427b7841

Author: Kristian Høgsberg <krh at bitplanet.net>
Date:   Thu Jul  5 16:43:04 2012 -0400

egl: Add EGL_WAYLAND_PLANE_WL attribute

This lets us specify the plane to create the image for for multiplanar
wl_buffers.

Signed-off-by: Kristian Høgsberg <krh at bitplanet.net>

---

 docs/WL_bind_wayland_display.spec         |   90 +++++++++++++++++-
 include/EGL/eglmesaext.h                  |   14 +++
 src/egl/drivers/dri2/egl_dri2.c           |  150 ++++++++++++++++++++++++++---
 src/egl/main/eglapi.c                     |   20 ++++
 src/egl/main/eglapi.h                     |    2 +
 src/egl/main/eglimage.c                   |    5 +
 src/egl/main/eglimage.h                   |    3 +
 src/egl/wayland/wayland-drm/wayland-drm.h |    2 +-
 8 files changed, 267 insertions(+), 19 deletions(-)

diff --git a/docs/WL_bind_wayland_display.spec b/docs/WL_bind_wayland_display.spec
index e2fde3c..e1aca53 100644
--- a/docs/WL_bind_wayland_display.spec
+++ b/docs/WL_bind_wayland_display.spec
@@ -56,12 +56,34 @@ New Procedures and Functions
     EGLBoolean eglUnbindWaylandDisplayWL(EGLDisplay dpy,
                                          struct wl_display *display);
 
+    EGLBoolean eglQueryWaylandBufferWL(EGLDisplay dpy,
+                                       struct wl_buffer *buffer,
+                                       EGLint attribute, EGLint *value);
+
 New Tokens
 
     Accepted as <target> in eglCreateImageKHR
 
         EGL_WAYLAND_BUFFER_WL                   0x31D5
 
+    Accepted in the <attrib_list> parameter of eglCreateImageKHR:
+
+        EGL_WAYLAND_PLANE_WL                    0x31D6
+
+
+    Accepted as a eglQueryWaylandBufferWL attribute:
+
+        EGL_WAYLAND_BUFFER_COMPONENTS_WL	0x31D7
+
+    Possible values for EGL_WAYLAND_BUFFER_COMPONENTS_WL:    
+
+        EGL_WAYLAND_BUFFER_RGB_WL               0x31D8
+        EGL_WAYLAND_BUFFER_RGBA_WL              0x31D9
+        EGL_WAYLAND_BUFFER_Y_U_V_WL             0x31Da
+        EGL_WAYLAND_BUFFER_Y_UV_WL              0x31Db
+        EGL_WAYLAND_BUFFER_Y_XUXV_WL            0x31Dc
+
+
 Additions to the EGL 1.4 Specification:
 
     To bind a server side wl_display to an EGLDisplay, call
@@ -80,9 +102,65 @@ Additions to the EGL 1.4 Specification:
     eglUnbindWaylandDisplayWL returns EGL_FALSE when there is no
     wl_display bound to the EGLDisplay currently otherwise EGL_TRUE.
 
-    Import a wl_buffer by calling eglCreateImageKHR with
-    wl_buffer as EGLClientBuffer, EGL_WAYLAND_BUFFER_WL as the target,
-    NULL context and an empty attribute_list.
+    A wl_buffer can have several planes, typically in case of planar
+    YUV formats.  Depending on the exact YUV format in use, the
+    compositor will have to create one or more EGLImages for the
+    various planes.  The eglQueryWaylandBufferWL function should be
+    used to first query the wl_buffer components using
+    EGL_WAYLAND_BUFFER_COMPONENTS_WL as the attribute.  If the
+    wl_buffer object is not an EGL wl_buffer (wl_shm and other wayland
+    extensions can create wl_buffer objects), this query will return
+    EGL_FALSE.  In that case the wl_buffer can not be used with EGL
+    and the compositor should have another way to get the buffer
+    contents.
+
+    If eglQueryWaylandBufferWL succeeds, the returned value will be
+    one of EGL_WAYLAND_BUFFER_RGB_WL, EGL_WAYLAND_BUFFER_RGBA_WL,
+    EGL_WAYLAND_BUFFER_Y_U_V_WL, EGL_WAYLAND_BUFFER_Y_UV_WL,
+    EGL_WAYLAND_BUFFER_Y_XUXV_WL.  The value returned describes how
+    many EGLImages must be used, which components will be sampled from
+    each EGLImage and how they map to rgba components in the shader.
+    The naming conventions separates planes by _ and within each
+    plane, the order or R, G, B, A, Y, U, and V indicates how those
+    components map to the rgba value returned by the sampler.  X
+    indicates that the corresponding component in the rgba value isn't
+    used.
+
+    RGB and RGBA buffer types:
+
+        EGL_WAYLAND_BUFFER_RGB_WL
+                One plane, samples RGB from the texture to rgb in the
+                shader.  Alpha channel is not valid.
+
+        EGL_WAYLAND_BUFFER_RGBA_WL              0x31D9
+                One plane, samples RGBA from the texture to rgba in the
+                shader.
+
+    YUV buffer types:
+
+        EGL_WAYLAND_BUFFER_Y_U_V_WL             0x31Da
+                Three planes, samples Y from the first plane to r in
+                the shader, U from the second plane to r, and V from
+                the third plane to r.
+
+        EGL_WAYLAND_BUFFER_Y_UV_WL              0x31Db
+                Two planes, samples Y from the first plane to r in
+                the shader, U and V from the second plane to rg.
+
+        EGL_WAYLAND_BUFFER_Y_XUXV_WL            0x31Dc
+                Two planes, samples Y from the first plane to r in
+                the shader, U and V from the second plane to g and a.
+
+    After querying the wl_buffer layout, create EGLImages for the
+    planes by calling eglCreateImageKHR with wl_buffer as
+    EGLClientBuffer, EGL_WAYLAND_BUFFER_WL as the target, NULL
+    context.  If no attributes are given, an EGLImage will be created
+    for the first plane.  For multi-planar buffers, specify the plane
+    to create the EGLImage for by using the EGL_WAYLAND_PLANE_WL
+    attribute.  The value of the attribute is the index of the plane,
+    as defined by the buffer format.  Writing to an EGLImage created
+    from a wl_buffer in any way (such as glTexImage2D, binding the
+    EGLImage as a renderbuffer etc) will result in undefined behavior.
 
 Issues
 
@@ -90,3 +168,9 @@ Revision History
 
     Version 1, March 1, 2011
         Initial draft (Benjamin Franzke)
+    Version 2, July 5, 2012
+        Add EGL_WAYLAND_PLANE_WL attribute to allow creating an EGLImage
+        for different planes of planar buffer. (Kristian Høgsberg)
+    Version 3, July 10, 2012
+        Add eglQueryWaylandBufferWL and the various buffer
+        formats. (Kristian Høgsberg)
diff --git a/include/EGL/eglmesaext.h b/include/EGL/eglmesaext.h
index 52dd5b1..74d8ced 100644
--- a/include/EGL/eglmesaext.h
+++ b/include/EGL/eglmesaext.h
@@ -113,13 +113,27 @@ typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDRMDISPLAYMESA) (int fd);
 #define EGL_WL_bind_wayland_display 1
 
 #define EGL_WAYLAND_BUFFER_WL			0x31D5 /* eglCreateImageKHR target */
+#define EGL_WAYLAND_PLANE_WL			0x31D6 /* eglCreateImageKHR target */
+
+#define EGL_WAYLAND_BUFFER_COMPONENTS_WL	0x31D7 /* eglQueryWaylandBufferWL attribute */
+
+#define EGL_WAYLAND_BUFFER_RGB_WL	0x31D8
+#define EGL_WAYLAND_BUFFER_RGBA_WL	0x31D9
+#define EGL_WAYLAND_BUFFER_Y_U_V_WL	0x31Da
+#define EGL_WAYLAND_BUFFER_Y_UV_WL	0x31Db
+#define EGL_WAYLAND_BUFFER_Y_XUXV_WL	0x31Dc
+
 struct wl_display;
+struct wl_buffer;
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
 EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
 #endif
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
+
 #endif
 
 #ifndef EGL_NOK_swap_region
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 0fc33e0..fcb2264 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -1052,20 +1052,120 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
 }
 
 #ifdef HAVE_WAYLAND_PLATFORM
+
+/* This structure describes how a wl_buffer maps to one or more
+ * __DRIimages.  A wl_drm_buffer stores the wl_drm format code and the
+ * offsets and strides of the planes in the buffer.  This table maps a
+ * wl_drm format code to a description of the planes in the buffer
+ * that lets us create a __DRIimage for each of the planes. */
+
+static const struct wl_drm_format_descriptor {
+   uint32_t wl_format;
+   EGLint components;
+   int nplanes;
+   struct {
+      int buffer_index;
+      int width_shift;
+      int height_shift;
+      uint32_t dri_format;
+      int cpp;
+   } planes[3];
+} wl_drm_formats[] = {
+   { WL_DRM_FORMAT_ARGB8888, EGL_WAYLAND_BUFFER_RGBA_WL, 1,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 }, } },
+
+   { WL_DRM_FORMAT_XRGB8888, EGL_WAYLAND_BUFFER_RGB_WL, 1,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB8888, 4 }, } },
+
+   { WL_DRM_FORMAT_YUV410, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 2, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 } } },
+
+   { WL_DRM_FORMAT_YUV411, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 2, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
+
+   { WL_DRM_FORMAT_YUV420, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 2, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 } } },
+
+   { WL_DRM_FORMAT_YUV422, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 2, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
+
+   { WL_DRM_FORMAT_YUV444, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 2, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
+
+   { WL_DRM_FORMAT_NV12, EGL_WAYLAND_BUFFER_Y_UV_WL, 2,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88, 2 } } },
+
+   { WL_DRM_FORMAT_NV16, EGL_WAYLAND_BUFFER_Y_UV_WL, 2,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
+       { 1, 1, 0, __DRI_IMAGE_FORMAT_GR88, 2 } } },
+
+   /* For YUYV buffers, we set up two overlapping DRI images and treat
+    * them as planar buffers in the compositors.  Plane 0 is GR88 and
+    * samples YU or YV pairs and places Y into the R component, while
+    * plane 1 is ARGB and samples YUYV clusters and places pairs and
+    * places U into the G component and V into A.  This lets the
+    * texture sampler interpolate the Y components correctly when
+    * sampling from plane 0, and interpolate U and V correctly when
+    * sampling from plane 1. */
+   { WL_DRM_FORMAT_YUYV, EGL_WAYLAND_BUFFER_Y_XUXV_WL, 2,
+     { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 },
+       { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 } } }
+};
+
 static _EGLImage *
 dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
 				    EGLClientBuffer _buffer,
 				    const EGLint *attr_list)
 {
-   struct wl_buffer *buffer = (struct wl_buffer *) _buffer;
+   struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
-   __DRIimage *dri_image, *source;
+   __DRIimage *dri_image;
+   _EGLImageAttribs attrs;
+   EGLint err;
+   uint32_t format;
+   int32_t offset, stride, plane, width, height;
+   int cpp, index;
+   const struct wl_drm_format_descriptor *f;
 
-   if (!wayland_buffer_is_drm(buffer))
+   if (!wayland_buffer_is_drm(&buffer->buffer))
        return NULL;
 
-   source = wayland_drm_buffer_get_buffer(buffer);
-   dri_image = dri2_dpy->image->dupImage(source, NULL);
+   err = _eglParseImageAttribList(&attrs, disp, attr_list);
+   plane = attrs.PlaneWL;
+   if (err != EGL_SUCCESS) {
+      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
+      return NULL;
+   }
+
+   f = buffer->driver_format;
+   if (plane < 0 || plane >= f->nplanes) {
+      _eglError(EGL_BAD_PARAMETER,
+                "dri2_create_image_wayland_wl_buffer (plane out of bounds)");
+      return NULL;
+   }
+
+   width = buffer->buffer.width >> f->planes[plane].width_shift;
+   height = buffer->buffer.height >> f->planes[plane].height_shift;
+   format = f->planes[plane].dri_format;
+   cpp = f->planes[plane].cpp;
+   index = f->planes[plane].buffer_index;
+   offset = buffer->offset[index];
+   stride = buffer->stride[index];
+
+   dri_image = dri2_dpy->image->createSubImage(buffer->driver_buffer,
+                                               width, height, format,
+                                               offset, stride / cpp, NULL);
 
    return dri2_create_image(disp, dri_image);
 }
@@ -1226,23 +1326,22 @@ dri2_wl_reference_buffer(void *user_data, uint32_t name,
 {
    _EGLDisplay *disp = user_data;
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   int i;
 
-   switch (buffer->format) {
-   case WL_DRM_FORMAT_ARGB8888:
-      buffer->driver_format =__DRI_IMAGE_FORMAT_ARGB8888;
-      break;
-   case WL_DRM_FORMAT_XRGB8888:
-      buffer->driver_format = __DRI_IMAGE_FORMAT_XRGB8888;
-      break;
-   default:
+   for (i = 0; i < ARRAY_SIZE(wl_drm_formats); i++)
+      if (wl_drm_formats[i].wl_format == buffer->format) {
+         buffer->driver_format = &wl_drm_formats[i];
+         break;
+      }
+
+   if (buffer->driver_format == NULL)
       return;
-   }
 
    buffer->driver_buffer =
       dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
                                            buffer->buffer.width,
                                            buffer->buffer.height, 
-                                           buffer->driver_format, name,
+                                           __DRI_IMAGE_FORMAT_NONE, name,
                                            buffer->stride[0] / 4,
                                            NULL);
 }
@@ -1302,6 +1401,26 @@ dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
 
    return EGL_TRUE;
 }
+
+static EGLBoolean
+dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
+                             struct wl_buffer *_buffer,
+                             EGLint attribute, EGLint *value)
+{
+   struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
+   const struct wl_drm_format_descriptor *format;
+
+   if (!wayland_buffer_is_drm(&buffer->buffer))
+      return EGL_FALSE;
+
+   format = buffer->driver_format;
+   if (attribute == EGL_WAYLAND_BUFFER_COMPONENTS_WL) {
+      *value = format->components;
+      return EGL_TRUE;
+   }
+
+   return EGL_FALSE;
+}
 #endif
 
 static void
@@ -1399,6 +1518,7 @@ _eglBuiltInDriverDRI2(const char *args)
 #ifdef HAVE_WAYLAND_PLATFORM
    dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
    dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
+   dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
 #endif
 
    dri2_drv->base.Name = "DRI2";
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index b27aac1..ffc404c 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -940,6 +940,7 @@ eglGetProcAddress(const char *procname)
 #ifdef EGL_WL_bind_wayland_display
       { "eglBindWaylandDisplayWL", (_EGLProc) eglBindWaylandDisplayWL },
       { "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL },
+      { "eglQueryWaylandBufferWL", (_EGLProc) eglQueryWaylandBufferWL },
 #endif
       { "eglPostSubBufferNV", (_EGLProc) eglPostSubBufferNV },
       { NULL, NULL }
@@ -1540,6 +1541,25 @@ eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display)
 
    RETURN_EGL_EVAL(disp, ret);
 }
+
+EGLBoolean EGLAPIENTRY
+eglQueryWaylandBufferWL(EGLDisplay dpy,struct wl_buffer *buffer,
+                        EGLint attribute, EGLint *value)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
+   assert(disp->Extensions.WL_bind_wayland_display);
+
+   if (!buffer)
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
+
+   ret = drv->API.QueryWaylandBufferWL(drv, disp, buffer, attribute, value);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
 #endif
 
 
diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h
index 14085cb..ec3ad7e 100644
--- a/src/egl/main/eglapi.h
+++ b/src/egl/main/eglapi.h
@@ -123,6 +123,7 @@ typedef EGLBoolean (*ExportDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _
 struct wl_display;
 typedef EGLBoolean (*BindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display);
 typedef EGLBoolean (*UnbindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display);
+typedef EGLBoolean (*QueryWaylandBufferWL_t)(_EGLDriver *drv, _EGLDisplay *displ, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
 #endif
 
 typedef EGLBoolean (*PostSubBufferNV_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surface, EGLint x, EGLint y, EGLint width, EGLint height);
@@ -199,6 +200,7 @@ struct _egl_api
 #ifdef EGL_WL_bind_wayland_display
    BindWaylandDisplayWL_t BindWaylandDisplayWL;
    UnbindWaylandDisplayWL_t UnbindWaylandDisplayWL;
+   QueryWaylandBufferWL_t QueryWaylandBufferWL;
 #endif
 
    PostSubBufferNV_t PostSubBufferNV;
diff --git a/src/egl/main/eglimage.c b/src/egl/main/eglimage.c
index 1174d0a..bfae709 100644
--- a/src/egl/main/eglimage.c
+++ b/src/egl/main/eglimage.c
@@ -88,6 +88,11 @@ _eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
          attrs->DRMBufferStrideMESA = val;
          break;
 
+      /* EGL_WL_bind_wayland_display */
+      case EGL_WAYLAND_PLANE_WL:
+         attrs->PlaneWL = val;
+         break;
+
       default:
          /* unknown attrs are ignored */
          break;
diff --git a/src/egl/main/eglimage.h b/src/egl/main/eglimage.h
index acb36aa..9cc86d5 100644
--- a/src/egl/main/eglimage.h
+++ b/src/egl/main/eglimage.h
@@ -50,6 +50,9 @@ struct _egl_image_attribs
    EGLint DRMBufferFormatMESA;
    EGLint DRMBufferUseMESA;
    EGLint DRMBufferStrideMESA;
+
+   /* EGL_WL_bind_wayland_display */
+   EGLint PlaneWL;
 };
 
 /**
diff --git a/src/egl/wayland/wayland-drm/wayland-drm.h b/src/egl/wayland/wayland-drm/wayland-drm.h
index 46aab69..4ef286f 100644
--- a/src/egl/wayland/wayland-drm/wayland-drm.h
+++ b/src/egl/wayland/wayland-drm/wayland-drm.h
@@ -13,7 +13,7 @@ struct wl_drm_buffer {
 	struct wl_buffer buffer;
 	struct wl_drm *drm;
 	uint32_t format;
-	uint32_t driver_format;
+        const void *driver_format;
         int32_t offset[3];
         int32_t stride[3];
 	void *driver_buffer;




More information about the mesa-commit mailing list