[RFC v3 06/22] RFC: egl/x11: Support DRI3 v1.1

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Wed Sep 27 05:28:36 UTC 2017


Add support for DRI3 v1.1, which allows pixmaps to be backed by
multi-planar buffers, or those with format modifiers. This is both
for allocating render buffers, as well as EGLImage imports from a
native pixmap (EGL_NATIVE_PIXMAP_KHR).

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom at imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov at collabora.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
---
 src/egl/drivers/dri2/egl_dri2.c          |   7 +
 src/egl/drivers/dri2/egl_dri2.h          |   3 +
 src/egl/drivers/dri2/platform_x11_dri3.c |  98 +++++++++--
 src/glx/dri3_glx.c                       |  10 +-
 src/loader/loader_dri3_helper.c          | 272 ++++++++++++++++++++++++++-----
 src/loader/loader_dri3_helper.h          |  17 +-
 6 files changed, 353 insertions(+), 54 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index b17675e1ba..7dcee161bb 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -835,6 +835,13 @@ dri2_setup_extensions(_EGLDisplay *disp)
    if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false))
       return EGL_FALSE;
 
+#ifdef HAVE_DRI3
+   dri2_dpy->multibuffers_available =
+      (dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 &&
+                                            dri2_dpy->dri3_minor_version >= 1)) &&
+      (dri2_dpy->image && dri2_dpy->image->base.version >= 15);
+#endif
+
    dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
    return EGL_TRUE;
 }
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 10a4151817..b0811ae3eb 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -206,6 +206,9 @@ struct dri2_egl_display
    xcb_screen_t             *screen;
    bool                     swap_available;
 #ifdef HAVE_DRI3
+   bool                     multibuffers_available;
+   int                      dri3_major_version;
+   int                      dri3_minor_version;
    struct loader_dri3_extensions loader_dri3_ext;
 #endif
 #endif
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c
index 45bb56ca17..5ca4347254 100644
--- a/src/egl/drivers/dri2/platform_x11_dri3.c
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c
@@ -39,6 +39,21 @@
 #include "loader.h"
 #include "loader_dri3_helper.h"
 
+static uint32_t
+dri3_format_for_depth(uint32_t depth)
+{
+   switch (depth) {
+   case 16:
+      return __DRI_IMAGE_FORMAT_RGB565;
+   case 24:
+      return __DRI_IMAGE_FORMAT_XRGB8888;
+   case 32:
+      return __DRI_IMAGE_FORMAT_ARGB8888;
+   default:
+      return __DRI_IMAGE_FORMAT_NONE;
+   }
+}
+
 static struct dri3_egl_surface *
 loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {
    size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
@@ -156,7 +171,9 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
 
    if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
                                  dri2_dpy->dri_screen,
-                                 dri2_dpy->is_different_gpu, dri_config,
+                                 dri2_dpy->is_different_gpu,
+                                 dri2_dpy->multibuffers_available,
+                                 dri_config,
                                  &dri2_dpy->loader_dri3_ext,
                                  &egl_dri3_vtable,
                                  &dri3_surf->loader_drawable)) {
@@ -262,17 +279,8 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
       return NULL;
    }
 
