<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Feb 9, 2018 at 3:43 PM, Jason Ekstrand <span dir="ltr"><<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Louis-Francis Ratté-Boulianne <<a href="mailto:lfrb@collabora.com">lfrb@collabora.com</a>><br>
<br>
Add support for DRI3 v1.1, which allows pixmaps to be backed by<br>
multi-planar buffers, or those with format modifiers. This is both<br>
for allocating render buffers, as well as EGLImage imports from a<br>
native pixmap (EGL_NATIVE_PIXMAP_KHR).<br>
<br>
Signed-off-by: Louis-Francis Ratté-Boulianne <<a href="mailto:lfrb@collabora.com">lfrb@collabora.com</a>><br>
Reviewed-by: Eric Engestrom <<a href="mailto:eric.engestrom@imgtec.com">eric.engestrom@imgtec.com</a>><br>
Reviewed-by: Emil Velikov <<a href="mailto:emil.velikov@collabora.com">emil.velikov@collabora.com</a>><br>
Reviewed-by: Daniel Stone <<a href="mailto:daniels@collabora.com">daniels@collabora.com</a>><br>
---<br>
 src/egl/drivers/dri2/egl_dri2.<wbr>c          |   7 +<br>
 src/egl/drivers/dri2/egl_dri2.<wbr>h          |   3 +<br>
 src/egl/drivers/dri2/platform_<wbr>x11_dri3.c | 104 ++++++++++--<br>
 src/glx/dri3_glx.c                       |  10 +-<br>
 src/loader/loader_dri3_helper.<wbr>c          | 272 ++++++++++++++++++++++++++----<wbr>-<br>
 src/loader/loader_dri3_helper.<wbr>h          |  17 +-<br>
 6 files changed, 358 insertions(+), 55 deletions(-)<br>
<br>
diff --git a/src/egl/drivers/dri2/egl_<wbr>dri2.c b/src/egl/drivers/dri2/egl_<wbr>dri2.c<br>
index 34cdb9f..8147842 100644<br>
--- a/src/egl/drivers/dri2/egl_<wbr>dri2.c<br>
+++ b/src/egl/drivers/dri2/egl_<wbr>dri2.c<br>
@@ -885,6 +885,13 @@ dri2_setup_extensions(_<wbr>EGLDisplay *disp)<br>
    if (!dri2_bind_extensions(dri2_<wbr>dpy, mandatory_core_extensions, extensions, false))<br>
       return EGL_FALSE;<br>
<br>
+#ifdef HAVE_DRI3<br>
+   dri2_dpy->multibuffers_<wbr>available =<br>
+      (dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 &&<br>
+                                            dri2_dpy->dri3_minor_version >= 1)) &&<br>
+      (dri2_dpy->image && dri2_dpy->image->base.version >= 15);<br>
+#endif<br>
+<br>
    dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);<br>
    return EGL_TRUE;<br>
 }<br>
diff --git a/src/egl/drivers/dri2/egl_<wbr>dri2.h b/src/egl/drivers/dri2/egl_<wbr>dri2.h<br>
index 0f4e7a8..bff33df 100644<br>
--- a/src/egl/drivers/dri2/egl_<wbr>dri2.h<br>
+++ b/src/egl/drivers/dri2/egl_<wbr>dri2.h<br>
@@ -199,6 +199,9 @@ struct dri2_egl_display<br>
    xcb_screen_t             *screen;<br>
    bool                     swap_available;<br>
 #ifdef HAVE_DRI3<br>
+   bool                     multibuffers_available;<br>
+   int                      dri3_major_version;<br>
+   int                      dri3_minor_version;<br>
    struct loader_dri3_extensions loader_dri3_ext;<br>
 #endif<br>
 #endif<br>
diff --git a/src/egl/drivers/dri2/<wbr>platform_x11_dri3.c b/src/egl/drivers/dri2/<wbr>platform_x11_dri3.c<br>
index 6e40eaa..0532cd3 100644<br>
--- a/src/egl/drivers/dri2/<wbr>platform_x11_dri3.c<br>
+++ b/src/egl/drivers/dri2/<wbr>platform_x11_dri3.c<br>
@@ -39,6 +39,23 @@<br>
 #include "loader.h"<br>
 #include "loader_dri3_helper.h"<br>