-   switch (bp_reply->depth) {
-   case 16:
-      format = __DRI_IMAGE_FORMAT_RGB565;
-      break;
-   case 24:
-      format = __DRI_IMAGE_FORMAT_XRGB8888;
-      break;
-   case 32:
-      format = __DRI_IMAGE_FORMAT_ARGB8888;
-      break;
-   default:
+   format = dri3_format_for_depth(bp_reply->depth);
+   if (format == __DRI_IMAGE_FORMAT_NONE) {
       _eglError(EGL_BAD_PARAMETER,
                 "dri3_create_image_khr: unsupported pixmap depth");
       free(bp_reply);
@@ -299,15 +307,78 @@ dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
    return &dri2_img->base;
 }
 
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+static _EGLImage *
+dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
+                                          EGLClientBuffer buffer,
+                                          const EGLint *attr_list)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_image *dri2_img;
+   xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
+   xcb_dri3_buffers_from_pixmap_reply_t  *bp_reply;
+   xcb_drawable_t drawable;
+   unsigned int format;
+
+   drawable = (xcb_drawable_t) (uintptr_t) buffer;
+   bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
+   bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
+                                                 bp_cookie, NULL);
+
+   if (!bp_reply) {
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   dri2_img = malloc(sizeof *dri2_img);
+   if (!dri2_img) {
+      _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   format = dri3_format_for_depth(bp_reply->depth);
+   if (format == __DRI_IMAGE_FORMAT_NONE) {
+      _eglError(EGL_BAD_PARAMETER,
+                "dri3_create_image_khr: unsupported pixmap depth");
+      free(bp_reply);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   _eglInitImage(&dri2_img->base, disp);
+
+   dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
+                                                               bp_reply,
+                                                               format,
+                                                               dri2_dpy->dri_screen,
+                                                               dri2_dpy->image,
+                                                               dri2_img);
+   free(bp_reply);
+
+   if (!dri2_img->dri_image) {
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+      free(dri2_img);
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   return &dri2_img->base;
+}
+#endif
+
 static _EGLImage *
 dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
                       _EGLContext *ctx, EGLenum target,
                       EGLClientBuffer buffer, const EGLint *attr_list)
 {
    (void) drv;
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
 
    switch (target) {
    case EGL_NATIVE_PIXMAP_KHR:
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+      if (dri2_dpy->multibuffers_available)
+         return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
+                                                          attr_list);
+#endif
       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
    default:
       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
@@ -469,6 +540,9 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
       free(error);
       return EGL_FALSE;
    }
+
+   dri2_dpy->dri3_major_version = dri3_query->major_version;
+   dri2_dpy->dri3_minor_version = dri3_query->minor_version;
    free(dri3_query);
 
    present_query =
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index b79fec7335..2041e7436f 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -338,7 +338,10 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
 {
    struct dri3_drawable *pdraw;
    struct dri3_screen *psc = (struct dri3_screen *) base;
+   const struct dri3_display *const pdp = (struct dri3_display *)
+      base->display->dri3Display;
    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+   bool has_multibuffer = false;
 
    pdraw = calloc(1, sizeof(*pdraw));
    if (!pdraw)
@@ -349,11 +352,16 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
    pdraw->base.drawable = drawable;
    pdraw->base.psc = &psc->base;
 
+   if ((psc->image && psc->image->base.version >= 15) &&
+       (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 1)))
+      has_multibuffer = true;
+
    (void) __glXInitialize(psc->base.dpy);
 
    if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy),
                                  xDrawable, psc->driScreen,
-                                 psc->is_different_gpu, config->driConfig,
+                                 psc->is_different_gpu, has_multibuffer,
+                                 config->driConfig,
                                  &psc->loader_dri3_ext, &glx_dri3_vtable,
                                  &pdraw->loader_drawable)) {
       free(pdraw);
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index bcd5a66ad2..f6bc1c52e8 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -41,6 +41,10 @@
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
 
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
 /**
  * A cached blit context.
  */
@@ -252,6 +256,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
                           xcb_drawable_t drawable,
                           __DRIscreen *dri_screen,
                           bool is_different_gpu,
+                          bool multiplanes_available,
                           const __DRIconfig *dri_config,
                           struct loader_dri3_extensions *ext,
                           const struct loader_dri3_vtable *vtable,
@@ -269,6 +274,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
    draw->drawable = drawable;
    draw->dri_screen = dri_screen;
    draw->is_different_gpu = is_different_gpu;
+   draw->multiplanes_available = multiplanes_available;
 
    draw->have_back = 0;
    draw->have_fake_front = 0;
@@ -1002,8 +1008,10 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
    xcb_pixmap_t pixmap;
    xcb_sync_fence_t sync_fence;
    struct xshmfence *shm_fence;
-   int buffer_fd, fence_fd;
-   int stride;
+   int buffer_fds[4], fence_fd;
+   int num_planes = 0;
+   int i, mod;
+   int ret;
 
    /* Create an xshmfence object and
     * prepare to send that to the X server
@@ -1028,13 +1036,85 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
       goto no_image;
 
    if (!draw->is_different_gpu) {
-      buffer->image = draw->ext->image->createImage(draw->dri_screen,
-                                                    width, height,
-                                                    format,
-                                                    __DRI_IMAGE_USE_SHARE |
-                                                    __DRI_IMAGE_USE_SCANOUT |
-                                                    __DRI_IMAGE_USE_BACKBUFFER,
-                                                    buffer);
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+      if (draw->multiplanes_available &&
+          draw->ext->image->base.version >= 18 &&
+          draw->ext->image->queryDmaBufModifiers &&
+          draw->ext->image->createImageWithModifiers2) {
+         xcb_dri3_get_supported_modifiers_cookie_t mod_cookie;
+         xcb_dri3_get_supported_modifiers_reply_t *mod_reply;
+         xcb_generic_error_t *error = NULL;
+         uint64_t *modifiers[2] = {NULL, NULL};
+         uint32_t counts[2] = {0, 0};
+         uint32_t n = 0;
+         uint32_t *mod_parts;
+         int i;
+
+         mod_cookie = xcb_dri3_get_supported_modifiers(draw->conn,
+                                                       draw->drawable,
+                                                       depth, buffer->cpp * 8);
+         mod_reply = xcb_dri3_get_supported_modifiers_reply(draw->conn,
+                                                            mod_cookie,
+                                                            &error);
+         if (!mod_reply)
+            goto no_image;
+
+         if (mod_reply->num_drawable_modifiers) {
+            counts[n] = mod_reply->num_drawable_modifiers;
+            modifiers[n] = malloc(counts[n] * sizeof(uint64_t));
+            if (!modifiers[n]) {
+               free(mod_reply);
+               goto no_image;
+            }
+
+            mod_parts = xcb_dri3_get_supported_modifiers_drawable_modifiers(mod_reply);
+            for (i = 0; i < counts[n]; i++) {
+               modifiers[n][i] = (uint64_t) mod_parts[i * 2] << 32;
+               modifiers[n][i] |= (uint64_t) mod_parts[i * 2 + 1] & 0xffffff;
+            }
+            n++;
+         }
+
+         if (mod_reply->num_screen_modifiers) {
+            counts[n] = mod_reply->num_screen_modifiers;
+            modifiers[n] = malloc(counts[n] * sizeof(uint64_t));
+            if (!modifiers[n]) {
+               free(modifiers[0]);
+               free(mod_reply);
+               goto no_image;
+            }
+
+            mod_parts = xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply);
+            for (i = 0; i < counts[n]; i++) {
+               modifiers[n][i] = (uint64_t) mod_parts[i * 2] << 32;
+               modifiers[n][i] |= (uint64_t) mod_parts[i * 2 + 1] & 0xffffff;
+            }
+            n++;
+         }
+
+         free(mod_reply);
+
+         buffer->image = draw->ext->image->createImageWithModifiers2(draw->dri_screen,
+                                                                     width, height,
+                                                                     format,
+                                                                     modifiers,
+                                                                     counts,
+                                                                     n,
+                                                                     buffer);
+         for (i = 0; i < n; i++)
+            free(modifiers[i]);
+      }
+#endif
+
+      if (!buffer->image)
+         buffer->image = draw->ext->image->createImage(draw->dri_screen,
+                                                       width, height,
+                                                       format,
+                                                       __DRI_IMAGE_USE_SHARE |
+                                                       __DRI_IMAGE_USE_SCANOUT |
+                                                       __DRI_IMAGE_USE_BACKBUFFER,
+                                                       buffer);
+
       pixmap_buffer = buffer->image;
 
       if (!buffer->image)
@@ -1062,25 +1142,71 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
          goto no_linear_buffer;
    }
 
-   /* X wants the stride, so ask the image for it
+   /* X want some information about the planes, so ask the image for it
     */
-   if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE,
-                                     &stride))
-      goto no_buffer_attrib;
-
-   buffer->pitch = stride;
-
-   if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD,
-                                     &buffer_fd))
-      goto no_buffer_attrib;
+   draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_NUM_PLANES,
+                                &num_planes);
+   if (num_planes <= 0)
+      num_planes = 1;
+
+   for (i = 0; i < num_planes; i++) {
+      __DRIimage *image = draw->ext->image->fromPlanar(pixmap_buffer, i, NULL);
+
+      if (!image)
+         image = pixmap_buffer;
+
+      ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD,
+                                         &buffer_fds[i]);
+      ret &= draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE,
+                                          &buffer->strides[i]);
+      ret &= draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET,
+                                          &buffer->offsets[i]);
+      if (image != pixmap_buffer)
+         draw->ext->image->destroyImage(image);
+
+      if (!ret)
+         goto no_buffer_attrib;
+   }
 