<br>
+static uint32_t<br>
+dri3_format_for_depth(uint32_<wbr>t depth)<br>
+{<br>
+   switch (depth) {<br>
+   case 16:<br>
+      return __DRI_IMAGE_FORMAT_RGB565;<br>
+   case 24:<br>
+      return __DRI_IMAGE_FORMAT_XRGB8888;<br>
+   case 30:<br>
+      return __DRI_IMAGE_FORMAT_<wbr>XRGB2101010;<br>
+   case 32:<br>
+      return __DRI_IMAGE_FORMAT_ARGB8888;<br>
+   default:<br>
+      return __DRI_IMAGE_FORMAT_NONE;<br>
+   }<br>
+}<br>
+<br>
 static struct dri3_egl_surface *<br>
 loader_drawable_to_egl_<wbr>surface(struct loader_dri3_drawable *draw) {<br>
    size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);<br>
@@ -156,7 +173,9 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,<br>
<br>
    if (loader_dri3_drawable_init(<wbr>dri2_dpy->conn, drawable,<br>
                                  dri2_dpy->dri_screen,<br>
-                                 dri2_dpy->is_different_gpu, dri_config,<br>
+                                 dri2_dpy->is_different_gpu,<br>
+                                 dri2_dpy->multibuffers_<wbr>available,<br>
+                                 dri_config,<br>
                                  &dri2_dpy->loader_dri3_ext,<br>
                                  &egl_dri3_vtable,<br>
                                  &dri3_surf->loader_drawable)) {<br>
@@ -262,20 +281,8 @@ dri3_create_image_khr_pixmap(_<wbr>EGLDisplay *disp, _EGLContext *ctx,<br>
       return NULL;<br>
    }<br>
<br>
-   switch (bp_reply->depth) {<br>
-   case 16:<br>
-      format = __DRI_IMAGE_FORMAT_RGB565;<br>
-      break;<br>
-   case 24:<br>
-      format = __DRI_IMAGE_FORMAT_XRGB8888;<br>
-      break;<br>
-   case 30:<br>
-      format = __DRI_IMAGE_FORMAT_<wbr>XRGB2101010;<br>
-      break;<br>
-   case 32:<br>
-      format = __DRI_IMAGE_FORMAT_ARGB8888;<br>
-      break;<br>
-   default:<br>
+   format = dri3_format_for_depth(bp_<wbr>reply->depth);<br>
+   if (format == __DRI_IMAGE_FORMAT_NONE) {<br>
       _eglError(EGL_BAD_PARAMETER,<br>
                 "dri3_create_image_khr: unsupported pixmap depth");<br>
       free(bp_reply);<br>
@@ -302,13 +309,77 @@ dri3_create_image_khr_pixmap(_<wbr>EGLDisplay *disp, _EGLContext *ctx,<br>
    return &dri2_img->base;<br>
 }<br>
<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+static _EGLImage *<br>
+dri3_create_image_khr_pixmap_<wbr>from_buffers(_EGLDisplay *disp, _EGLContext *ctx,<br>
+                                          EGLClientBuffer buffer,<br>
+                                          const EGLint *attr_list)<br>
+{<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+   struct dri2_egl_image *dri2_img;<br>
+   xcb_dri3_buffers_from_pixmap_<wbr>cookie_t bp_cookie;<br>
+   xcb_dri3_buffers_from_pixmap_<wbr>reply_t  *bp_reply;<br>
+   xcb_drawable_t drawable;<br>
+   unsigned int format;<br>
+<br>
+   drawable = (xcb_drawable_t) (uintptr_t) buffer;<br>
+   bp_cookie = xcb_dri3_buffers_from_pixmap(<wbr>dri2_dpy->conn, drawable);<br>
+   bp_reply = xcb_dri3_buffers_from_pixmap_<wbr>reply(dri2_dpy->conn,<br>
+                                                 bp_cookie, NULL);<br>
+<br>
+   if (!bp_reply) {<br>
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");<br>
+      return EGL_NO_IMAGE_KHR;<br>
+   }<br>
+<br>
+   dri2_img = malloc(sizeof *dri2_img);<br>
+   if (!dri2_img) {<br></blockquote><div><br></div><div>You need to free bp_reply<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");<br>
+      return EGL_NO_IMAGE_KHR;<br>
+   }<br>
+<br>
+   format = dri3_format_for_depth(bp_<wbr>reply->depth);<br>
+   if (format == __DRI_IMAGE_FORMAT_NONE) {<br>
+      _eglError(EGL_BAD_PARAMETER,<br>
+                "dri3_create_image_khr: unsupported pixmap depth");<br>
+      free(bp_reply);<br></blockquote><div><br></div><div>You need to free dri2_img<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      return EGL_NO_IMAGE_KHR;<br>
+   }<br>
+<br>
+   _eglInitImage(&dri2_img->base, disp);<br>
+<br>
+   dri2_img->dri_image = loader_dri3_create_image_from_<wbr>buffers(dri2_dpy->conn,<br>
+                                                               bp_reply,<br>
+                                                               format,<br>
+                                                               dri2_dpy->dri_screen,<br>
+                                                               dri2_dpy->image,<br>
+                                                               dri2_img);<br>
+   free(bp_reply);<br>
+<br>
+   if (!dri2_img->dri_image) {<br>
+      _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");<br>
+      free(dri2_img);<br>
+      return EGL_NO_IMAGE_KHR;<br>
+   }<br>
+<br>
+   return &dri2_img->base;<br>
+}<br>
+#endif<br>
+<br>
 static _EGLImage *<br>
 dri3_create_image_khr(_<wbr>EGLDriver *drv, _EGLDisplay *disp,<br>
                       _EGLContext *ctx, EGLenum target,<br>
                       EGLClientBuffer buffer, const EGLint *attr_list)<br>
 {<br>
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+<br>
    switch (target) {<br>
    case EGL_NATIVE_PIXMAP_KHR:<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+      if (dri2_dpy->multibuffers_<wbr>available)<br>
+         return dri3_create_image_khr_pixmap_<wbr>from_buffers(disp, ctx, buffer,<br>
+                                                          attr_list);<br>
+#endif<br>
       return dri3_create_image_khr_pixmap(<wbr>disp, ctx, buffer, attr_list);<br>
    default:<br>
       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);<br>
@@ -470,6 +541,9 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)<br>
       free(error);<br>
       return EGL_FALSE;<br>
    }<br>
+<br>
+   dri2_dpy->dri3_major_version = dri3_query->major_version;<br>
+   dri2_dpy->dri3_minor_version = dri3_query->minor_version;<br>
    free(dri3_query);<br>
<br>
    present_query =<br>
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c<br>
index f280a8c..931912f 100644<br>
--- a/src/glx/dri3_glx.c<br>
+++ b/src/glx/dri3_glx.c<br>
@@ -346,7 +346,10 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,<br>
 {<br>
    struct dri3_drawable *pdraw;<br>
    struct dri3_screen *psc = (struct dri3_screen *) base;<br>
+   const struct dri3_display *const pdp = (struct dri3_display *)<br>
+      base->display->dri3Display;<br>
    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;<br>
+   bool has_multibuffer = false;<br>
<br>
    pdraw = calloc(1, sizeof(*pdraw));<br>
    if (!pdraw)<br>
@@ -357,11 +360,16 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,<br>
    pdraw->base.drawable = drawable;<br>
    pdraw->base.psc = &psc->base;<br>
<br>
+   if ((psc->image && psc->image->base.version >= 15) &&<br></blockquote><div><br></div><div>Should we check for some image functions as well?  In particular, createImageWithModifiers and queryDmaBufModifiers.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+       (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 1)))<br>
+      has_multibuffer = true;<br>
+<br>
    (void) __glXInitialize(psc->base.dpy)<wbr>;<br>
<br>
    if (loader_dri3_drawable_init(<wbr>XGetXCBConnection(base->dpy),<br>
                                  xDrawable, psc->driScreen,<br>
-                                 psc->is_different_gpu, config->driConfig,<br>
+                                 psc->is_different_gpu, has_multibuffer,<br>
+                                 config->driConfig,<br>
                                  &psc->loader_dri3_ext, &glx_dri3_vtable,<br>
                                  &pdraw->loader_drawable)) {<br>
       free(pdraw);<br>
diff --git a/src/loader/loader_dri3_<wbr>helper.c b/src/loader/loader_dri3_<wbr>helper.c<br>
index 2912bb6..80a4497 100644<br>
--- a/src/loader/loader_dri3_<wbr>helper.c<br>
+++ b/src/loader/loader_dri3_<wbr>helper.c<br>
@@ -24,6 +24,7 @@<br>
 #include <fcntl.h><br>
 #include <stdlib.h><br>
 #include <unistd.h><br>
+#include <string.h><br>
<br>
 #include <X11/xshmfence.h><br>
 #include <xcb/xcb.h><br>
@@ -40,6 +41,10 @@<br>
 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2<br>
 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3<br>
<br>
+#ifndef DRM_FORMAT_MOD_INVALID<br>
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)<br>
+#endif<br></blockquote><div><br></div><div>The copy of drm_fourcc.h we have in mesa has this now.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
 /**<br>
  * A cached blit context.<br>
  */<br>
@@ -256,6 +261,7 @@ loader_dri3_drawable_init(xcb_<wbr>connection_t *conn,<br>
                           xcb_drawable_t drawable,<br>
                           __DRIscreen *dri_screen,<br>
                           bool is_different_gpu,<br>
+                          bool multiplanes_available,<br>
                           const __DRIconfig *dri_config,<br>
                           struct loader_dri3_extensions *ext,<br>
                           const struct loader_dri3_vtable *vtable,<br>
@@ -273,6 +279,7 @@ loader_dri3_drawable_init(xcb_<wbr>connection_t *conn,<br>
    draw->drawable = drawable;<br>
    draw->dri_screen = dri_screen;<br>
    draw->is_different_gpu = is_different_gpu;<br>
+   draw->multiplanes_available = multiplanes_available;<br>
<br>
    draw->have_back = 0;<br>
    draw->have_fake_front = 0;<br>
@@ -1040,8 +1047,10 @@ dri3_alloc_render_buffer(<wbr>struct loader_dri3_drawable *draw, unsigned int format,<br>
    xcb_pixmap_t pixmap;<br>
    xcb_sync_fence_t sync_fence;<br>
    struct xshmfence *shm_fence;<br>
-   int buffer_fd, fence_fd;<br>
-   int stride;<br>
+   int buffer_fds[4], fence_fd;<br>
+   int num_planes = 0;<br>
+   int i, mod;<br>
+   int ret;<br>
<br>
    /* Create an xshmfence object and<br>
     * prepare to send that to the X server<br>
@@ -1066,13 +1075,80 @@ dri3_alloc_render_buffer(<wbr>struct loader_dri3_drawable *draw, unsigned int format,<br>
       goto no_image;<br>
<br>
    if (!draw->is_different_gpu) {<br>
-      buffer->image = draw->ext->image->createImage(<wbr>draw->dri_screen,<br>
-                                                    width, height,<br>
-                                                    format,<br>
-                                                    __DRI_IMAGE_USE_SHARE |<br>
-                                                    __DRI_IMAGE_USE_SCANOUT |<br>
-                                                    __DRI_IMAGE_USE_BACKBUFFER,<br>
-                                                    buffer);<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+      if (draw->multiplanes_available &&<br>
+          draw->ext->image->base.version >= 19 &&<br>
+          draw->ext->image-><wbr>queryDmaBufModifiers &&<br>
+          draw->ext->image-><wbr>createImageWithModifiers2) {<br></blockquote><div><br></div><div>Ok, I guess we do some extra checks here.  Maybe that's sufficient.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         xcb_dri3_get_supported_<wbr>modifiers_cookie_t mod_cookie;<br>
+         xcb_dri3_get_supported_<wbr>modifiers_reply_t *mod_reply;<br>
+         xcb_generic_error_t *error = NULL;<br>
+         uint64_t *modifiers[2] = {NULL, NULL};<br>
+         uint32_t counts[2] = {0, 0};<br>
+         uint32_t n = 0;<br>
+         int i;<br>
+<br>
+         mod_cookie = xcb_dri3_get_supported_<wbr>modifiers(draw->conn,<br>
+                                                       draw->drawable,<br>
+                                                       depth, buffer->cpp * 8);<br>
+         mod_reply = xcb_dri3_get_supported_<wbr>modifiers_reply(draw->conn,<br>
+                                                            mod_cookie,<br>
+                                                            &error);<br>
+         if (!mod_reply)<br>
+            goto no_image;<br>
+<br>
+         if (mod_reply->num_drawable_<wbr>modifiers) { </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+            counts[n] = mod_reply->num_drawable_<wbr>modifiers;<br>
+            modifiers[n] = malloc(counts[n] * sizeof(uint64_t));<br>
+            if (!modifiers[n]) {<br>
+               free(mod_reply);<br>
+               goto no_image;<br>
+            }<br>
+<br>
+            memcpy(modifiers[n],<br>
+                   xcb_dri3_get_supported_<wbr>modifiers_drawable_modifiers(<wbr>mod_reply),<br>
+                   counts[n] * sizeof(uint64_t));<br>
+            n++;<br>
+         }<br>
+<br>
+         if (mod_reply->num_screen_<wbr>modifiers) {<br>
+            counts[n] = mod_reply->num_screen_<wbr>modifiers;<br>
+            modifiers[n] = malloc(counts[n] * sizeof(uint64_t));<br>
+            if (!modifiers[n]) {<br>
+               free(modifiers[0]);<br></blockquote><div><br></div><div>The use of the modifiers array all the way through with the n counter is desceptively general.  Since you have free(modifiers[0]) here no one can just insert another modifiers list get in between even though it looks like they can.  I think it would be clearer if we just had separate drawable_modifiers and screen_modifiers variables and put them into an array right before the createImageWithModifiers. <br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+               free(mod_reply);<br>
+               goto no_image;<br>
+            }<br>
+<br>
+            memcpy(modifiers[n],<br>
+                   xcb_dri3_get_supported_<wbr>modifiers_screen_modifiers(<wbr>mod_reply),<br>
+                   counts[n] * sizeof(uint64_t));<br>
+            n++;<br>
+         }<br>
+<br>
+         free(mod_reply);<br>
+<br>
+         buffer->image = draw->ext->image-><wbr>createImageWithModifiers2(<wbr>draw->dri_screen,<br>
+                                                                     width, height,<br>
+                                                                     format,<br>
+                                                                     modifiers,<br>
+                                                                     counts,<br>
+                                                                     n,<br>
+                                                                     buffer);<br>
+         for (i = 0; i < n; i++)<br>
+            free(modifiers[i]);<br></blockquote><div><br></div><div>You don't relaly need the n here because free(NULL) is safe.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      }<br>
+#endif<br>
+<br>
+      if (!buffer->image)<br>
+         buffer->image = draw->ext->image->createImage(<wbr>draw->dri_screen,<br>
+                                                       width, height,<br>
+                                                       format,<br>
+                                                       __DRI_IMAGE_USE_SHARE |<br>
+                                                       __DRI_IMAGE_USE_SCANOUT |<br>
+                                                       __DRI_IMAGE_USE_BACKBUFFER,<br>
+                                                       buffer);<br>
+<br>
       pixmap_buffer = buffer->image;<br>
<br>
       if (!buffer->image)<br>
@@ -1100,25 +1176,72 @@ dri3_alloc_render_buffer(<wbr>struct loader_dri3_drawable *draw, unsigned int format,<br>
          goto no_linear_buffer;<br>
    }<br>
<br>
-   /* X wants the stride, so ask the image for it<br>
+   /* X want some information about the planes, so ask the image for it<br>
     */<br>
-   if (!draw->ext->image-><wbr>queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE,<br>
-                                     &stride))<br>
-      goto no_buffer_attrib;<br>
+   draw->ext->image->queryImage(<wbr>pixmap_buffer, __DRI_IMAGE_ATTRIB_NUM_PLANES,<br>
+                                &num_planes);<br>
+   if (num_planes <= 0)<br>
+      num_planes = 1;<br></blockquote><div><br></div><div>Do we want this based on num_planes <= 0 or the return value of queryImage?  I think either probably works.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
-   buffer->pitch = stride;<br>
+   for (i = 0; i < num_planes; i++) {<br>
+      __DRIimage *image = draw->ext->image->fromPlanar(<wbr>pixmap_buffer, i, NULL);<br>
<br>
-   if (!draw->ext->image-><wbr>queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD,<br>
-                                     &buffer_fd))<br>
-      goto no_buffer_attrib;<br>
+      if (!image) {<br>
+         assert(i == 0);<br>
+         image = pixmap_buffer;<br>
+      }<br>
+<br>
+      ret = draw->ext->image->queryImage(<wbr>image, __DRI_IMAGE_ATTRIB_FD,<br>
+                                         &buffer_fds[i]);<br>
+      ret &= draw->ext->image->queryImage(<wbr>image, __DRI_IMAGE_ATTRIB_STRIDE,<br>
+                                          &buffer->strides[i]);<br>
+      ret &= draw->ext->image->queryImage(<wbr>image, __DRI_IMAGE_ATTRIB_OFFSET,<br>
+                                          &buffer->offsets[i]);<br>
+      if (image != pixmap_buffer)<br>
+         draw->ext->image-><wbr>destroyImage(image);<br>
+<br>
+      if (!ret)<br>
+         goto no_buffer_attrib;<br>
+   }<br>
<br>
-   xcb_dri3_pixmap_from_buffer(<wbr>draw->conn,<br>
-                               (pixmap = xcb_generate_id(draw->conn)),<br>
-                               draw->drawable,<br>
-                               buffer->size,<br>
-                               width, height, buffer->pitch,<br>
-                               depth, buffer->cpp * 8,<br>
-                               buffer_fd);<br>
+   ret = draw->ext->image->queryImage(<wbr>pixmap_buffer,<br>
+                                     __DRI_IMAGE_ATTRIB_MODIFIER_<wbr>UPPER, &mod);<br>
+   buffer->modifier = (uint64_t) mod << 32;<br>
+   ret &= draw->ext->image->queryImage(<wbr>pixmap_buffer,<br>
+                                       __DRI_IMAGE_ATTRIB_MODIFIER_<wbr>LOWER, &mod);<br>
+   buffer->modifier |= (uint64_t)(mod & 0xffffffff);<br>
+<br>
+   if (!ret)<br>
+      buffer->modifier = DRM_FORMAT_MOD_INVALID;<br>
+<br>
+   pixmap = xcb_generate_id(draw->conn);<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+   if (draw->multiplanes_available &&<br>
+       buffer->modifier != DRM_FORMAT_MOD_INVALID) {<br>
+      xcb_dri3_pixmap_from_buffers(<wbr>draw->conn,<br>
+                                   pixmap,<br>
+                                   draw->drawable,<br>
+                                   num_planes,<br>
+                                   width, height,<br>
+                                   buffer->strides[0], buffer->offsets[0],<br>
+                                   buffer->strides[1], buffer->offsets[1],<br>
+                                   buffer->strides[2], buffer->offsets[2],<br>
+                                   buffer->strides[3], buffer->offsets[3],<br>
+                                   depth, buffer->cpp * 8,<br>
+                                   buffer->modifier,<br>
+                                   buffer_fds);<br>
+   }<br>
+   else<br>
+#endif<br></blockquote><div><br></div><div>This #define is gross.  I don't mind #ifs but when preprocessor and language control flow aren't properly nested, you're just asking for problems.  Perhaps the best thing to do would be to leave the entire if outside the #if and then do<br><br></div><div>#if ...<br></div><div>   xcb_dri3_pixmap_from_buffers(...);<br></div><div>#else<br></div><div>   unreachable("DRI3 v1.1 or greater is required for modifiers");<br></div><div>#endif<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   {<br>
+      xcb_dri3_pixmap_from_buffer(<wbr>draw->conn,<br>
+                                  pixmap,<br>
+                                  draw->drawable,<br>
+                                  buffer->size,<br>
+                                  width, height, buffer->strides[0],<br>
+                                  depth, buffer->cpp * 8,<br>
+                                  buffer_fds[0]);<br>
+   }<br>
<br>
    xcb_dri3_fence_from_fd(draw-><wbr>conn,<br>
                           pixmap,<br>
@@ -1140,6 +1263,9 @@ dri3_alloc_render_buffer(<wbr>struct loader_dri3_drawable *draw, unsigned int format,<br>
    return buffer;<br>
<br>
 no_buffer_attrib:<br>
+   do {<br>
+      close(buffer_fds[i]);<br>
+   } while (--i >= 0);<br></blockquote><div><br></div><div>You could also do<br><br></div><div>while (i >= 0)<br></div><div>   close(buffer_fds[i--]);<br><br></div><div>I don't know which is more readable.  Meh.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    draw->ext->image-><wbr>destroyImage(pixmap_b </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">uffer);<br>
 no_linear_buffer:<br>
    if (draw->is_different_gpu)<br>
@@ -1296,6 +1422,50 @@ loader_dri3_create_image(xcb_<wbr>connection_t *c,<br>
    return ret;<br>
 }<br>
<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+__DRIimage *<br>
+loader_dri3_create_image_<wbr>from_buffers(xcb_connection_t *c,<br>
+                                      xcb_dri3_buffers_from_pixmap_<wbr>reply_t *bp_reply,<br>
+                                      unsigned int format,<br>
+                                      __DRIscreen *dri_screen,<br>
+                                      const __DRIimageExtension *image,<br>
+                                      void *loaderPrivate)<br>
+{<br>
+   __DRIimage                           *ret;<br>
+   int                                  *fds;<br>
+   uint32_t                             *strides_in, *offsets_in;<br>
+   int                                   strides[4], offsets[4];<br>
+   unsigned                              error;<br>
+   int                                   i;<br>
+<br>
+   if (bp_reply->nfd > 4)<br>
+      return NULL;<br>
+<br>
+   fds = xcb_dri3_buffers_from_pixmap_<wbr>reply_fds(c, bp_reply);<br>
+   strides_in = xcb_dri3_buffers_from_pixmap_<wbr>strides(bp_reply);<br>
+   offsets_in = xcb_dri3_buffers_from_pixmap_<wbr>offsets(bp_reply);<br>
+   for (i = 0; i < bp_reply->nfd; i++) {<br>
+      strides[i] = strides_in[i];<br>
+      offsets[i] = offsets_in[i];<br>
+   }<br>
+<br>
+   ret = image-><wbr>createImageFromDmaBufs2(dri_<wbr>screen,<br>
+                                        bp_reply->width,<br>
+                                        bp_reply->height,<br>
+                                        image_format_to_fourcc(format)<wbr>,<br>
+                                        bp_reply->modifier,<br>
+                                        fds, bp_reply->nfd,<br>
+                                        strides, offsets,<br>
+                                        0, 0, 0, 0, /* UNDEFINED */<br>
+                                        &error, loaderPrivate);<br>
+<br>
+   for (i = 0; i < bp_reply->nfd; i++)<br>
+      close(fds[i]);<br>
+<br>
+   return ret;<br>
+}<br>
+#endif<br>
+<br>
 /** dri3_get_pixmap_buffer<br>
  *<br>
  * Get the DRM object for a pixmap from the X server and<br>
@@ -1309,10 +1479,10 @@ dri3_get_pixmap_buffer(__<wbr>DRIdrawable *driDrawable, unsigned int format,<br>
    int                                  buf_id = loader_dri3_pixmap_buf_id(<wbr>buffer_type);<br>
    struct loader_dri3_buffer            *buffer = draw->buffers[buf_id];<br>
    xcb_drawable_t                       pixmap;<br>
-   xcb_dri3_buffer_from_pixmap_<wbr>cookie_t bp_cookie;<br>
-   xcb_dri3_buffer_from_pixmap_<wbr>reply_t  *bp_reply;<br>
    xcb_sync_fence_t                     sync_fence;<br>
    struct xshmfence                     *shm_fence;<br>
+   int                                  width;<br>
+   int                                  height;<br>
    int                                  fence_fd;<br>
<br>
    if (buffer)<br>
@@ -1339,32 +1509,58 @@ dri3_get_pixmap_buffer(__<wbr>DRIdrawable *driDrawable, unsigned int format,<br>
                           false,<br>
                           fence_fd);<br>
<br>
-   bp_cookie = xcb_dri3_buffer_from_pixmap(<wbr>draw->conn, pixmap);<br>
-   bp_reply = xcb_dri3_buffer_from_pixmap_<wbr>reply(draw->conn, bp_cookie, NULL);<br>
-   if (!bp_reply)<br>
-      goto no_image;<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br></blockquote><div><br></div><div>Same comment about this #if.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   if (draw->multiplanes_available &&<br>
+       draw->ext->image->base.version >= 15 &&<br>
+       draw->ext->image-><wbr>createImageFromDmaBufs2) {<br>
+      xcb_dri3_buffers_from_pixmap_<wbr>cookie_t bps_cookie;<br>
+      xcb_dri3_buffers_from_pixmap_<wbr>reply_t *bps_reply;<br>
+<br>
+      bps_cookie = xcb_dri3_buffers_from_pixmap(<wbr>draw->conn, pixmap);<br>
+      bps_reply = xcb_dri3_buffers_from_pixmap_<wbr>reply(draw->conn, bps_cookie,<br>
+                                                     NULL);<br>
+      buffer->image =<br>
+         loader_dri3_create_image_from_<wbr>buffers(draw->conn, bps_reply, format,<br>
+                                               draw->dri_screen,<br>
+                                               draw->ext->image,<br>
+                                               buffer);<br>
+      width = bps_reply->width;<br>
+      height = bps_reply->height;<br>
+      free(bps_reply);<br>
+   } else<br>
+#endif<br>
+   {<br>
+      xcb_dri3_buffer_from_pixmap_<wbr>cookie_t bp_cookie;<br>
+      xcb_dri3_buffer_from_pixmap_<wbr>reply_t *bp_reply;<br>
+<br>
+      bp_cookie = xcb_dri3_buffer_from_pixmap(<wbr>draw->conn, pixmap);<br>
+      bp_reply = xcb_dri3_buffer_from_pixmap_<wbr>reply(draw->conn, bp_cookie, NULL);<br>
+      if (!bp_reply)<br>
+         goto no_image;<br>
+<br>
+      buffer->image = loader_dri3_create_image(draw-<wbr>>conn, bp_reply, format,<br>
+                                               draw->dri_screen,<br>
+                                               draw->ext->image, buffer);<br>
+      width = bp_reply->width;<br>
+      height = bp_reply->height;<br>
+      free(bp_reply);<br>
+   }<br>
<br>
-   buffer->image = loader_dri3_create_image(draw-<wbr>>conn, bp_reply, format,<br>
-                                            draw->dri_screen, draw->ext->image,<br>
-                                            buffer);<br>
    if (!buffer->image)<br>
       goto no_image;<br>
<br>
    buffer->pixmap = pixmap;<br>
    buffer->own_pixmap = false;<br>
-   buffer->width = bp_reply->width;<br>
-   buffer->height = bp_reply->height;<br>
+   buffer->width = width;<br>
+   buffer->height = height;<br>
    buffer->shm_fence = shm_fence;<br>
    buffer->sync_fence = sync_fence;<br>
<br>
    draw->buffers[buf_id] = buffer;<br>
<br>
-   free(bp_reply);<br>
-<br>
    return buffer;<br>
<br>
 no_image:<br>
-   free(bp_reply);<br>
    xcb_sync_destroy_fence(draw-><wbr>conn, sync_fence);<br>
    xshmfence_unmap_shm(shm_fence)<wbr>;<br>
 no_fence:<br>
diff --git a/src/loader/loader_dri3_<wbr>helper.h b/src/loader/loader_dri3_<wbr>helper.h<br>
index 4ce98b8..5689e27 100644<br>
--- a/src/loader/loader_dri3_<wbr>helper.h<br>
+++ b/src/loader/loader_dri3_<wbr>helper.h<br>
@@ -62,8 +62,11 @@ struct loader_dri3_buffer {<br>
    bool         busy;           /* Set on swap, cleared on IdleNotify */<br>
    bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy */<br>
<br>
+   uint32_t     num_planes;<br>
    uint32_t     size;<br>
-   uint32_t     pitch;<br>
+   int          strides[4];<br>
+   int          offsets[4];<br>
+   uint64_t     modifier;<br>
    uint32_t     cpp;<br>
    uint32_t     flags;<br>
    uint32_t     width, height;<br>
@@ -120,6 +123,7 @@ struct loader_dri3_drawable {<br>
    /* Information about the GPU owning the buffer */<br>
    __DRIscreen *dri_screen;<br>
    bool is_different_gpu;<br>
+   bool multiplanes_available;<br>
<br>
    /* Present extension capabilities<br>
     */<br>
@@ -179,6 +183,7 @@ loader_dri3_drawable_init(xcb_<wbr>connection_t *conn,<br>
                           xcb_drawable_t drawable,<br>
                           __DRIscreen *dri_screen,<br>
                           bool is_different_gpu,<br>
+                          bool is_multiplanes_available,<br>
                           const __DRIconfig *dri_config,<br>
                           struct loader_dri3_extensions *ext,<br>
                           const struct loader_dri3_vtable *vtable,<br>
@@ -236,6 +241,16 @@ loader_dri3_create_image(xcb_<wbr>connection_t *c,<br>
                          const __DRIimageExtension *image,<br>
                          void *loaderPrivate);<br>
<br>
+#if XCB_DRI3_MAJOR_VERSION > 1 || (XCB_DRI3_MAJOR_VERSION == 1 && XCB_DRI3_MINOR_VERSION >= 1)<br>
+__DRIimage *<br>
+loader_dri3_create_image_<wbr>from_buffers(xcb_connection_t *c,<br>
+                                      xcb_dri3_buffers_from_pixmap_<wbr>reply_t *bp_reply,<br>
+                                      unsigned int format,<br>
+                                      __DRIscreen *dri_screen,<br>
+                                      const __DRIimageExtension *image,<br>
+                                      void *loaderPrivate);<br>
+#endif<br>
+<br>
 int<br>
 loader_dri3_get_buffers(__<wbr>DRIdrawable *driDrawable,<br>
                         unsigned int format,<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.5.0.400.gff86faf<br>
<br>
</font></span></blockquote></div><br></div></div>