-   xcb_dri3_pixmap_from_buffer(draw->conn,
-                               (pixmap = xcb_generate_id(draw->conn)),
-                               draw->drawable,
-                               buffer->size,
-                               width, height, buffer->pitch,
-                               depth, buffer->cpp * 8,
-                               buffer_fd);
+   ret = draw->ext->image->queryImage(pixmap_buffer,
+                                     __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, &mod);
+   buffer->modifier = (uint64_t) mod << 32;
+   ret &= draw->ext->image->queryImage(pixmap_buffer,
+                                       __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &mod);
+   buffer->modifier |= (uint64_t)(mod & 0xffffffff);
+
+   if (!ret)
+      buffer->modifier = DRM_FORMAT_MOD_INVALID;
+
+   pixmap = xcb_generate_id(draw->conn);
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+   if (draw->multiplanes_available &&
+       buffer->modifier != DRM_FORMAT_MOD_INVALID) {
+      xcb_dri3_pixmap_from_buffers(draw->conn,
+                                   pixmap,
+                                   draw->drawable,
+                                   num_planes,
+                                   width, height,
+                                   buffer->strides[0], buffer->offsets[0],
+                                   buffer->strides[1], buffer->offsets[1],
+                                   buffer->strides[2], buffer->offsets[2],
+                                   buffer->strides[3], buffer->offsets[3],
+                                   depth, buffer->cpp * 8,
+                                   buffer->modifier >> 32,
+                                   buffer->modifier & 0xffffffff,
+                                   buffer_fds);
+   }
+   else
+#endif
+   {
+      xcb_dri3_pixmap_from_buffer(draw->conn,
+                                  pixmap,
+                                  draw->drawable,
+                                  buffer->size,
+                                  width, height, buffer->strides[0],
+                                  depth, buffer->cpp * 8,
+                                  buffer_fds[0]);
+   }
 
    xcb_dri3_fence_from_fd(draw->conn,
                           pixmap,
@@ -1102,6 +1228,9 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
    return buffer;
 
 no_buffer_attrib:
+   do {
+      close(buffer_fds[i]);
+   } while (--i >= 0);
    draw->ext->image->destroyImage(pixmap_buffer);
 no_linear_buffer:
    if (draw->is_different_gpu)
@@ -1250,6 +1379,45 @@ loader_dri3_create_image(xcb_connection_t *c,
    return ret;
 }
 
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+                                      xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+                                      unsigned int format,
+                                      __DRIscreen *dri_screen,
+                                      const __DRIimageExtension *image,
+                                      void *loaderPrivate)
+{
+   int                                  *fds;
+   uint32_t                             *strides_in, *offsets_in;
+   int                                   strides[4], offsets[4];
+   uint64_t                              modifier;
+   unsigned                              error;
+   int                                   i;
+
+   if (bp_reply->nfd > 4)
+      return NULL;
+
+   fds = xcb_dri3_buffers_from_pixmap_reply_fds(c, bp_reply);
+   strides_in = xcb_dri3_buffers_from_pixmap_strides(bp_reply);
+   offsets_in = xcb_dri3_buffers_from_pixmap_offsets(bp_reply);
+   for (i = 0; i < bp_reply->nfd; i++) {
+      strides[i] = strides_in[i];
+      offsets[i] = offsets_in[i];
+   }
+
+   return image->createImageFromDmaBufs2(dri_screen,
+                                         bp_reply->width,
+                                         bp_reply->height,
+                                         image_format_to_fourcc(format),
+                                         bp_reply->modifier,
+                                         fds, bp_reply->nfd,
+                                         strides, offsets,
+                                         0, 0, 0, 0, /* UNDEFINED */
+                                         &error, loaderPrivate);
+}
+#endif
+
 /** dri3_get_pixmap_buffer
  *
  * Get the DRM object for a pixmap from the X server and
@@ -1263,10 +1431,10 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
    int                                  buf_id = loader_dri3_pixmap_buf_id(buffer_type);
    struct loader_dri3_buffer            *buffer = draw->buffers[buf_id];
    xcb_drawable_t                       pixmap;
-   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
-   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
    xcb_sync_fence_t                     sync_fence;
    struct xshmfence                     *shm_fence;
+   int                                  width;
+   int                                  height;
    int                                  fence_fd;
 
    if (buffer)
@@ -1293,32 +1461,56 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
                           false,
                           fence_fd);
 
-   bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap);
-   bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL);
-   if (!bp_reply)
-      goto no_image;
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+   if (draw->multiplanes_available && draw->ext->image->base.version >= 15) {
+      xcb_dri3_buffers_from_pixmap_cookie_t bps_cookie;
+      xcb_dri3_buffers_from_pixmap_reply_t *bps_reply;
+
+      bps_cookie = xcb_dri3_buffers_from_pixmap(draw->conn, pixmap);
+      bps_reply = xcb_dri3_buffers_from_pixmap_reply(draw->conn, bps_cookie,
+                                                     NULL);
+      buffer->image =
+         loader_dri3_create_image_from_buffers(draw->conn, bps_reply, format,
+                                               draw->dri_screen,
+                                               draw->ext->image,
+                                               buffer);
+      width = bps_reply->width;
+      height = bps_reply->height;
+      free(bps_reply);
+   } else
+#endif
+   {
+      xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
+      xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
+
+      bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap);
+      bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL);
+      if (!bp_reply)
+         goto no_image;
+
+      buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format,
+                                               draw->dri_screen,
+                                               draw->ext->image, buffer);
+      width = bp_reply->width;
+      height = bp_reply->height;
+      free(bp_reply);
+   }
 
-   buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format,
-                                            draw->dri_screen, draw->ext->image,
-                                            buffer);
    if (!buffer->image)
       goto no_image;
 
    buffer->pixmap = pixmap;
    buffer->own_pixmap = false;
-   buffer->width = bp_reply->width;
-   buffer->height = bp_reply->height;
+   buffer->width = width;
+   buffer->height = height;
    buffer->shm_fence = shm_fence;
    buffer->sync_fence = sync_fence;
 
    draw->buffers[buf_id] = buffer;
 
-   free(bp_reply);
-
    return buffer;
 
 no_image:
-   free(bp_reply);
    xcb_sync_destroy_fence(draw->conn, sync_fence);
    xshmfence_unmap_shm(shm_fence);
 no_fence:
diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
index d3f4b0c00a..03c874fe0d 100644
--- a/src/loader/loader_dri3_helper.h
+++ b/src/loader/loader_dri3_helper.h
@@ -61,8 +61,11 @@ struct loader_dri3_buffer {
    bool         busy;           /* Set on swap, cleared on IdleNotify */
    bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy */
 
+   uint32_t     num_planes;
    uint32_t     size;
-   uint32_t     pitch;
+   int          strides[4];
+   int          offsets[4];
+   uint64_t     modifier;
    uint32_t     cpp;
    uint32_t     flags;
    uint32_t     width, height;
@@ -119,6 +122,7 @@ struct loader_dri3_drawable {
    /* Information about the GPU owning the buffer */
    __DRIscreen *dri_screen;
    bool is_different_gpu;
+   bool multiplanes_available;
 
    /* Present extension capabilities
     */
@@ -173,6 +177,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
                           xcb_drawable_t drawable,
                           __DRIscreen *dri_screen,
                           bool is_different_gpu,
+                          bool is_multiplanes_available,
                           const __DRIconfig *dri_config,
                           struct loader_dri3_extensions *ext,
                           const struct loader_dri3_vtable *vtable,
@@ -230,6 +235,16 @@ loader_dri3_create_image(xcb_connection_t *c,
                          const __DRIimageExtension *image,
                          void *loaderPrivate);
 
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+                                      xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+                                      unsigned int format,
+                                      __DRIscreen *dri_screen,
+                                      const __DRIimageExtension *image,
+                                      void *loaderPrivate);
+#endif
+
 int
 loader_dri3_get_buffers(__DRIdrawable *driDrawable,
                         unsigned int format,
-- 
2.13.0



More information about the xorg-devel mailing list