xserver: Branch 'master' - 12 commits

Adam Jackson ajax at kemper.freedesktop.org
Mon Mar 5 18:32:15 UTC 2018


 configure.ac                                     |   19 
 dri3/dri3.c                                      |   19 
 dri3/dri3.h                                      |   44 +
 dri3/dri3_priv.h                                 |   27 
 dri3/dri3_request.c                              |  294 ++++++-
 dri3/dri3_screen.c                               |  196 ++++
 glamor/Makefile.am                               |    1 
 glamor/glamor.c                                  |   62 +
 glamor/glamor.h                                  |   88 +-
 glamor/glamor_egl.c                              |  260 +++++-
 glamor/glamor_egl.h                              |    1 
 glamor/glamor_egl_ext.h                          |   65 +
 glamor/glamor_egl_stubs.c                        |   16 
 glamor/glamor_priv.h                             |    1 
 glamor/meson.build                               |    4 
 hw/kdrive/ephyr/meson.build                      |    1 
 hw/xfree86/common/xf86Mode.c                     |    1 
 hw/xfree86/drivers/modesetting/driver.c          |   18 
 hw/xfree86/drivers/modesetting/driver.h          |    1 
 hw/xfree86/drivers/modesetting/drmmode_display.c |  951 +++++++++++++++++++++--
 hw/xfree86/drivers/modesetting/drmmode_display.h |   80 +
 hw/xfree86/drivers/modesetting/pageflip.c        |   38 
 hw/xfree86/drivers/modesetting/present.c         |   33 
 hw/xwayland/.gitignore                           |    2 
 hw/xwayland/Makefile.am                          |   10 
 hw/xwayland/meson.build                          |    5 
 hw/xwayland/xwayland-glamor.c                    |  378 +++++++--
 hw/xwayland/xwayland.c                           |    6 
 hw/xwayland/xwayland.h                           |   19 
 include/dix-config.h.in                          |   12 
 include/meson.build                              |    8 
 include/protocol-versions.h                      |    4 
 meson.build                                      |    6 
 present/meson.build                              |    2 
 present/present.c                                |   88 +-
 present/present.h                                |   15 
 present/present_priv.h                           |    2 
 37 files changed, 2519 insertions(+), 258 deletions(-)

New commits:
commit ce8da936464cc78ec31de6e970e1353ffecf2547
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:46 2018 +0000

    dri3: Enable DRI3 version 1.2
    
    Enable DRI3 v1.2 now that all functions have been implemented and
    that there is at least one backend implementing the driver hooks
    (modesetting/glamor).
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 39cd2e909..7cab7cd5b 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -48,7 +48,7 @@
 
 /* DRI3 */
 #define SERVER_DRI3_MAJOR_VERSION               1
-#define SERVER_DRI3_MINOR_VERSION               0
+#define SERVER_DRI3_MINOR_VERSION               2
 
 /* DMX */
 #define SERVER_DMX_MAJOR_VERSION		2
commit 8d0d89715984e321315631dd6667e05813d26e03
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:45 2018 +0000

    glamor: Use gbm_bo_create_with_modifiers for internal pixmap allocation
    
    Using modifier might allow the driver to use a more optimal format
    (e.g. tiled/compressed). Let's try to use those if possible.
    
    v2: Don't filter out multi-plane modifiers
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index c00fb3c1b..ca368c15c 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -256,6 +256,7 @@ glamor_make_pixmap_exportable(PixmapPtr pixmap)
         glamor_get_pixmap_private(pixmap);
     unsigned width = pixmap->drawable.width;
     unsigned height = pixmap->drawable.height;
+    uint32_t format;
     struct gbm_bo *bo;
     PixmapPtr exported;
     GCPtr scratch_gc;
@@ -270,14 +271,33 @@ glamor_make_pixmap_exportable(PixmapPtr pixmap)
         return FALSE;
     }
 
-    bo = gbm_bo_create(glamor_egl->gbm, width, height,
-                       (pixmap->drawable.depth == 30) ?
-                       GBM_FORMAT_ARGB2101010 : GBM_FORMAT_ARGB8888,
+    if (pixmap->drawable.depth == 30)
+	format = GBM_FORMAT_ARGB2101010;
+    else
+        format = GBM_FORMAT_ARGB8888;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+    if (glamor_egl->dmabuf_capable) {
+        uint32_t num_modifiers;
+        uint64_t *modifiers = NULL;
+
+        glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
+
+        bo = gbm_bo_create_with_modifiers(glamor_egl->gbm, width, height,
+                                          format, modifiers, num_modifiers);
+        free(modifiers);
+    }
+    else
+#endif
+    {
+        bo = gbm_bo_create(glamor_egl->gbm, width, height, format,
 #ifdef GLAMOR_HAS_GBM_LINEAR
-                       (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
-                        GBM_BO_USE_LINEAR : 0) |
+                (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
+                 GBM_BO_USE_LINEAR : 0) |
 #endif
-                       GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
+                GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
+    }
+
     if (!bo) {
         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
                    "Failed to make %dx%dx%dbpp GBM bo\n",
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 72e2625fb..b961695d7 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -227,14 +227,30 @@ xwl_glamor_create_pixmap(ScreenPtr screen,
 {
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
     struct gbm_bo *bo;
+    uint32_t format;
 
     if (width > 0 && height > 0 && depth >= 15 &&
         (hint == 0 ||
          hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
          hint == CREATE_PIXMAP_USAGE_SHARED)) {
-        bo = gbm_bo_create(xwl_screen->gbm, width, height,
-                           gbm_format_for_depth(depth),
-                           GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+        format = gbm_format_for_depth(depth);
+
+#ifdef GBM_BO_WITH_MODIFIERS
+        if (xwl_screen->dmabuf_capable) {
+            uint32_t num_modifiers;
+            uint64_t *modifiers = NULL;
+
+            glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
+            bo = gbm_bo_create_with_modifiers(xwl_screen->gbm, width, height,
+                                              format, modifiers, num_modifiers);
+            free(modifiers);
+        }
+        else
+#endif
+        {
+            bo = gbm_bo_create(xwl_screen->gbm, width, height, format,
+                               GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+        }
 
         if (bo)
             return xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
commit cef12efc15ca1444d6d8cd839116b318a4668692
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:44 2018 +0000

    glamor: Implement GetSupportedModifiers
    
    Implement function added in DRI3 v1.1.
    
    A newest version of libepoxy (>= 1.4.4) is required as earlier
    versions use a problematic version of Khronos
    EXT_image_dma_buf_import_modifiers spec.
    
    v4: Only send scanout-supported modifiers if flipping is possible
    v5: Fix memory corruption in XWayland (uninitialized pointer)
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 773567b53..f82c0a66a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2087,6 +2087,10 @@ if test "x$GLAMOR" = xyes; then
 	AC_DEFINE(GLAMOR, 1, [Build glamor])
 	PKG_CHECK_MODULES([GLAMOR], [epoxy])
 
+	PKG_CHECK_EXISTS(epoxy >= 1.4.4,
+			 [AC_DEFINE(GLAMOR_HAS_EGL_QUERY_DMABUF, 1, [Have GLAMOR_HAS_EGL_QUERY_DMABUF])],
+			 [])
+
 	PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no])
 	if test "x$GBM" = xyes; then
 		AC_DEFINE(GLAMOR_HAS_GBM, 1,
diff --git a/glamor/glamor.c b/glamor/glamor.c
index c890d0ce0..c7077dd84 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -793,6 +793,31 @@ glamor_supports_pixmap_import_export(ScreenPtr screen)
     return glamor_priv->dri3_enabled;
 }
 
+_X_EXPORT void
+glamor_set_drawable_modifiers_func(ScreenPtr screen,
+                                   GetDrawableModifiersFuncPtr func)
+{
+    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+    glamor_priv->get_drawable_modifiers = func;
+}
+
+_X_EXPORT Bool
+glamor_get_drawable_modifiers(DrawablePtr draw, CARD32 format,
+                              CARD32 *num_modifiers, uint64_t **modifiers)
+{
+    struct glamor_screen_private *glamor_priv =
+        glamor_get_screen_private(draw->pScreen);
+
+    if (glamor_priv->get_drawable_modifiers) {
+        return glamor_priv->get_drawable_modifiers(draw, format,
+                                                   num_modifiers, modifiers);
+    }
+    *num_modifiers = 0;
+    *modifiers = NULL;
+    return TRUE;
+}
+
 _X_EXPORT int
 glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
                        uint32_t *strides, uint32_t *offsets,
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 8f8c31b45..5475aedbb 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -60,6 +60,11 @@ typedef enum glamor_pixmap_type {
     GLAMOR_TEXTURE_ONLY,
 } glamor_pixmap_type_t;
 
+typedef Bool (*GetDrawableModifiersFuncPtr) (DrawablePtr draw,
+                                             CARD32 format,
+                                             CARD32 *num_modifiers,
+                                             uint64_t **modifiers);
+
 #define GLAMOR_EGL_EXTERNAL_BUFFER 3
 #define GLAMOR_USE_EGL_SCREEN		(1 << 0)
 #define GLAMOR_NO_DRI3			(1 << 1)
@@ -272,6 +277,24 @@ extern _X_EXPORT Bool glamor_back_pixmap_from_fd(PixmapPtr pixmap,
                                                  CARD16 stride,
                                                  CARD8 depth,
                                                  CARD8 bpp);
+
+extern _X_EXPORT Bool glamor_get_formats(ScreenPtr screen,
+                                         CARD32 *num_formats,
+                                         CARD32 **formats);
+
+extern _X_EXPORT Bool glamor_get_modifiers(ScreenPtr screen,
+                                           CARD32 format,
+                                           CARD32 *num_modifiers,
+                                           uint64_t **modifiers);
+
+extern _X_EXPORT Bool glamor_get_drawable_modifiers(DrawablePtr draw,
+                                                    CARD32 format,
+                                                    CARD32 *num_modifiers,
+                                                    uint64_t **modifiers);
+
+extern _X_EXPORT void glamor_set_drawable_modifiers_func(ScreenPtr screen,
+                                                         GetDrawableModifiersFuncPtr func);
+
 #ifdef GLAMOR_FOR_XORG
 
 #define GLAMOR_EGL_MODULE_NAME  "glamoregl"
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index cf2513491..c00fb3c1b 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -505,6 +505,95 @@ glamor_pixmap_from_fds(ScreenPtr screen,
     return pixmap;
 }
 
+_X_EXPORT Bool
+glamor_get_formats(ScreenPtr screen,
+                   CARD32 *num_formats, CARD32 **formats)
+{
+#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLint num;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+    if (!glamor_egl->dmabuf_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    if (num == 0) {
+        *num_formats = 0;
+        return TRUE;
+    }
+
+    *formats = calloc(num, sizeof(CARD32));
+    if (*formats == NULL) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
+                                  (EGLint *) *formats, &num)) {
+        *num_formats = 0;
+        free(*formats);
+        return FALSE;
+    }
+
+    *num_formats = num;
+    return TRUE;
+#else
+    *num_formats = 0;
+    return TRUE;
+#endif
+}
+
+_X_EXPORT Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+                     CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
+    struct glamor_egl_screen_private *glamor_egl;
+    EGLint num;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+    if (!glamor_egl->dmabuf_capable)
+        return FALSE;
+
+    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
+                                    NULL, &num)) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    if (num == 0) {
+        *num_modifiers = 0;
+        return TRUE;
+    }
+
+    *modifiers = calloc(num, sizeof(uint64_t));
+    if (*modifiers == NULL) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
+                                    (EGLuint64KHR *) *modifiers, NULL, &num)) {
+        *num_modifiers = 0;
+        free(*modifiers);
+        return FALSE;
+    }
+
+    *num_modifiers = num;
+    return TRUE;
+#else
+    *num_modifiers = 0;
+    return TRUE;
+#endif
+}
+
 static Bool
 glamor_egl_destroy_pixmap(PixmapPtr pixmap)
 {
@@ -626,6 +715,9 @@ static dri3_screen_info_rec glamor_dri3_info = {
     .open_client = glamor_dri3_open_client,
     .pixmap_from_fds = glamor_pixmap_from_fds,
     .fds_from_pixmap = glamor_egl_fds_from_pixmap,
+    .get_formats = glamor_get_formats,
+    .get_modifiers = glamor_get_modifiers,
+    .get_drawable_modifiers = glamor_get_drawable_modifiers,
 };
 #endif /* DRI3 */
 
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index 2344066cb..3fff6396c 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -281,6 +281,7 @@ typedef struct glamor_screen_private {
     int radial_max_nstops;
 
     struct glamor_saved_procs saved_procs;
+    GetDrawableModifiersFuncPtr get_drawable_modifiers;
     int flags;
     ScreenPtr screen;
     int dri3_enabled;
diff --git a/glamor/meson.build b/glamor/meson.build
index 0b963275e..268af593e 100644
--- a/glamor/meson.build
+++ b/glamor/meson.build
@@ -38,12 +38,14 @@ if build_xv
     srcs_glamor += 'glamor_xv.c'
 endif
 
+epoxy_dep = dependency('epoxy')
+
 glamor = static_library('glamor',
     srcs_glamor,
     include_directories: inc,
     dependencies: [
         common_dep,
-        dependency('epoxy'),
+        epoxy_dep,
     ],
 )
 
diff --git a/hw/kdrive/ephyr/meson.build b/hw/kdrive/ephyr/meson.build
index 31e167387..b48afd612 100644
--- a/hw/kdrive/ephyr/meson.build
+++ b/hw/kdrive/ephyr/meson.build
@@ -30,6 +30,7 @@ if build_glamor
     xephyr_glamor += glamor
     xephyr_glamor += glamor_egl_stubs
     xephyr_dep += dependency('x11-xcb')
+    xephyr_dep += epoxy_dep
 endif
 
 if build_xv
diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c
index 40d09a9f4..484cde7ab 100644
--- a/hw/xfree86/common/xf86Mode.c
+++ b/hw/xfree86/common/xf86Mode.c
@@ -86,6 +86,7 @@
 
 #include <X11/X.h>
 #include "xf86Modes.h"
+#include "xf86Crtc.h"
 #include "os.h"
 #include "servermd.h"
 #include "globals.h"
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 88a42257c..f20284bb0 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1601,15 +1601,11 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv)
 
     fbPictureInit(pScreen, NULL, 0);
 
-#ifdef GLAMOR_HAS_GBM
-    if (ms->drmmode.glamor) {
-        if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
-            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                       "Failed to initialize glamor at ScreenInit() time.\n");
-            return FALSE;
-        }
+    if (drmmode_init(pScrn, &ms->drmmode) == FALSE) {
+        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                   "Failed to initialize glamor at ScreenInit() time.\n");
+        return FALSE;
     }
-#endif
 
     if (ms->drmmode.shadow_enable && !msShadowInit(pScreen)) {
         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "shadow fb init failed\n");
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 1f7a9fd0a..1027e637a 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -45,6 +45,7 @@
 #include <xf86drm.h>
 #include "xf86Crtc.h"
 #include "drmmode_display.h"
+#include "present.h"
 
 #include <cursorstr.h>
 
@@ -175,6 +176,24 @@ get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
     *modifiers = ret;
     return count_modifiers;
 }
+
+static Bool
+get_drawable_modifiers(DrawablePtr draw, uint32_t format,
+                       uint32_t *num_modifiers, uint64_t **modifiers)
+{
+    ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
+    modesettingPtr ms = modesettingPTR(scrn);
+
+    if (!present_can_window_flip((WindowPtr) draw) ||
+        !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
+        *num_modifiers = 0;
+        *modifiers = NULL;
+        return TRUE;
+    }
+
+    *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
+    return TRUE;
+}
 #endif
 
 static Bool
@@ -3121,6 +3140,25 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
     return TRUE;
 }
 
+Bool
+drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
+{
+#ifdef GLAMOR_HAS_GBM
+    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
+
+    if (drmmode->glamor) {
+        if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
+            return FALSE;
+        }
+#ifdef GBM_BO_WITH_MODIFIERS
+        glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
+#endif
+    }
+#endif
+
+    return TRUE;
+}
+
 void
 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
 {
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 607fe8179..ee59711cb 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -263,6 +263,7 @@ Bool drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
 void drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode);
 
 extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp);
+extern Bool drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y);
 extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw);
 extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 774a18893..72e2625fb 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -407,19 +407,6 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
 static void
 xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
 {
-   struct xwl_screen *xwl_screen = data;
-
-   switch (format) {
-   case WL_DRM_FORMAT_ARGB8888:
-      xwl_screen->formats |= XWL_FORMAT_ARGB8888;
-      break;
-   case WL_DRM_FORMAT_XRGB8888:
-      xwl_screen->formats |= XWL_FORMAT_XRGB8888;
-      break;
-   case WL_DRM_FORMAT_RGB565:
-      xwl_screen->formats |= XWL_FORMAT_RGB565;
-      break;
-   }
 }
 
 static void
@@ -446,6 +433,54 @@ static const struct wl_drm_listener xwl_drm_listener = {
     xwl_drm_handle_capabilities
 };
 
+static void
+xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                         uint32_t format)
+{
+}
+
+static void
+xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                           uint32_t format, uint32_t modifier_hi,
+                           uint32_t modifier_lo)
+{
+   struct xwl_screen *xwl_screen = data;
+    struct xwl_format *xwl_format = NULL;
+    int i;
+
+    for (i = 0; i < xwl_screen->num_formats; i++) {
+        if (xwl_screen->formats[i].format == format) {
+            xwl_format = &xwl_screen->formats[i];
+            break;
+        }
+    }
+
+    if (xwl_format == NULL) {
+       xwl_screen->num_formats++;
+       xwl_screen->formats = realloc(xwl_screen->formats,
+                                     xwl_screen->num_formats * sizeof(*xwl_format));
+       if (!xwl_screen->formats)
+          return;
+       xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
+       xwl_format->format = format;
+       xwl_format->num_modifiers = 0;
+       xwl_format->modifiers = NULL;
+    }
+
+    xwl_format->num_modifiers++;
+    xwl_format->modifiers = realloc(xwl_format->modifiers,
+                                    xwl_format->num_modifiers * sizeof(uint64_t));
+    if (!xwl_format->modifiers)
+       return;
+    xwl_format->modifiers[xwl_format->num_modifiers - 1]  = (uint64_t) modifier_lo;
+    xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
+}
+
+static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
+    .format   = xwl_dmabuf_handle_format,
+    .modifier = xwl_dmabuf_handle_modifier
+};
+
 Bool
 xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
                              uint32_t id, uint32_t version)
@@ -470,6 +505,7 @@ xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
 
     xwl_screen->dmabuf =
         wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+    zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);
 
     return TRUE;
 }
@@ -678,12 +714,85 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
 #endif
 }
 
+_X_EXPORT Bool
+glamor_get_formats(ScreenPtr screen,
+                   CARD32 *num_formats, CARD32 **formats)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    int i;
+
+    if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
+        return FALSE;
+
+    if (xwl_screen->num_formats == 0) {
+       *num_formats = 0;
+       return TRUE;
+    }
+
+    *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
+    if (*formats == NULL) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    for (i = 0; i < xwl_screen->num_formats; i++)
+       (*formats)[i] = xwl_screen->formats[i].format;
+    *num_formats = xwl_screen->num_formats;
+
+    return TRUE;
+}
+
+_X_EXPORT Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+                     CARD32 *num_modifiers, uint64_t **modifiers)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_format *xwl_format = NULL;
+    int i;
+
+    if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
+        return FALSE;
+
+    if (xwl_screen->num_formats == 0) {
+       *num_modifiers = 0;
+       return TRUE;
+    }
+
+    for (i = 0; i < xwl_screen->num_formats; i++) {
+       if (xwl_screen->formats[i].format == format) {
+          xwl_format = &xwl_screen->formats[i];
+          break;
+       }
+    }
+
+    if (!xwl_format) {
+	*num_modifiers = 0;
+        return FALSE;
+    }
+
+    *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
+    if (*modifiers == NULL) {
+        *num_modifiers = 0;
+        return FALSE;
+    }
+
+    for (i = 0; i < xwl_format->num_modifiers; i++)
+       (*modifiers)[i] = xwl_format->modifiers[i];
+    *num_modifiers = xwl_format->num_modifiers;
+
+    return TRUE;
+}
+
+
 static dri3_screen_info_rec xwl_dri3_info = {
     .version = 2,
     .open = NULL,
     .pixmap_from_fds = glamor_pixmap_from_fds,
     .fds_from_pixmap = glamor_fds_from_pixmap,
     .open_client = xwl_dri3_open_client,
+    .get_formats = glamor_get_formats,
+    .get_modifiers = glamor_get_modifiers,
+    .get_drawable_modifiers = glamor_get_drawable_modifiers,
 };
 
 Bool
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index be95bab55..36ebeaa83 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -49,6 +49,12 @@
 #include "xdg-output-unstable-v1-client-protocol.h"
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 
+struct xwl_format {
+    uint32_t format;
+    int num_modifiers;
+    uint64_t *modifiers;
+};
+
 struct xwl_screen {
     int width;
     int height;
@@ -100,7 +106,8 @@ struct xwl_screen {
     int drm_authenticated;
     struct wl_drm *drm;
     struct zwp_linux_dmabuf_v1 *dmabuf;
-    uint32_t formats;
+    uint32_t num_formats;
+    struct xwl_format *formats;
     uint32_t capabilities;
     void *egl_display, *egl_context;
     struct gbm_device *gbm;
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index ea932c46d..58585724c 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -500,6 +500,9 @@
 /* Glamor can retrieve supported DRM formats/modifiers */
 #undef GLAMOR_HAS_DRM_MODIFIERS
 
+/* Glamor can use eglQueryDmaBuf* functions */
+#undef GLAMOR_HAS_EGL_QUERY_DMABUF
+
 /* byte order */
 #undef X_BYTE_ORDER
 
diff --git a/include/meson.build b/include/meson.build
index c39c00420..e6abf22f8 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -79,6 +79,8 @@ conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
               libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
 conf_data.set('GLAMOR_HAS_DRM_MODIFIERS',
               libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.83'))
+conf_data.set('GLAMOR_HAS_EGL_QUERY_DMABUF',
+              epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.4.4'))
 conf_data.set('GLXEXT', build_glx)
 conf_data.set('GLAMOR', build_glamor)
 conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
diff --git a/meson.build b/meson.build
index d64fb0ca3..3579d078a 100644
--- a/meson.build
+++ b/meson.build
@@ -262,9 +262,11 @@ else
     build_glamor = get_option('glamor') == 'true'
 endif
 
-gbm_dep = dependency('', required:false)
+gbm_dep = dependency('', required: false)
+epoxy_dep = dependency('', required: false)
 if build_glamor
     gbm_dep = dependency('gbm', version: '>= 10.2', required: false)
+    epoxy_dep = dependency('epoxy', required: false)
 endif
 
 # XXX: Add more sha1 options, because Linux is about choice
diff --git a/present/present.c b/present/present.c
index 42e5fb4fc..080cafcba 100644
--- a/present/present.c
+++ b/present/present.c
@@ -614,6 +614,44 @@ present_check_flip_window (WindowPtr window)
     }
 }
 
+Bool
+present_can_window_flip(WindowPtr window)
+{
+    ScreenPtr                   screen = window->drawable.pScreen;
+    PixmapPtr                   window_pixmap;
+    WindowPtr                   root = screen->root;
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+
+    if (!screen_priv)
+        return FALSE;
+
+    if (!screen_priv->info)
+        return FALSE;
+
+    /* Check to see if the driver supports flips at all */
+    if (!screen_priv->info->flip)
+        return FALSE;
+
+    /* Make sure the window hasn't been redirected with Composite */
+    window_pixmap = screen->GetWindowPixmap(window);
+    if (window_pixmap != screen->GetScreenPixmap(screen) &&
+        window_pixmap != screen_priv->flip_pixmap &&
+        window_pixmap != present_flip_pending_pixmap(screen))
+        return FALSE;
+
+    /* Check for full-screen window */
+    if (!RegionEqual(&window->clipList, &root->winSize)) {
+        return FALSE;
+    }
+
+    /* Does the window match the pixmap exactly? */
+    if (window->drawable.x != 0 || window->drawable.y != 0) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 /*
  * Called when the wait fence is triggered; just gets the current msc/ust and
  * calls present_execute again. That will re-check the fence and pend the
diff --git a/present/present.h b/present/present.h
index 6542dc385..ade838bda 100644
--- a/present/present.h
+++ b/present/present.h
@@ -135,4 +135,7 @@ typedef void (*present_complete_notify_proc)(WindowPtr window,
 extern _X_EXPORT void
 present_register_complete_notify(present_complete_notify_proc proc);
 
+extern _X_EXPORT Bool
+present_can_window_flip(WindowPtr window);
+
 #endif /* _PRESENT_H_ */
commit c8c276c9569b3ca1e695682a5443f1b615c606bd
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:43 2018 +0000

    glamor: Implement PixmapFromBuffers and BuffersFromPixmap
    
    It relies on GBM >= 17.1.0 where we can import BO with multiple
    planes and a format modifier (GBM_BO_IMPORT_FD_MODIFIER).
    
    v2: Properly free fds in Xwayland
    
    [Also add glamor_egl_ext.h to Makefile.am for distcheck's sake - ajax]
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index f4534e30b..773567b53 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2095,6 +2095,10 @@ if test "x$GLAMOR" = xyes; then
 			[AC_DEFINE(GLAMOR_HAS_GBM_LINEAR, 1, [Have GBM_BO_USE_LINEAR])], [],
 			[#include <stdlib.h>
 			 #include <gbm.h>])
+		dnl 17.1.0 is required for gbm_bo_create_with_modifiers
+		PKG_CHECK_EXISTS(gbm >= 17.1.0,
+				 [AC_DEFINE(GBM_BO_WITH_MODIFIERS, 1, [Have gbm_bo_create_with_modifiers])],
+				 [])
 	else
 		if test "x$XORG" = xyes; then
 			AC_MSG_ERROR([Glamor for Xorg requires $LIBGBM])
diff --git a/glamor/Makefile.am b/glamor/Makefile.am
index 8c79994e0..aaf0aab17 100644
--- a/glamor/Makefile.am
+++ b/glamor/Makefile.am
@@ -56,6 +56,7 @@ endif
 
 libglamor_egl_stubs_la_SOURCES = \
 	glamor_egl_stubs.c \
+	glamor_egl_ext.h \
 	glamor_egl.h
 
 sdk_HEADERS = glamor.h
diff --git a/glamor/glamor.c b/glamor/glamor.c
index d61e27563..c890d0ce0 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -32,6 +32,7 @@
  */
 
 #include <stdlib.h>
+#include <unistd.h>
 
 #include "glamor_priv.h"
 #include "mipict.h"
@@ -793,8 +794,9 @@ glamor_supports_pixmap_import_export(ScreenPtr screen)
 }
 
 _X_EXPORT int
-glamor_fd_from_pixmap(ScreenPtr screen,
-                      PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+                       uint32_t *strides, uint32_t *offsets,
+                       uint64_t *modifier)
 {
     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
     glamor_screen_private *glamor_priv =
@@ -808,10 +810,9 @@ glamor_fd_from_pixmap(ScreenPtr screen,
         if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
                                       GL_RGB10_A2 : GL_RGBA, 0))
             return -1;
-        return glamor_egl_dri3_fd_name_from_tex(screen,
-                                                pixmap,
-                                                pixmap_priv->fbo->tex,
-                                                FALSE, stride, size);
+        return glamor_egl_fds_from_pixmap(screen, pixmap, fds,
+                                          strides, offsets,
+                                          modifier);
     default:
         break;
     }
@@ -824,6 +825,9 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen,
 {
     unsigned orig_usage_hint = pixmap->usage_hint;
     int ret;
+    int fds[4];
+    uint32_t strides[4], offsets[4];
+    uint64_t modifier;
 
     /*
      * The actual difference between a sharable and non sharable buffer
@@ -832,7 +836,20 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen,
      * 2 of those calls are also exported API, so we cannot just add a flag.
      */
     pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED;
-    ret = glamor_fd_from_pixmap(screen, pixmap, stride, size);
+    ret = glamor_fds_from_pixmap(screen, pixmap, fds, strides, offsets,
+                                 &modifier);
+
+    /* Pixmaps with multi-planes/modifier are not shareable */
+    if (ret > 1) {
+        while (ret > 0)
+            close(fds[--ret]);
+        return -1;
+    }
+
+    ret = fds[0];
+    *stride = strides[0];
+    *size = pixmap->drawable.height * *stride;
+
     pixmap->usage_hint = orig_usage_hint;
 
     return ret;
@@ -849,10 +866,8 @@ glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
         if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
                                       GL_RGB10_A2 : GL_RGBA, 0))
             return -1;
-        return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen,
-                                                pixmap,
-                                                pixmap_priv->fbo->tex,
-                                                TRUE, stride, size);
+        return glamor_egl_fd_name_from_pixmap(pixmap->drawable.pScreen,
+                                              pixmap, stride, size);
     default:
         break;
     }
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 5b15a46e5..8f8c31b45 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -138,15 +138,17 @@ extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front,
 
 /* The DDX is not supposed to call these three functions */
 extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen);
-extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr,
-                                                      unsigned int, Bool,
-                                                      CARD16 *, CARD32 *);
+extern _X_EXPORT int glamor_egl_fds_from_pixmap(ScreenPtr, PixmapPtr, int *,
+                                                uint32_t *, uint32_t *,
+                                                uint64_t *);
+extern _X_EXPORT int glamor_egl_fd_name_from_pixmap(ScreenPtr, PixmapPtr,
+                                                    CARD16 *, CARD32 *);
 
 extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen);
 
 /* @glamor_supports_pixmap_import_export: Returns whether
- * glamor_fd_from_pixmap(), glamor_name_from_pixmap(), and
- * glamor_pixmap_from_fd() are supported.
+ * glamor_fds_from_pixmap(), glamor_name_from_pixmap(), and
+ * glamor_pixmap_from_fds() are supported.
  *
  * @screen: Current screen pointer.
  *
@@ -159,20 +161,22 @@ extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen);
  * */
 extern _X_EXPORT Bool glamor_supports_pixmap_import_export(ScreenPtr screen);
 
-/* @glamor_fd_from_pixmap: Get a dma-buf fd from a pixmap.
+/* @glamor_fds_from_pixmap: Get a dma-buf fd from a pixmap.
  *
  * @screen: Current screen pointer.
  * @pixmap: The pixmap from which we want the fd.
- * @stride, @size: Pointers to fill the stride and size of the
- * 		   buffer associated to the fd.
+ * @fds, @strides, @offsets: Pointers to fill info of each plane.
+ * @modifier: Pointer to fill the modifier of the buffer.
  *
- * the pixmap and the buffer associated by the fd will share the same
- * content.
- * Returns the fd on success, -1 on error.
+ * the pixmap and the buffer associated by the fds will share the same
+ * content. The caller is responsible to close the returned file descriptors.
+ * Returns the number of planes, -1 on error.
  * */
-extern _X_EXPORT int glamor_fd_from_pixmap(ScreenPtr screen,
-                                           PixmapPtr pixmap,
-                                           CARD16 *stride, CARD32 *size);
+extern _X_EXPORT int glamor_fds_from_pixmap(ScreenPtr screen,
+                                            PixmapPtr pixmap,
+                                            int *fds,
+                                            uint32_t *strides, uint32_t *offsets,
+                                            uint64_t *modifier);
 
 /* @glamor_shareable_fd_from_pixmap: Get a dma-buf fd suitable for sharing
  *				     with other GPUs from a pixmap.
@@ -224,25 +228,30 @@ extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap,
 extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen,
                                                           PixmapPtr pixmap);
 
-/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd.
+/* @glamor_pixmap_from_fds: Creates a pixmap to wrap a dma-buf fds.
  *
  * @screen: Current screen pointer.
- * @fd: The dma-buf fd to import.
- * @width: The width of the buffer.
- * @height: The height of the buffer.
- * @stride: The stride of the buffer.
- * @depth: The depth of the buffer.
- * @bpp: The number of bpp of the buffer.
+ * @num_fds: Number of fds to import
+ * @fds: The dma-buf fds to import.
+ * @width: The width of the buffers.
+ * @height: The height of the buffers.
+ * @stride: The stride of the buffers.
+ * @depth: The depth of the buffers.
+ * @bpp: The bpp of the buffers.
+ * @modifier: The modifier of the buffers.
  *
  * Returns a valid pixmap if the import succeeded, else NULL.
  * */
-extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen,
-                                                 int fd,
-                                                 CARD16 width,
-                                                 CARD16 height,
-                                                 CARD16 stride,
-                                                 CARD8 depth,
-                                                 CARD8 bpp);
+extern _X_EXPORT PixmapPtr glamor_pixmap_from_fds(ScreenPtr screen,
+                                                  CARD8 num_fds,
+                                                  int *fds,
+                                                  CARD16 width,
+                                                  CARD16 height,
+                                                  CARD32 *strides,
+                                                  CARD32 *offsets,
+                                                  CARD8 depth,
+                                                  CARD8 bpp,
+                                                  uint64_t modifier);
 
 /* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd.
  *
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index eb5e68b8e..cf2513491 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -56,6 +56,7 @@ struct glamor_egl_screen_private {
     CloseScreenProcPtr CloseScreen;
     int fd;
     struct gbm_device *gbm;
+    int dmabuf_capable;
 
     CloseScreenProcPtr saved_close_screen;
     DestroyPixmapProcPtr saved_destroy_pixmap;
@@ -330,10 +331,51 @@ glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
 }
 
 int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
-                                 PixmapPtr pixmap,
-                                 unsigned int tex,
-                                 Bool want_name, CARD16 *stride, CARD32 *size)
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+                           uint32_t *strides, uint32_t *offsets,
+                           uint64_t *modifier)
+{
+#ifdef GLAMOR_HAS_GBM
+    struct gbm_bo *bo;
+    int num_fds;
+#ifdef GBM_BO_WITH_MODIFIERS
+    int i;
+#endif
+
+    if (!glamor_make_pixmap_exportable(pixmap))
+        return 0;
+
+    bo = glamor_gbm_bo_from_pixmap(screen, pixmap);
+    if (!bo)
+        return 0;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+    num_fds = gbm_bo_get_plane_count(bo);
+    for (i = 0; i < num_fds; i++) {
+        fds[i] = gbm_bo_get_fd(bo);
+        strides[i] = gbm_bo_get_stride_for_plane(bo, i);
+        offsets[i] = gbm_bo_get_offset(bo, i);
+    }
+    *modifier = gbm_bo_get_modifier(bo);
+#else
+    num_fds = 1;
+    fds[0] = gbm_bo_get_fd(bo);
+    strides[0] = gbm_bo_get_stride(bo);
+    offsets[0] = 0;
+    *modifier = DRM_FORMAT_MOD_INVALID;
+#endif
+
+    gbm_bo_destroy(bo);
+    return num_fds;
+#else
+    return 0;
+#endif
+}
+
+int
+glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
+                               PixmapPtr pixmap,
+                               CARD16 *stride, CARD32 *size)
 {
     struct glamor_egl_screen_private *glamor_egl;
     struct gbm_bo *bo;
@@ -347,12 +389,7 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
 
     pixmap->devKind = gbm_bo_get_stride(bo);
 
-    if (want_name) {
-        glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
-    }
-    else {
-        fd = gbm_bo_get_fd(bo);
-    }
+    glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
     *stride = pixmap->devKind;
     *size = pixmap->devKind * gbm_bo_get_height(bo);
 
@@ -399,19 +436,68 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap,
     return ret;
 }
 
+static uint32_t
+gbm_format_for_depth(CARD8 depth)
+{
+    switch (depth) {
+    case 16:
+        return GBM_FORMAT_RGB565;
+    case 24:
+        return GBM_FORMAT_XRGB8888;
+    default:
+        ErrorF("unexpected depth: %d\n", depth);
+    case 32:
+        return GBM_FORMAT_ARGB8888;
+    }
+}
+
 _X_EXPORT PixmapPtr
-glamor_pixmap_from_fd(ScreenPtr screen,
-                      int fd,
-                      CARD16 width,
-                      CARD16 height,
-                      CARD16 stride, CARD8 depth, CARD8 bpp)
+glamor_pixmap_from_fds(ScreenPtr screen,
+                       CARD8 num_fds, int *fds,
+                       CARD16 width, CARD16 height,
+                       CARD32 *strides, CARD32 *offsets,
+                       CARD8 depth, CARD8 bpp,
+                       uint64_t modifier)
 {
     PixmapPtr pixmap;
-    Bool ret;
+    struct glamor_egl_screen_private *glamor_egl;
+    Bool ret = FALSE;
+    int i;
+
+    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
 
     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
-    ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
-                                     stride, depth, bpp);
+
+#ifdef GBM_BO_WITH_MODIFIERS
+    if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
+        struct gbm_import_fd_modifier_data import_data = { 0 };
+        struct gbm_bo *bo;
+
+        import_data.width = width;
+        import_data.height = height;
+        import_data.num_fds = num_fds;
+        import_data.modifier = modifier;
+        for (i = 0; i < num_fds; i++) {
+            import_data.fds[i] = fds[i];
+            import_data.strides[i] = strides[i];
+            import_data.offsets[i] = offsets[i];
+        }
+        import_data.format = gbm_format_for_depth(depth);
+        bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0);
+        if (bo) {
+            screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);
+            ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
+            gbm_bo_destroy(bo);
+        }
+    } else
+#endif
+    {
+        if (num_fds == 1) {
+            ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
+                                             strides[0], depth, bpp);
+        }
+    }
+
     if (ret == FALSE) {
         screen->DestroyPixmap(pixmap);
         return NULL;
@@ -536,10 +622,10 @@ glamor_dri3_open_client(ClientPtr client,
 }
 
 static dri3_screen_info_rec glamor_dri3_info = {
-    .version = 1,
+    .version = 2,
     .open_client = glamor_dri3_open_client,
-    .pixmap_from_fd = glamor_pixmap_from_fd,
-    .fd_from_pixmap = glamor_fd_from_pixmap,
+    .pixmap_from_fds = glamor_pixmap_from_fds,
+    .fds_from_pixmap = glamor_egl_fds_from_pixmap,
 };
 #endif /* DRI3 */
 
@@ -737,6 +823,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
     xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
                glGetString(GL_RENDERER));
 
+#ifdef GBM_BO_WITH_MODIFIERS
+    if (epoxy_has_egl_extension(glamor_egl->display,
+                                "EGL_EXT_image_dma_buf_import") &&
+        epoxy_has_egl_extension(glamor_egl->display,
+                                "EGL_EXT_image_dma_buf_import_modifiers"))
+        glamor_egl->dmabuf_capable = TRUE;
+#endif
+
     glamor_egl->saved_free_screen = scrn->FreeScreen;
     scrn->FreeScreen = glamor_egl_free_screen;
     return TRUE;
diff --git a/glamor/glamor_egl.h b/glamor/glamor_egl.h
index 6bb1185bf..2f7566b24 100644
--- a/glamor/glamor_egl.h
+++ b/glamor/glamor_egl.h
@@ -30,6 +30,7 @@
 #define MESA_EGL_NO_X11_HEADERS
 #include <epoxy/gl.h>
 #include <epoxy/egl.h>
+#include <glamor_egl_ext.h>
 
 /*
  * Create an EGLDisplay from a native display type. This is a little quirky
diff --git a/glamor/glamor_egl_ext.h b/glamor/glamor_egl_ext.h
new file mode 100644
index 000000000..436e52137
--- /dev/null
+++ b/glamor/glamor_egl_ext.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Extensions used by Glamor, copied from Mesa's eglmesaext.h, */
+
+#ifndef GLAMOR_EGL_EXT_H
+#define GLAMOR_EGL_EXT_H
+
+/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
+ * here to avoid having to add ifdefs everywhere.*/
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_LINUX_DMA_BUF_EXT					0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT				0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT				0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT				0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT				0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT				0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT				0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT				0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT				0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT				0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT				0x327A
+#endif
+
+/* Define tokens from EGL_EXT_image_dma_buf_import_modifiers */
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_EXT_image_dma_buf_import_modifiers 1
+#define EGL_DMA_BUF_PLANE3_FD_EXT         0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT     0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT      0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#endif
+
+#endif /* GLAMOR_EGL_EXT_H */
diff --git a/glamor/glamor_egl_stubs.c b/glamor/glamor_egl_stubs.c
index 40f7fcc01..aae909e9f 100644
--- a/glamor/glamor_egl_stubs.c
+++ b/glamor/glamor_egl_stubs.c
@@ -36,10 +36,18 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
 }
 
 int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
-                                 PixmapPtr pixmap,
-                                 unsigned int tex,
-                                 Bool want_name, CARD16 *stride, CARD32 *size)
+glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
+                               PixmapPtr pixmap,
+                               CARD16 *stride, CARD32 *size)
+{
+    return -1;
+}
+
+
+int
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+                           uint32_t *offsets, uint32_t *strides,
+                           uint64_t *modifier)
 {
     return 0;
 }
diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index 38ada56d1..c0320b555 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -5,3 +5,5 @@ pointer-constraints-unstable-v1-client-protocol.h
 pointer-constraints-unstable-v1-protocol.c
 relative-pointer-unstable-v1-client-protocol.h
 relative-pointer-unstable-v1-protocol.c
+linux-dmabuf-unstable-v1-client-protocol.h
+linux-dmabuf-unstable-v1-protocol.c
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 173686e31..f44a7ded3 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -62,8 +62,9 @@ Xwayland_built_sources +=					\
 	xwayland-keyboard-grab-unstable-v1-protocol.c		\
 	xwayland-keyboard-grab-unstable-v1-client-protocol.h	\
 	xdg-output-unstable-v1-protocol.c			\
-	xdg-output-unstable-v1-client-protocol.h
-
+	xdg-output-unstable-v1-client-protocol.h		\
+	linux-dmabuf-unstable-v1-client-protocol.h		\
+	linux-dmabuf-unstable-v1-protocol.c
 
 nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
 CLEANFILES = $(Xwayland_built_sources)
@@ -100,6 +101,11 @@ xdg-output-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-ou
 xdg-output-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 
+linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 %-protocol.c : %.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index f6f75001c..7e24c5d63 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -12,7 +12,7 @@ srcs = [
 scanner_dep = dependency('wayland-scanner', native: true)
 scanner = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner'))
 
-protocols_dep = dependency('wayland-protocols')
+protocols_dep = dependency('wayland-protocols', version: '>= 1.8')
 protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir')
 
 pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml')
@@ -20,6 +20,7 @@ relative_xml = join_paths(protodir, 'unstable', 'relative-pointer', 'relative-po
 tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml')
 kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml')
 xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml')
+dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
 
 client_header = generator(scanner,
     output : '@BASENAME at -client-protocol.h',
@@ -34,11 +35,13 @@ srcs += client_header.process(pointer_xml)
 srcs += client_header.process(tablet_xml)
 srcs += client_header.process(kbgrab_xml)
 srcs += client_header.process(xdg_output_xml)
+srcs += client_header.process(dmabuf_xml)
 srcs += code.process(relative_xml)
 srcs += code.process(pointer_xml)
 srcs += code.process(tablet_xml)
 srcs += code.process(kbgrab_xml)
 srcs += code.process(xdg_output_xml)
+srcs += code.process(dmabuf_xml)
 
 xwayland_glamor = []
 if gbm_dep.found()
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 0933e9411..774a18893 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -28,6 +28,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <xf86drm.h>
+#include <drm_fourcc.h>
 
 #define MESA_EGL_NO_X11_HEADERS
 #include <gbm.h>
@@ -158,25 +159,65 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
     struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
     int prime_fd;
+    int num_planes;
+    uint32_t strides[4];
+    uint32_t offsets[4];
+    uint64_t modifier;
+    int i;
 
     if (xwl_pixmap->buffer)
         return xwl_pixmap->buffer;
 
+    if (!xwl_pixmap->bo)
+       return NULL;
+
     prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
     if (prime_fd == -1)
         return NULL;
 
-    xwl_pixmap->buffer =
-        wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
-                                   pixmap->drawable.width,
-                                   pixmap->drawable.height,
-                                   wl_drm_format_for_depth(pixmap->drawable.depth),
-                                   0, gbm_bo_get_stride(xwl_pixmap->bo),
-                                   0, 0,
-                                   0, 0);
+#ifdef GBM_BO_WITH_MODIFIERS
+    num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
+    modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+    for (i = 0; i < num_planes; i++) {
+        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+    }
+#else
+    num_planes = 1;
+    modifier = DRM_FORMAT_MOD_INVALID;
+    strides[0] = gbm_go_get_stride(xwl_pixmap->bo);
+    offsets[0] = 0;
+#endif
 
-    close(prime_fd);
+    if (xwl_screen->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
+        struct zwp_linux_buffer_params_v1 *params;
+
+        params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
+        for (i = 0; i < num_planes; i++) {
+            zwp_linux_buffer_params_v1_add(params, prime_fd, i,
+                                           offsets[i], strides[i],
+                                           modifier >> 32, modifier & 0xffffffff);
+        }
+
+        xwl_pixmap->buffer =
+           zwp_linux_buffer_params_v1_create_immed(params,
+                                                   pixmap->drawable.width,
+                                                   pixmap->drawable.height,
+                                                   wl_drm_format_for_depth(pixmap->drawable.depth),
+                                                   0);
+        zwp_linux_buffer_params_v1_destroy(params);
+    } else if (num_planes == 1) {
+        xwl_pixmap->buffer =
+            wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
+                                       pixmap->drawable.width,
+                                       pixmap->drawable.height,
+                                       wl_drm_format_for_depth(pixmap->drawable.depth),
+                                       0, gbm_bo_get_stride(xwl_pixmap->bo),
+                                       0, 0,
+                                       0, 0);
+    }
 
+    close(prime_fd);
     return xwl_pixmap->buffer;
 }
 
@@ -213,7 +254,8 @@ xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
             wl_buffer_destroy(xwl_pixmap->buffer);
 
         eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
-        gbm_bo_destroy(xwl_pixmap->bo);
+        if (xwl_pixmap->bo)
+           gbm_bo_destroy(xwl_pixmap->bo);
         free(xwl_pixmap);
     }
 
@@ -282,8 +324,6 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
     if (xwl_screen->egl_display)
         return;
 
-    xwl_screen->expecting_event--;
-
     xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd);
     if (xwl_screen->gbm == NULL) {
         ErrorF("couldn't get display device\n");
@@ -327,6 +367,12 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
         return;
     }
 
+    if (epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import") &&
+        epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import_modifiers"))
+       xwl_screen->dmabuf_capable = TRUE;
+
     return;
 }
 
@@ -347,12 +393,14 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
        return;
    }
 
+   xwl_screen->expecting_event--;
+
    if (is_fd_render_node(xwl_screen->drm_fd)) {
        xwl_screen->fd_render_node = 1;
-       xwl_drm_init_egl(xwl_screen);
    } else {
        drmGetMagic(xwl_screen->drm_fd, &magic);
        wl_drm_authenticate(xwl_screen->drm, magic);
+       xwl_screen->expecting_event++; /* wait for 'authenticated' */
    }
 }
 
@@ -379,8 +427,8 @@ xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
 {
     struct xwl_screen *xwl_screen = data;
 
-    if (!xwl_screen->egl_display)
-        xwl_drm_init_egl(xwl_screen);
+    xwl_screen->drm_authenticated = 1;
+    xwl_screen->expecting_event--;
 }
 
 static void
@@ -399,8 +447,8 @@ static const struct wl_drm_listener xwl_drm_listener = {
 };
 
 Bool
-xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
-                       uint32_t id, uint32_t version)
+xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
+                             uint32_t id, uint32_t version)
 {
     if (version < 2)
         return FALSE;
@@ -413,11 +461,23 @@ xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
     return TRUE;
 }
 
+Bool
+xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
+                                uint32_t id, uint32_t version)
+{
+    if (version < 3)
+        return FALSE;
+
+    xwl_screen->dmabuf =
+        wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+
+    return TRUE;
+}
+
 int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
-                                 PixmapPtr pixmap,
-                                 unsigned int tex,
-                                 Bool want_name, CARD16 *stride, CARD32 *size)
+glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
+                               PixmapPtr pixmap,
+                               CARD16 *stride, CARD32 *size)
 {
     return 0;
 }
@@ -518,58 +578,111 @@ xwl_dri3_open_client(ClientPtr client,
     return Success;
 }
 
-static PixmapPtr
-xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd,
-                        CARD16 width, CARD16 height, CARD16 stride,
-                        CARD8 depth, CARD8 bpp)
+_X_EXPORT PixmapPtr
+glamor_pixmap_from_fds(ScreenPtr screen,
+                         CARD8 num_fds, int *fds,
+                         CARD16 width, CARD16 height,
+                         CARD32 *strides, CARD32 *offsets,
+                         CARD8 depth, CARD8 bpp, uint64_t modifier)
 {
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    struct gbm_import_fd_data data;
-    struct gbm_bo *bo;
+    struct gbm_bo *bo = NULL;
     PixmapPtr pixmap;
+    int i;
+
+    if (width == 0 || height == 0 || num_fds == 0 ||
+        depth < 15 || bpp != BitsPerPixel(depth) ||
+        strides[0] < width * bpp / 8)
+       goto error;
+
+    if (xwl_screen->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
+#ifdef GBM_BO_WITH_MODIFIERS
+       struct gbm_import_fd_modifier_data data;
+
+       data.width = width;
+       data.height = height;
+       data.num_fds = num_fds;
+       data.format = gbm_format_for_depth(depth);
+       data.modifier = modifier;
+       for (i = 0; i < num_fds; i++) {
+          data.fds[i] = fds[i];
+          data.strides[i] = strides[i];
+          data.offsets[i] = offsets[i];
+       }
+       bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
+#endif
+    } else if (num_fds == 1) {
+       struct gbm_import_fd_data data;
+
+       data.fd = fds[0];
+       data.width = width;
+       data.height = height;
+       data.stride = strides[0];
+       data.format = gbm_format_for_depth(depth);
+       bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
+             GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+    } else {
+       goto error;
+    }
 
-    if (width == 0 || height == 0 ||
-        depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8)
-        return NULL;
-
-    data.fd = fd;
-    data.width = width;
-    data.height = height;
-    data.stride = stride;
-    data.format = gbm_format_for_depth(depth);
-    bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
-                       GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
     if (bo == NULL)
-        return NULL;
+       goto error;
 
     pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
     if (pixmap == NULL) {
-        gbm_bo_destroy(bo);
-        return NULL;
+       gbm_bo_destroy(bo);
+       goto error;
     }
 
     return pixmap;
+
+error:
+    for (i = 0; i < num_fds; i++)
+       close(fds[i]);
+    return NULL;
 }
 
-static int
-xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
-                        CARD16 *stride, CARD32 *size)
+_X_EXPORT int
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+                           uint32_t *strides, uint32_t *offsets,
+                           uint64_t *modifier)
 {
     struct xwl_pixmap *xwl_pixmap;
+#ifdef GBM_BO_WITH_MODIFIERS
+    uint32_t num_fds;
+    int i;
+#endif
 
     xwl_pixmap = xwl_pixmap_get(pixmap);
 
-    *stride = gbm_bo_get_stride(xwl_pixmap->bo);
-    *size = pixmap->drawable.width * *stride;
+    if (!xwl_pixmap->bo)
+       return 0;
 
-    return gbm_bo_get_fd(xwl_pixmap->bo);
+#ifdef GBM_BO_WITH_MODIFIERS
+    num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
+    *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+
+    for (i = 0; i < num_fds; i++) {
+        fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
+        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+    }
+
+    return num_fds;
+#else
+    *modifier = DRM_FORMAT_MOD_INVALID;
+    fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
+    strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
+    offsets[0] = 0;
+    return 1;
+#endif
 }
 
 static dri3_screen_info_rec xwl_dri3_info = {
-    .version = 1,
+    .version = 2,
     .open = NULL,
-    .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
-    .fd_from_pixmap = xwl_dri3_fd_from_pixmap,
+    .pixmap_from_fds = glamor_pixmap_from_fds,
+    .fds_from_pixmap = glamor_fds_from_pixmap,
     .open_client = xwl_dri3_open_client,
 };
 
@@ -585,6 +698,12 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
         return FALSE;
     }
 
+    if (!xwl_screen->fd_render_node && !xwl_screen->drm_authenticated) {
+        ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
+	return FALSE;
+    }
+
+    xwl_drm_init_egl(xwl_screen);
     if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
         ErrorF("Disabling glamor and dri3, EGL setup failed\n");
         return FALSE;
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 73bc47a67..d6a2887ac 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -728,7 +728,11 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
 #ifdef GLAMOR_HAS_GBM
     else if (xwl_screen->glamor &&
              strcmp(interface, "wl_drm") == 0 && version >= 2) {
-        xwl_screen_init_glamor(xwl_screen, id, version);
+        xwl_screen_set_drm_interface(xwl_screen, id, version);
+    }
+    else if (xwl_screen->glamor &&
+             strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
+        xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
     }
 #endif
 }
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index ffa0d7297..be95bab55 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -47,6 +47,7 @@
 #include "tablet-unstable-v2-client-protocol.h"
 #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
 #include "xdg-output-unstable-v1-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
 
 struct xwl_screen {
     int width;
@@ -96,12 +97,15 @@ struct xwl_screen {
     char *device_name;
     int drm_fd;
     int fd_render_node;
+    int drm_authenticated;
     struct wl_drm *drm;
+    struct zwp_linux_dmabuf_v1 *dmabuf;
     uint32_t formats;
     uint32_t capabilities;
     void *egl_display, *egl_context;
     struct gbm_device *gbm;
     struct glamor_context *glamor_ctx;
+    int dmabuf_capable;
 
     Atom allow_commits_prop;
 };
@@ -326,8 +330,10 @@ struct wl_buffer *xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap);
 
 Bool xwl_glamor_init(struct xwl_screen *xwl_screen);
 
-Bool xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
-                         uint32_t id, uint32_t version);
+Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
+                                  uint32_t id, uint32_t version);
+Bool xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
+                                     uint32_t id, uint32_t version);
 struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);
 
 void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen);
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 65d655ca8..ea932c46d 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -488,6 +488,9 @@
 /* Build glamor/gbm has linear support */
 #undef GLAMOR_HAS_GBM_LINEAR
 
+/* GBM has modifiers support */
+#undef GBM_BO_WITH_MODIFIERS
+
 /* Build glamor use new drmGetDeviceNameFromFD2 */
 #undef GLAMOR_HAS_DRM_NAME_FROM_FD_2
 
diff --git a/include/meson.build b/include/meson.build
index b83180f7c..c39c00420 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -84,6 +84,8 @@ conf_data.set('GLAMOR', build_glamor)
 conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
 conf_data.set('GLAMOR_HAS_GBM_LINEAR',
               gbm_dep.found() and gbm_dep.version().version_compare('>= 10.6'))
+conf_data.set('GBM_BO_WITH_MODIFIERS',
+              gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1'))
 
 conf_data.set_quoted('SERVER_MISC_CONFIG_PATH', serverconfigdir)
 conf_data.set_quoted('PROJECTROOT', get_option('prefix'))
commit 9d147305b4048dcec7ea4eda3eeea83f843f7788
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:42 2018 +0000

    modesetting: Check if buffer format is supported when flipping
    
    Add support for 'check_flip2' so that the present core can know
    why it is impossible to flip in that scenario. The core can then
    let know the client that the buffer format/modifier is suboptimal.
    
    v2: No longer need to implement 'check_flip'
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 6fa22da56..1f7a9fd0a 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -73,6 +73,48 @@ modifiers_ptr(struct drm_format_modifier_blob *blob)
 
 #endif
 
+Bool
+drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    int c, i, j;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+        Bool found = FALSE;
+
+        if (!crtc->enabled)
+            continue;
+
+        for (i = 0; i < drmmode_crtc->num_formats; i++) {
+            drmmode_format_ptr iter = &drmmode_crtc->formats[i];
+
+            if (iter->format != format)
+                continue;
+
+            if (modifier == 0) {
+                found = TRUE;
+                break;
+            }
+
+            for (j = 0; j < iter->num_modifiers; j++) {
+                if (iter->modifiers[j] == modifier) {
+                    found = TRUE;
+                    break;
+                }
+            }
+
+            break;
+        }
+
+        if (!found)
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
 #ifdef GBM_BO_WITH_MODIFIERS
 static uint32_t
 get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 75e4b8499..607fe8179 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -241,6 +241,8 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec;
 
 #define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))
 
+Bool drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format,
+                                 uint64_t modifier);
 int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
                       uint32_t *fb_id);
 int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo);
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index 4a01d19ea..71ef2f7f1 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -214,7 +214,8 @@ static Bool
 ms_present_check_flip(RRCrtcPtr crtc,
                       WindowPtr window,
                       PixmapPtr pixmap,
-                      Bool sync_flip)
+                      Bool sync_flip,
+                      PresentFlipReason *reason)
 {
     ScreenPtr screen = window->drawable.pScreen;
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
@@ -222,6 +223,9 @@ ms_present_check_flip(RRCrtcPtr crtc,
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
     int num_crtcs_on = 0;
     int i;
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+    struct gbm_bo *gbm;
+#endif
 
     if (!ms->drmmode.pageflip)
         return FALSE;
@@ -252,6 +256,23 @@ ms_present_check_flip(RRCrtcPtr crtc,
         pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
         return FALSE;
 
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+    /* Check if buffer format/modifier is supported by all active CRTCs */
+    gbm = glamor_gbm_bo_from_pixmap(screen, pixmap);
+    if (gbm) {
+        uint32_t format;
+        uint64_t modifier;
+
+        format = gbm_bo_get_format(gbm);
+        modifier = gbm_bo_get_modifier(gbm);
+        if (!drmmode_is_format_supported(scrn, format, modifier)) {
+            if (reason)
+                *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT;
+            return FALSE;
+        }
+    }
+#endif
+
     /* Make sure there's a bo we can get to */
     /* XXX: actually do this.  also...is it sufficient?
      * if (!glamor_get_pixmap_private(pixmap))
@@ -280,7 +301,7 @@ ms_present_flip(RRCrtcPtr crtc,
     Bool ret;
     struct ms_present_vblank_event *event;
 
-    if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip))
+    if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip, NULL))
         return FALSE;
 
     event = calloc(1, sizeof(struct ms_present_vblank_event));
@@ -323,7 +344,7 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
     event->event_id = event_id;
     event->unflip = TRUE;
 
-    if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE) &&
+    if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE, NULL) &&
         ms_do_pageflip(screen, pixmap, event, -1, FALSE,
                        ms_present_flip_handler, ms_present_flip_abort)) {
         return;
@@ -368,7 +389,8 @@ static present_screen_info_rec ms_present_screen_info = {
 
     .capabilities = PresentCapabilityNone,
 #ifdef GLAMOR_HAS_GBM
-    .check_flip = ms_present_check_flip,
+    .check_flip = NULL,
+    .check_flip2 = ms_present_check_flip,
     .flip = ms_present_flip,
     .unflip = ms_present_unflip,
 #endif
commit e375f29662ad7589cc6d8d179846da9b8a897122
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:41 2018 +0000

    modesetting: Create scanout buffers using supported modifiers
    
    Use most optimal buffer format (e.g. tiled/compressed) available
    for scanout.
    
    v2: Don't use multi-plane modifier to create scanout buffer
    
    v3: Add flag to retrieve modifiers set from enabled CRTCs only
    
    v4: Fix uses when GBM/EGL driver doesn't support modifiers
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7af805da2..6fa22da56 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -73,6 +73,68 @@ modifiers_ptr(struct drm_format_modifier_blob *blob)
 
 #endif
 
+#ifdef GBM_BO_WITH_MODIFIERS
+static uint32_t
+get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
+                  Bool enabled_crtc_only, Bool exclude_multiplane)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    modesettingPtr ms = modesettingPTR(scrn);
+    drmmode_ptr drmmode = &ms->drmmode;
+    int c, i, j, k, count_modifiers = 0;
+    uint64_t *tmp, *ret = NULL;
+
+    *modifiers = NULL;
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+        if (enabled_crtc_only && !crtc->enabled)
+            continue;
+
+        for (i = 0; i < drmmode_crtc->num_formats; i++) {
+            drmmode_format_ptr iter = &drmmode_crtc->formats[i];
+
+            if (iter->format != format)
+                continue;
+
+            for (j = 0; j < iter->num_modifiers; j++) {
+                Bool found = FALSE;
+
+		/* Don't choose multi-plane formats for our screen pixmap.
+		 * These will get used with frontbuffer rendering, which will
+		 * lead to worse-than-tearing with multi-plane formats, as the
+		 * primary and auxiliary planes go out of sync. */
+		if (exclude_multiplane &&
+                    gbm_device_get_format_modifier_plane_count(drmmode->gbm,
+                                                               format,
+                                                               iter->modifiers[j]) > 1) {
+                    continue;
+                }
+
+                for (k = 0; k < count_modifiers; k++) {
+                    if (iter->modifiers[j] == ret[k])
+                        found = TRUE;
+                }
+                if (!found) {
+                    count_modifiers++;
+                    tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
+                    if (!tmp) {
+                        free(ret);
+                        return 0;
+                    }
+                    ret = tmp;
+                    ret[count_modifiers - 1] = iter->modifiers[j];
+                }
+            }
+        }
+    }
+
+    *modifiers = ret;
+    return count_modifiers;
+}
+#endif
+
 static Bool
 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
 {
@@ -593,14 +655,36 @@ static Bool
 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
                   unsigned width, unsigned height, unsigned bpp)
 {
+    uint32_t format;
+
+    if (drmmode->scrn->depth == 30)
+        format = GBM_FORMAT_ARGB2101010;
+    else
+        format = GBM_FORMAT_ARGB8888;
+
     bo->width = width;
     bo->height = height;
 
 #ifdef GLAMOR_HAS_GBM
     if (drmmode->glamor) {
-        bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
-                                drmmode->scrn->depth == 30 ?
-                                GBM_FORMAT_ARGB2101010 : GBM_FORMAT_ARGB8888,
+#ifdef GBM_BO_WITH_MODIFIERS
+        uint32_t num_modifiers;
+        uint64_t *modifiers = NULL;
+
+        num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
+                                          FALSE, TRUE);
+        if (num_modifiers > 0 &&
+            !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
+            bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
+                                                   format, modifiers,
+                                                   num_modifiers);
+            free(modifiers);
+            if (bo->gbm)
+                return TRUE;
+        }
+#endif
+
+        bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
                                 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
         return bo->gbm != NULL;
     }
commit ca1c390ec7bf617c0147d69cf874dadce28e903b
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:40 2018 +0000

    modesetting: Get supported formats/modifiers for scanout
    
    Retrieve IN_FORMATS property from the plane. It gives the
    allowed formats and modifiers for BO allocation.
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 00549148c..f4534e30b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2107,6 +2107,10 @@ if test "x$GLAMOR" = xyes; then
 	PKG_CHECK_EXISTS(libdrm >= 2.4.74,
 			 [AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
 			 [])
+
+	PKG_CHECK_EXISTS(libdrm >= 2.4.83,
+			 [AC_DEFINE(GLAMOR_HAS_DRM_MODIFIERS, 1, [Have GLAMOR_HAS_DRM_MODIFIERS])],
+			 [])
 fi
 AM_CONDITIONAL([GLAMOR_EGL], [test "x$GBM" = xyes])
 
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 3e3613a98..7af805da2 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -56,6 +56,23 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
 static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
                                               int depth, int bitsPerPixel, int devKind,
                                               void *pPixData);
+
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+
+static inline uint32_t *
+formats_ptr(struct drm_format_modifier_blob *blob)
+{
+    return (uint32_t *)(((char *)blob) + blob->formats_offset);
+}
+
+static inline struct drm_format_modifier *
+modifiers_ptr(struct drm_format_modifier_blob *blob)
+{
+    return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
+}
+
+#endif
+
 static Bool
 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
 {
@@ -1532,15 +1549,76 @@ is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
     return FALSE;
 }
 
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+/**
+ * Populates the formats array, and the modifiers of each format for a drm_plane.
+ */
+static Bool
+populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
+                          uint32_t blob_id)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    drmmode_ptr drmmode = drmmode_crtc->drmmode;
+    unsigned i, j;
+    drmModePropertyBlobRes *blob;
+    struct drm_format_modifier_blob *fmt_mod_blob;
+    uint32_t *blob_formats;
+    struct drm_format_modifier *blob_modifiers;
+
+    blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
+    if (!blob)
+        return FALSE;
+
+    fmt_mod_blob = blob->data;
+    blob_formats = formats_ptr(fmt_mod_blob);
+    blob_modifiers = modifiers_ptr(fmt_mod_blob);
+
+    assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
+
+    for (i = 0; i < fmt_mod_blob->count_formats; i++) {
+        uint32_t num_modifiers = 0;
+        uint64_t *modifiers = NULL;
+        uint64_t *tmp;
+
+        for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
+            struct drm_format_modifier *mod = &blob_modifiers[j];
+
+            if ((i < mod->offset) || (i > mod->offset + 63))
+                continue;
+            if (!(mod->formats & (1 << (i - mod->offset))))
+                continue;
+
+            num_modifiers++;
+            tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
+            if (!tmp) {
+                free(modifiers);
+                drmModeFreePropertyBlob(blob);
+                return FALSE;
+            }
+            modifiers = tmp;
+            modifiers[num_modifiers - 1] = mod->modifier;
+        }
+
+        drmmode_crtc->formats[i].format = blob_formats[i];
+        drmmode_crtc->formats[i].modifiers = modifiers;
+        drmmode_crtc->formats[i].num_modifiers = num_modifiers;
+    }
+
+    drmModeFreePropertyBlob(blob);
+
+    return TRUE;
+}
+#endif
+
 static void
 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
 {
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     drmmode_ptr drmmode = drmmode_crtc->drmmode;
     drmModePlaneRes *kplane_res;
-    drmModePlane *kplane;
+    drmModePlane *kplane, *best_kplane = NULL;
     drmModeObjectProperties *props;
-    uint32_t i, type;
+    uint32_t i, type, blob_id;
     int current_crtc, best_plane = 0;
 
     static drmmode_prop_enum_info_rec plane_type_enums[] = {
@@ -1562,6 +1640,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
         },
         [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+        [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
         [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
@@ -1602,13 +1681,13 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
         }
 
         plane_id = kplane->plane_id;
-        drmModeFreePlane(kplane);
 
         props = drmModeObjectGetProperties(drmmode->fd, plane_id,
                                            DRM_MODE_OBJECT_PLANE);
         if (!props) {
             xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
                     "couldn't get plane properties\n");
+            drmModeFreePlane(kplane);
             continue;
         }
 
@@ -1618,6 +1697,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
         type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
                                       props, DRMMODE_PLANE_TYPE__COUNT);
         if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+            drmModeFreePlane(kplane);
             drmModeFreeObjectProperties(props);
             continue;
         }
@@ -1626,9 +1706,14 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
         current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
                                               props, 0);
         if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
-            if (best_plane)
+            if (best_plane) {
+                drmModeFreePlane(best_kplane);
                 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+            }
             best_plane = plane_id;
+            best_kplane = kplane;
+            blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+                                             props, 0);
             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
                                    DRMMODE_PLANE__COUNT, 1);
             drmModeFreeObjectProperties(props);
@@ -1637,14 +1722,35 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
 
         if (!best_plane) {
             best_plane = plane_id;
+            best_kplane = kplane;
+            blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+                                             props, 0);
             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
                                    DRMMODE_PLANE__COUNT, 1);
+        } else {
+            drmModeFreePlane(kplane);
         }
 
         drmModeFreeObjectProperties(props);
     }
 
     drmmode_crtc->plane_id = best_plane;
+    if (best_kplane) {
+        drmmode_crtc->num_formats = best_kplane->count_formats;
+        drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
+                                       best_kplane->count_formats);
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+        if (blob_id) {
+            populate_format_modifiers(crtc, best_kplane, blob_id);
+        }
+        else
+#endif
+        {
+            for (i = 0; i < best_kplane->count_formats; i++)
+                drmmode_crtc->formats[i].format = best_kplane->formats[i];
+        }
+        drmModeFreePlane(best_kplane);
+    }
 
     drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
     drmModeFreePlaneResources(kplane_res);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index e5f3542c5..75e4b8499 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -39,6 +39,7 @@ struct gbm_device;
 enum drmmode_plane_property {
     DRMMODE_PLANE_TYPE = 0,
     DRMMODE_PLANE_FB_ID,
+    DRMMODE_PLANE_IN_FORMATS,
     DRMMODE_PLANE_CRTC_ID,
     DRMMODE_PLANE_SRC_X,
     DRMMODE_PLANE_SRC_Y,
@@ -143,6 +144,12 @@ typedef struct {
 } drmmode_mode_rec, *drmmode_mode_ptr;
 
 typedef struct {
+    uint32_t format;
+    uint32_t num_modifiers;
+    uint64_t *modifiers;
+} drmmode_format_rec, *drmmode_format_ptr;
+
+typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     uint32_t vblank_pipe;
@@ -155,6 +162,8 @@ typedef struct {
     drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
     uint32_t plane_id;
     drmmode_mode_ptr current_mode;
+    uint32_t num_formats;
+    drmmode_format_rec *formats;
 
     drmmode_bo rotate_bo;
     unsigned rotate_fb_id;
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 9f8dc913f..65d655ca8 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -494,6 +494,9 @@
 /* Glamor should use atomic DRM API */
 #undef GLAMOR_HAS_DRM_ATOMIC
 
+/* Glamor can retrieve supported DRM formats/modifiers */
+#undef GLAMOR_HAS_DRM_MODIFIERS
+
 /* byte order */
 #undef X_BYTE_ORDER
 
diff --git a/include/meson.build b/include/meson.build
index 88d96cacc..b83180f7c 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -77,6 +77,8 @@ conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
               libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
 conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
               libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
+conf_data.set('GLAMOR_HAS_DRM_MODIFIERS',
+              libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.83'))
 conf_data.set('GLXEXT', build_glx)
 conf_data.set('GLAMOR', build_glamor)
 conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
commit 9817c14f6a2ea5db44459659131c13f403716df1
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:39 2018 +0000

    modesetting: Use atomic modesetting to configure output/CRTCs
    
    To make sure we also use the same primary plane and to avoid
    mixing uses of two APIs, it is better to always use the atomic
    modesetting API when possible.
    
    v2: Don't use mode_output->connector_id
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index ee9f4d724..3e3613a98 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -267,16 +267,100 @@ plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
                                    info->prop_id, val);
     return (ret <= 0) ? -1 : 0;
 }
+
+static int
+crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+              enum drmmode_crtc_property prop, uint64_t val)
+{
+    drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
+    int ret;
+
+    if (!info)
+        return -1;
+
+    ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
+                                   info->prop_id, val);
+    return (ret <= 0) ? -1 : 0;
+}
+
+static int
+connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
+                   enum drmmode_connector_property prop, uint64_t val)
+{
+    drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
+    int ret;
+
+    if (!info)
+        return -1;
+
+    ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
+                                   info->prop_id, val);
+    return (ret <= 0) ? -1 : 0;
+}
+
+static int
+drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
+{
+    return memcmp(kmode, other, sizeof(*kmode));
+}
+
+static int
+drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    drmmode_mode_ptr mode;
+    int ret;
+
+    if (drmmode_crtc->current_mode &&
+        drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
+        return 0;
+
+    mode = calloc(sizeof(drmmode_mode_rec), 1);
+    if (!mode)
+        return -1;
+
+    mode->mode_info = mode_info;
+    ret = drmModeCreatePropertyBlob(ms->fd,
+                                    &mode->mode_info,
+                                    sizeof(mode->mode_info),
+                                    &mode->blob_id);
+    drmmode_crtc->current_mode = mode;
+    xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
+
+    return ret;
+}
+
+static void
+drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    if (mode->blob_id)
+        drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
+    xorg_list_del(&mode->entry);
+    free(mode);
+}
 #endif
 
+static void
+drmmode_ConvertToKMode(ScrnInfoPtr scrn,
+                       drmModeModeInfo * kmode, DisplayModePtr mode);
+
 int
-drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
                     int x, int y, uint32_t flags, void *data)
 {
     modesettingPtr ms = modesettingPTR(crtc->scrn);
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-    int ret = 0;
+    drmmode_ptr drmmode = drmmode_crtc->drmmode;
+    int output_count = 0;
+    uint32_t *output_ids = NULL;
+    drmModeModeInfo kmode;
+    int i, ret = 0;
+
+    if (mode)
+        drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
 #ifdef GLAMOR_HAS_DRM_ATOMIC
     if (ms->atomic_modeset) {
@@ -285,12 +369,56 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
         if (!req)
             return 1;
 
+        if (mode) {
+            ret = drm_mode_ensure_blob(crtc, kmode);
+
+            for (i = 0; i < xf86_config->num_output; i++) {
+                xf86OutputPtr output = xf86_config->output[i];
+                drmmode_output_private_ptr drmmode_output;
+
+                if (output->crtc != crtc)
+                    continue;
+
+                drmmode_output = output->driver_private;
+                if (drmmode_output->output_id == -1)
+                    continue;
+
+                if (drmmode_output->dpms == DPMSModeOn) {
+                    ret |= crtc_add_prop(req, drmmode_crtc,
+                                         DRMMODE_CRTC_ACTIVE, 1);
+                    ret |= crtc_add_prop(req, drmmode_crtc,
+                                         DRMMODE_CRTC_MODE_ID,
+                                         drmmode_crtc->current_mode->blob_id);
+                    ret |= connector_add_prop(req, drmmode_output,
+                                              DRMMODE_CONNECTOR_CRTC_ID,
+                                              drmmode_crtc->mode_crtc->crtc_id);
+                } else {
+                    ret |= crtc_add_prop(req, drmmode_crtc,
+                                         DRMMODE_CRTC_ACTIVE, 0);
+                    ret |= crtc_add_prop(req, drmmode_crtc,
+                                         DRMMODE_CRTC_MODE_ID, 0);
+                    ret |= connector_add_prop(req, drmmode_output,
+                                              DRMMODE_CONNECTOR_CRTC_ID, 0);
+                }
+            }
+        }
+
         ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
                               fb_id);
         ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
                               drmmode_crtc->mode_crtc->crtc_id);
-        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
-        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
+                              drmmode->front_bo.width << 16);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
+                              drmmode->front_bo.height << 16);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
+                              drmmode->front_bo.width);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
+                              drmmode->front_bo.height);
 
         if (ret == 0)
             ret = drmModeAtomicCommit(ms->fd, req, flags, data);
@@ -300,7 +428,29 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
     }
 #endif
 
-    return 0;
+    output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
+    if (!output_ids)
+        return -1;
+
+    for (i = 0; i < xf86_config->num_output; i++) {
+        xf86OutputPtr output = xf86_config->output[i];
+        drmmode_output_private_ptr drmmode_output;
+
+        if (output->crtc != crtc)
+            continue;
+
+        drmmode_output = output->driver_private;
+        if (drmmode_output->output_id == -1)
+            continue;
+        output_ids[output_count] = drmmode_output->output_id;
+        output_count++;
+    }
+
+    ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+                         fb_id, x, y, output_ids, output_count, &kmode);
+
+    free(output_ids);
+    return ret;
 }
 
 
@@ -858,23 +1008,16 @@ static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
                        Rotation rotation, int x, int y)
 {
-    ScrnInfoPtr pScrn = crtc->scrn;
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     drmmode_ptr drmmode = drmmode_crtc->drmmode;
     int saved_x, saved_y;
     Rotation saved_rotation;
     DisplayModeRec saved_mode;
-    uint32_t *output_ids = NULL;
-    int output_count = 0;
     Bool ret = TRUE;
     int i;
     uint32_t fb_id = 0;
-    drmModeModeInfo kmode;
-
-    output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
-    if (!output_ids)
-        return FALSE;
+    uint32_t flags = 0;
 
     saved_mode = crtc->mode;
     saved_x = crtc->x;
@@ -887,29 +1030,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
         crtc->y = y;
         crtc->rotation = rotation;
 
-        for (i = 0; i < xf86_config->num_output; i++) {
-            xf86OutputPtr output = xf86_config->output[i];
-            drmmode_output_private_ptr drmmode_output;
-
-            if (output->crtc != crtc)
-                continue;
-
-            drmmode_output = output->driver_private;
-            if (drmmode_output->output_id == -1)
-                continue;
-            output_ids[output_count] =
-                drmmode_output->mode_output->connector_id;
-            output_count++;
-        }
-
         if (!xf86CrtcRotate(crtc)) {
             goto done;
         }
+
         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
                                crtc->gamma_blue, crtc->gamma_size);
 
-        drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
-
         fb_id = drmmode->fb_id;
         if (drmmode_crtc->prime_pixmap) {
             if (!drmmode->reverse_prime_offload_mode) {
@@ -927,12 +1054,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
         }
 
         if (fb_id == 0) {
-            ret = drmModeAddFB(drmmode->fd,
-                               pScrn->virtualX, pScrn->virtualY,
-                               pScrn->depth, drmmode->kbpp,
-                               drmmode_bo_get_pitch(&drmmode->front_bo),
-                               drmmode_bo_get_handle(&drmmode->front_bo),
-                               &drmmode->fb_id);
+            ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
+                                    &drmmode->fb_id);
             if (ret < 0) {
                 ErrorF("failed to add fb %d\n", ret);
                 ret = FALSE;
@@ -941,8 +1064,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
             fb_id = drmmode->fb_id;
         }
 
-        if (drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
-                           fb_id, x, y, output_ids, output_count, &kmode)) {
+        flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+        if (drmmode_crtc_set_fb(crtc, mode, fb_id, x, y, flags, NULL)) {
             xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
                        "failed to set mode: %s\n", strerror(errno));
             ret = FALSE;
@@ -983,8 +1106,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
     } else
         crtc->active = TRUE;
 
-    free(output_ids);
-
     return ret;
 }
 
@@ -1355,9 +1476,15 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
 static void
 drmmode_crtc_destroy(xf86CrtcPtr crtc)
 {
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    drmmode_mode_ptr iterator, next;
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
     drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+    xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
+        drm_mode_destroy(crtc, iterator);
+    }
+#endif
 }
 
 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
@@ -1437,6 +1564,12 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+        [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
+        [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
+        [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
+        [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
+        [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
+        [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
     };
     drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
 
@@ -1524,19 +1657,37 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
     xf86CrtcPtr crtc;
     drmmode_crtc_private_ptr drmmode_crtc;
     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    drmModeObjectPropertiesPtr props;
+    static const drmmode_prop_info_rec crtc_props[] = {
+        [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
+        [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
+    };
+#endif
 
     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
     if (crtc == NULL)
         return 0;
-
     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
+    crtc->driver_private = drmmode_crtc;
     drmmode_crtc->mode_crtc =
         drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
     drmmode_crtc->drmmode = drmmode;
     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
-    crtc->driver_private = drmmode_crtc;
+    xorg_list_init(&drmmode_crtc->mode_list);
 
 #ifdef GLAMOR_HAS_DRM_ATOMIC
+    props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
+                                       DRM_MODE_OBJECT_CRTC);
+    if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
+                                          DRMMODE_CRTC__COUNT, 0)) {
+        xf86CrtcDestroy(crtc);
+        return 0;
+    }
+
+    drmmode_prop_info_update(drmmode, drmmode_crtc->props,
+                             DRMMODE_CRTC__COUNT, props);
+    drmModeFreeObjectProperties(props);
     drmmode_crtc_create_planes(crtc, num);
 #endif
 
@@ -1680,6 +1831,7 @@ koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
     return idx;
 }
 
+#ifndef GLAMOR_HAS_DRM_ATOMIC
 static int
 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
         int type, const char *name)
@@ -1688,6 +1840,7 @@ koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
 
     return (idx > -1) ? koutput->props[idx] : -1;
 }
+#endif
 
 static drmModePropertyBlobPtr
 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
@@ -1859,13 +2012,19 @@ drmmode_output_dpms(xf86OutputPtr output, int mode)
     drmmode_output_private_ptr drmmode_output = output->driver_private;
     xf86CrtcPtr crtc = output->crtc;
     drmModeConnectorPtr koutput = drmmode_output->mode_output;
+#ifndef GLAMOR_HAS_DRM_ATOMIC
     drmmode_ptr drmmode = drmmode_output->drmmode;
+#endif
 
     if (!koutput)
         return;
 
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    drmmode_output->dpms = mode;
+#else
     drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
                                 drmmode_output->dpms_enum_id, mode);
+#endif
 
     if (crtc) {
         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
@@ -2214,6 +2373,13 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
     Bool nonDesktop = FALSE;
     drmModePropertyBlobPtr path_blob = NULL;
     const char *s;
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    drmModeObjectPropertiesPtr props;
+    static const drmmode_prop_info_rec connector_props[] = {
+        [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
+    };
+#endif
+
     koutput =
         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
     if (!koutput)
@@ -2301,8 +2467,20 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
     /* work out the possible clones later */
     output->possible_clones = 0;
 
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    if (!drmmode_prop_info_copy(drmmode_output->props_connector, connector_props,
+                                DRMMODE_CONNECTOR__COUNT, 0)) {
+        goto out_free_encoders;
+    }
+    props = drmModeObjectGetProperties(drmmode->fd,
+                                       drmmode_output->output_id,
+                                       DRM_MODE_OBJECT_CONNECTOR);
+    drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
+                             DRMMODE_CONNECTOR__COUNT, props);
+#else
     drmmode_output->dpms_enum_id =
         koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM, "DPMS");
+#endif
 
     if (dynamic)
         output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 177ccabd7..e5f3542c5 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -42,6 +42,12 @@ enum drmmode_plane_property {
     DRMMODE_PLANE_CRTC_ID,
     DRMMODE_PLANE_SRC_X,
     DRMMODE_PLANE_SRC_Y,
+    DRMMODE_PLANE_SRC_W,
+    DRMMODE_PLANE_SRC_H,
+    DRMMODE_PLANE_CRTC_X,
+    DRMMODE_PLANE_CRTC_Y,
+    DRMMODE_PLANE_CRTC_W,
+    DRMMODE_PLANE_CRTC_H,
     DRMMODE_PLANE__COUNT
 };
 
@@ -52,6 +58,17 @@ enum drmmode_plane_type {
     DRMMODE_PLANE_TYPE__COUNT
 };
 
+enum drmmode_connector_property {
+    DRMMODE_CONNECTOR_CRTC_ID,
+    DRMMODE_CONNECTOR__COUNT
+};
+
+enum drmmode_crtc_property {
+    DRMMODE_CRTC_ACTIVE,
+    DRMMODE_CRTC_MODE_ID,
+    DRMMODE_CRTC__COUNT
+};
+
 typedef struct {
     uint32_t width;
     uint32_t height;
@@ -120,6 +137,12 @@ typedef struct {
 } drmmode_prop_info_rec, *drmmode_prop_info_ptr;
 
 typedef struct {
+    drmModeModeInfo mode_info;
+    uint32_t blob_id;
+    struct xorg_list entry;
+} drmmode_mode_rec, *drmmode_mode_ptr;
+
+typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     uint32_t vblank_pipe;
@@ -128,8 +151,10 @@ typedef struct {
     Bool cursor_up;
     uint16_t lut_r[256], lut_g[256], lut_b[256];
 
+    drmmode_prop_info_rec props[DRMMODE_CRTC__COUNT];
     drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
     uint32_t plane_id;
+    drmmode_mode_ptr current_mode;
 
     drmmode_bo rotate_bo;
     unsigned rotate_fb_id;
@@ -151,6 +176,7 @@ typedef struct {
     /** @} */
 
     Bool need_modeset;
+    struct xorg_list mode_list;
 
     Bool enable_flipping;
     Bool flipping_active;
@@ -171,8 +197,10 @@ typedef struct {
     drmModePropertyBlobPtr edid_blob;
     drmModePropertyBlobPtr tile_blob;
     int dpms_enum_id;
+    int dpms;
     int num_props;
     drmmode_prop_ptr props;
+    drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT];
     int enc_mask;
     int enc_clone_mask;
 } drmmode_output_private_rec, *drmmode_output_private_ptr;
@@ -242,7 +270,7 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
 
 void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 
-int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
                         int x, int y, uint32_t flags, void *data);
 
 #ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index 027ebfe42..26738f928 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -168,7 +168,7 @@ do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
 #ifdef GLAMOR_HAS_DRM_ATOMIC
     if (ms->atomic_modeset) {
         flags |= DRM_MODE_ATOMIC_NONBLOCK;
-        return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+        return drmmode_crtc_set_fb(crtc, NULL, ms->drmmode.fb_id, 0, 0, flags,
                                    (void *) (uintptr_t) seq);
     }
 #endif
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index c01be3486..4a01d19ea 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -248,7 +248,8 @@ ms_present_check_flip(RRCrtcPtr crtc,
         return FALSE;
 
     /* Check stride, can't change that on flip */
-    if (pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
+    if (!ms->atomic_modeset &&
+        pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
         return FALSE;
 
     /* Make sure there's a bo we can get to */
commit 2f807c2324b46fbd9a557e7a4f177a392d5851b3
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:38 2018 +0000

    modesetting: Add support for multi-plane pixmaps when page-flipping
    
    This allows the uses of CCS compressed or tiled pixmaps as BOs when
    page-flipping.
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 8674c2c16..ee9f4d724 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -39,6 +39,8 @@
 #include "micmap.h"
 #include "xf86cmap.h"
 #include "xf86DDC.h"
+#include <drm_fourcc.h>
+#include <drm_mode.h>
 
 #include <xf86drm.h>
 #include "xf86Crtc.h"
@@ -376,10 +378,57 @@ drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
     return bo->dumb->ptr;
 }
 
+int
+drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+                  uint32_t *fb_id)
+{
+#ifdef GBM_BO_WITH_MODIFIERS
+    if (bo->gbm &&
+        gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
+        int num_fds;
+
+        num_fds = gbm_bo_get_plane_count(bo->gbm);
+        if (num_fds > 0) {
+            int i;
+            uint32_t format;
+            uint32_t handles[4];
+            uint32_t strides[4];
+            uint32_t offsets[4];
+            uint64_t modifiers[4];
+
+            memset(handles, 0, sizeof(handles));
+            memset(strides, 0, sizeof(strides));
+            memset(offsets, 0, sizeof(offsets));
+            memset(modifiers, 0, sizeof(modifiers));
+
+            format = gbm_bo_get_format(bo->gbm);
+            for (i = 0; i < num_fds; i++) {
+                handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
+                strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
+                offsets[i] = gbm_bo_get_offset(bo->gbm, i);
+                modifiers[i] = gbm_bo_get_modifier(bo->gbm);
+            }
+
+            return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
+                                              format, handles, strides,
+                                              offsets, modifiers, fb_id,
+                                              DRM_MODE_FB_MODIFIERS);
+        }
+    }
+#endif
+    return drmModeAddFB(drmmode->fd, bo->width, bo->height,
+                        drmmode->scrn->depth, drmmode->scrn->bitsPerPixel,
+                        drmmode_bo_get_pitch(bo),
+                        drmmode_bo_get_handle(bo), fb_id);
+}
+
 static Bool
 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
                   unsigned width, unsigned height, unsigned bpp)
 {
+    bo->width = width;
+    bo->height = height;
+
 #ifdef GLAMOR_HAS_GBM
     if (drmmode->glamor) {
         bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 1f24c3a5b..177ccabd7 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -53,6 +53,8 @@ enum drmmode_plane_type {
 };
 
 typedef struct {
+    uint32_t width;
+    uint32_t height;
     struct dumb_bo *dumb;
 #ifdef GLAMOR_HAS_GBM
     struct gbm_bo *gbm;
@@ -202,6 +204,8 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec;
 
 #define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))
 
+int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+                      uint32_t *fb_id);
 int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo);
 uint32_t drmmode_bo_get_pitch(drmmode_bo *bo);
 uint32_t drmmode_bo_get_handle(drmmode_bo *bo);
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index dd296cd12..027ebfe42 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -258,6 +258,7 @@ ms_do_pageflip(ScreenPtr screen,
 
     new_front_bo.gbm = glamor_gbm_bo_from_pixmap(screen, new_front);
     new_front_bo.dumb = NULL;
+
     if (!new_front_bo.gbm) {
         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
                    "Failed to get GBM bo for flip to new front.\n");
@@ -288,14 +289,12 @@ ms_do_pageflip(ScreenPtr screen,
 
     /* Create a new handle for the back buffer */
     flipdata->old_fb_id = ms->drmmode.fb_id;
-    if (drmModeAddFB(ms->fd, scrn->virtualX, scrn->virtualY,
-                     scrn->depth, scrn->bitsPerPixel,
-                     drmmode_bo_get_pitch(&new_front_bo),
-                     drmmode_bo_get_handle(&new_front_bo), &ms->drmmode.fb_id)) {
-        goto error_out;
-    }
 
-    drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+    new_front_bo.width = new_front->drawable.width;
+    new_front_bo.height = new_front->drawable.height;
+    if (drmmode_bo_import(&ms->drmmode, &new_front_bo,
+                          &ms->drmmode.fb_id))
+        goto error_out;
 
     flags = DRM_MODE_PAGE_FLIP_EVENT;
     if (async)
@@ -323,6 +322,8 @@ ms_do_pageflip(ScreenPtr screen,
         }
     }
 
+    drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+
     /*
      * Do we have more than our local reference,
      * if so and no errors, then drop our local
@@ -348,6 +349,7 @@ error_undo:
 error_out:
     xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
                strerror(errno));
+    drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
     /* if only the local reference - free the structure,
      * else drop the local reference and return */
     if (flipdata->flip_count == 1)
commit 4023d537341b9c36b9bb248c206e40694e4b08d2
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:37 2018 +0000

    modesetting: Use atomic modesetting API for pageflip if available
    
    In order to flip between compressed and uncompressed buffers -
    something drmModePageFlip explicitly bans us from doing - we need
    to port use the atomic modesetting API. It's only 'fake' atomic
    though given we still commit for each CRTC separately and
    CRTC and connector properties are not set with the atomic API.
    
    The helper functions to retrieve DRM properties have been borrowed
    from Weston.
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index e1ca8f974..00549148c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2101,6 +2101,9 @@ if test "x$GLAMOR" = xyes; then
 		fi
 	fi
 
+	PKG_CHECK_EXISTS(libdrm >= 2.4.62,
+			 [AC_DEFINE(GLAMOR_HAS_DRM_ATOMIC, 1, [libdrm supports atomic API])],
+			 [])
 	PKG_CHECK_EXISTS(libdrm >= 2.4.74,
 			 [AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
 			 [])
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index ec2aa9a27..88a42257c 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1018,6 +1018,12 @@ PreInit(ScrnInfoPtr pScrn, int flags)
     }
 #endif
 
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+    ret |= drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+    ms->atomic_modeset = (ret == 0);
+#endif
+
     if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
         goto fail;
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
index fe835918b..ed32239db 100644
--- a/hw/xfree86/drivers/modesetting/driver.h
+++ b/hw/xfree86/drivers/modesetting/driver.h
@@ -105,6 +105,7 @@ typedef struct _modesettingRec {
      * Page flipping stuff.
      *  @{
      */
+    Bool atomic_modeset;
     /** @} */
 
     DamagePtr damage;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index bfc8c50db..8674c2c16 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -75,6 +75,233 @@ drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name
     return ret;
 }
 
+static uint64_t
+drmmode_prop_get_value(drmmode_prop_info_ptr info,
+                       drmModeObjectPropertiesPtr props,
+                       uint64_t def)
+{
+    unsigned int i;
+
+    if (info->prop_id == 0)
+        return def;
+
+    for (i = 0; i < props->count_props; i++) {
+        unsigned int j;
+
+        if (props->props[i] != info->prop_id)
+            continue;
+
+        /* Simple (non-enum) types can return the value directly */
+        if (info->num_enum_values == 0)
+            return props->prop_values[i];
+
+        /* Map from raw value to enum value */
+        for (j = 0; j < info->num_enum_values; j++) {
+            if (!info->enum_values[j].valid)
+                continue;
+            if (info->enum_values[j].value != props->prop_values[i])
+                continue;
+
+            return j;
+        }
+    }
+
+    return def;
+}
+
+static uint32_t
+drmmode_prop_info_update(drmmode_ptr drmmode,
+                         drmmode_prop_info_ptr info,
+                         unsigned int num_infos,
+                         drmModeObjectProperties *props)
+{
+    drmModePropertyRes *prop;
+    uint32_t valid_mask = 0;
+    unsigned i, j;
+
+    assert(num_infos <= 32 && "update return type");
+
+    for (i = 0; i < props->count_props; i++) {
+        Bool props_incomplete = FALSE;
+        unsigned int k;
+
+        for (j = 0; j < num_infos; j++) {
+            if (info[j].prop_id == props->props[i])
+                break;
+            if (!info[j].prop_id)
+                props_incomplete = TRUE;
+        }
+
+        /* We've already discovered this property. */
+        if (j != num_infos)
+            continue;
+
+        /* We haven't found this property ID, but as we've already
+         * found all known properties, we don't need to look any
+         * further. */
+        if (!props_incomplete)
+            break;
+
+        prop = drmModeGetProperty(drmmode->fd, props->props[i]);
+        if (!prop)
+            continue;
+
+        for (j = 0; j < num_infos; j++) {
+            if (!strcmp(prop->name, info[j].name))
+                break;
+        }
+
+        /* We don't know/care about this property. */
+        if (j == num_infos) {
+            drmModeFreeProperty(prop);
+            continue;
+        }
+
+        info[j].prop_id = props->props[i];
+        valid_mask |= 1U << j;
+
+        if (info[j].num_enum_values == 0) {
+            drmModeFreeProperty(prop);
+            continue;
+        }
+
+        if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
+            xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
+                       "expected property %s to be an enum,"
+                       " but it is not; ignoring\n", prop->name);
+            drmModeFreeProperty(prop);
+            continue;
+        }
+
+        for (k = 0; k < info[j].num_enum_values; k++) {
+            int l;
+
+            if (info[j].enum_values[k].valid)
+                continue;
+
+            for (l = 0; l < prop->count_enums; l++) {
+                if (!strcmp(prop->enums[l].name,
+                            info[j].enum_values[k].name))
+                    break;
+            }
+
+            if (l == prop->count_enums)
+                continue;
+
+            info[j].enum_values[k].valid = TRUE;
+            info[j].enum_values[k].value = prop->enums[l].value;
+        }
+
+        drmModeFreeProperty(prop);
+    }
+
+    return valid_mask;
+}
+
+static Bool
+drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
+		       const drmmode_prop_info_rec *src,
+		       unsigned int num_props,
+		       Bool copy_prop_id)
+{
+    unsigned int i;
+
+    memcpy(dst, src, num_props * sizeof(*dst));
+
+    for (i = 0; i < num_props; i++) {
+        unsigned int j;
+
+        if (copy_prop_id)
+            dst[i].prop_id = src[i].prop_id;
+        else
+            dst[i].prop_id = 0;
+
+        if (src[i].num_enum_values == 0)
+            continue;
+
+        dst[i].enum_values =
+            malloc(src[i].num_enum_values *
+                    sizeof(*dst[i].enum_values));
+        if (!dst[i].enum_values)
+            goto err;
+
+        memcpy(dst[i].enum_values, src[i].enum_values,
+                src[i].num_enum_values * sizeof(*dst[i].enum_values));
+
+        for (j = 0; j < dst[i].num_enum_values; j++)
+            dst[i].enum_values[j].valid = FALSE;
+    }
+
+    return TRUE;
+
+err:
+    while (i--)
+        free(dst[i].enum_values);
+    free(dst);
+    return FALSE;
+}
+
+static void
+drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
+{
+    int i;
+
+    for (i = 0; i < num_props; i++)
+        free(info[i].enum_values);
+}
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static int
+plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+               enum drmmode_plane_property prop, uint64_t val)
+{
+    drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
+    int ret;
+
+    if (!info)
+        return -1;
+
+    ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
+                                   info->prop_id, val);
+    return (ret <= 0) ? -1 : 0;
+}
+#endif
+
+int
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+                    int x, int y, uint32_t flags, void *data)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    int ret = 0;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    if (ms->atomic_modeset) {
+        drmModeAtomicReq *req = drmModeAtomicAlloc();
+
+        if (!req)
+            return 1;
+
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
+                              fb_id);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
+                              drmmode_crtc->mode_crtc->crtc_id);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
+        ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+
+        if (ret == 0)
+            ret = drmModeAtomicCommit(ms->fd, req, flags, data);
+
+        drmModeAtomicFree(req);
+        return ret;
+    }
+#endif
+
+    return 0;
+}
+
+
 int
 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
 {
@@ -1076,6 +1303,14 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
     }
 }
 
+static void
+drmmode_crtc_destroy(xf86CrtcPtr crtc)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+}
+
 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
     .dpms = drmmode_crtc_dpms,
     .set_mode_major = drmmode_set_mode_major,
@@ -1086,7 +1321,7 @@ static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
     .load_cursor_argb_check = drmmode_load_cursor_argb_check,
 
     .gamma_set = drmmode_crtc_gamma_set,
-    .destroy = NULL,            /* XXX */
+    .destroy = drmmode_crtc_destroy,
     .set_scanout_pixmap = drmmode_set_scanout_pixmap,
     .shadow_allocate = drmmode_shadow_allocate,
     .shadow_create = drmmode_shadow_create,
@@ -1104,6 +1339,136 @@ drmmode_crtc_vblank_pipe(int crtc_id)
         return 0;
 }
 
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static Bool
+is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    int c;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr iter = xf86_config->crtc[c];
+        drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
+        if (drmmode_crtc->plane_id == plane_id)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void
+drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    drmmode_ptr drmmode = drmmode_crtc->drmmode;
+    drmModePlaneRes *kplane_res;
+    drmModePlane *kplane;
+    drmModeObjectProperties *props;
+    uint32_t i, type;
+    int current_crtc, best_plane = 0;
+
+    static drmmode_prop_enum_info_rec plane_type_enums[] = {
+        [DRMMODE_PLANE_TYPE_PRIMARY] = {
+            .name = "Primary",
+        },
+        [DRMMODE_PLANE_TYPE_OVERLAY] = {
+            .name = "Overlay",
+        },
+        [DRMMODE_PLANE_TYPE_CURSOR] = {
+            .name = "Cursor",
+        },
+    };
+    static const drmmode_prop_info_rec plane_props[] = {
+        [DRMMODE_PLANE_TYPE] = {
+            .name = "type",
+            .enum_values = plane_type_enums,
+            .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
+        },
+        [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
+        [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+        [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
+        [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+    };
+    drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
+
+    if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
+        xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+                   "failed to copy plane property info\n");
+        drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+        return;
+    }
+
+    kplane_res = drmModeGetPlaneResources(drmmode->fd);
+    if (!kplane_res) {
+        xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+                   "failed to get plane resources: %s\n", strerror(errno));
+        drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+        return;
+    }
+
+    for (i = 0; i < kplane_res->count_planes; i++) {
+        int plane_id;
+
+        kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
+        if (!kplane)
+            continue;
+
+        if (!(kplane->possible_crtcs & (1 << num)) ||
+            is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
+            drmModeFreePlane(kplane);
+            continue;
+        }
+
+        plane_id = kplane->plane_id;
+        drmModeFreePlane(kplane);
+
+        props = drmModeObjectGetProperties(drmmode->fd, plane_id,
+                                           DRM_MODE_OBJECT_PLANE);
+        if (!props) {
+            xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+                    "couldn't get plane properties\n");
+            continue;
+        }
+
+        drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
+
+        /* Only primary planes are important for atomic page-flipping */
+        type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
+                                      props, DRMMODE_PLANE_TYPE__COUNT);
+        if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+            drmModeFreeObjectProperties(props);
+            continue;
+        }
+
+        /* Check if plane is already on this CRTC */
+        current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
+                                              props, 0);
+        if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
+            if (best_plane)
+                drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+            best_plane = plane_id;
+            drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+                                   DRMMODE_PLANE__COUNT, 1);
+            drmModeFreeObjectProperties(props);
+            break;
+        }
+
+        if (!best_plane) {
+            best_plane = plane_id;
+            drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+                                   DRMMODE_PLANE__COUNT, 1);
+        }
+
+        drmModeFreeObjectProperties(props);
+    }
+
+    drmmode_crtc->plane_id = best_plane;
+
+    drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+    drmModeFreePlaneResources(kplane_res);
+}
+#endif
+
 static unsigned int
 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
 {
@@ -1122,6 +1487,10 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
     crtc->driver_private = drmmode_crtc;
 
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    drmmode_crtc_create_planes(crtc, num);
+#endif
+
     /* Hide any cursors which may be active from previous users */
     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
 
@@ -1477,7 +1846,8 @@ drmmode_property_ignore(drmModePropertyPtr prop)
     if (prop->flags & DRM_MODE_PROP_BLOB)
         return TRUE;
     /* ignore standard property */
-    if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
+    if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
+        !strcmp(prop->name, "CRTC_ID"))
         return TRUE;
 
     return FALSE;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 267040918..1f24c3a5b 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -36,6 +36,22 @@
 
 struct gbm_device;
 
+enum drmmode_plane_property {
+    DRMMODE_PLANE_TYPE = 0,
+    DRMMODE_PLANE_FB_ID,
+    DRMMODE_PLANE_CRTC_ID,
+    DRMMODE_PLANE_SRC_X,
+    DRMMODE_PLANE_SRC_Y,
+    DRMMODE_PLANE__COUNT
+};
+
+enum drmmode_plane_type {
+    DRMMODE_PLANE_TYPE_PRIMARY = 0,
+    DRMMODE_PLANE_TYPE_CURSOR,
+    DRMMODE_PLANE_TYPE_OVERLAY,
+    DRMMODE_PLANE_TYPE__COUNT
+};
+
 typedef struct {
     struct dumb_bo *dumb;
 #ifdef GLAMOR_HAS_GBM
@@ -89,6 +105,19 @@ typedef struct {
 } drmmode_rec, *drmmode_ptr;
 
 typedef struct {
+    const char *name;
+    Bool valid;
+    uint64_t value;
+} drmmode_prop_enum_info_rec, *drmmode_prop_enum_info_ptr;
+
+typedef struct {
+    const char *name;
+    uint32_t prop_id;
+    unsigned int num_enum_values;
+    drmmode_prop_enum_info_rec *enum_values;
+} drmmode_prop_info_rec, *drmmode_prop_info_ptr;
+
+typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     uint32_t vblank_pipe;
@@ -97,6 +126,9 @@ typedef struct {
     Bool cursor_up;
     uint16_t lut_r[256], lut_g[256], lut_b[256];
 
+    drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
+    uint32_t plane_id;
+
     drmmode_bo rotate_bo;
     unsigned rotate_fb_id;
 
@@ -205,6 +237,10 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
                              int *depth, int *bpp);
 
 void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
+
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+                        int x, int y, uint32_t flags, void *data);
+
 #ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
 #define DRM_CAP_DUMB_PREFERRED_DEPTH 3
 #endif
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index d5fd0625b..dd296cd12 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -160,6 +160,25 @@ ms_pageflip_abort(void *data)
 }
 
 static Bool
+do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
+                      uint32_t flags, uint32_t seq)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+    if (ms->atomic_modeset) {
+        flags |= DRM_MODE_ATOMIC_NONBLOCK;
+        return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+                                   (void *) (uintptr_t) seq);
+    }
+#endif
+
+    return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
+                           ms->drmmode.fb_id, flags,
+                           (void *) (uintptr_t) seq);
+}
+
+static Bool
 queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
                    struct ms_flipdata *flipdata,
                    int ref_crtc_vblank_pipe, uint32_t flags)
@@ -193,8 +212,7 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
     /* take a reference on flipdata for use in flip */
     flipdata->flip_count++;
 
-    while (drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
-                           ms->drmmode.fb_id, flags, (void *) (uintptr_t) seq)) {
+    while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
         err = errno;
         /* We may have failed because the event queue was full.  Flush it
          * and retry.  If there was nothing to flush, then we failed for
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index f12df74da..9f8dc913f 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -491,6 +491,9 @@
 /* Build glamor use new drmGetDeviceNameFromFD2 */
 #undef GLAMOR_HAS_DRM_NAME_FROM_FD_2
 
+/* Glamor should use atomic DRM API */
+#undef GLAMOR_HAS_DRM_ATOMIC
+
 /* byte order */
 #undef X_BYTE_ORDER
 
diff --git a/include/meson.build b/include/meson.build
index 25239ad74..88d96cacc 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -73,6 +73,8 @@ conf_data.set_quoted('SHMDIR', '/tmp')
 
 conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found())
 conf_data.set('WITH_LIBDRM', libdrm_dep.found())
+conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
+              libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
 conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
               libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
 conf_data.set('GLXEXT', build_glx)
commit e2ef3b44fa697f2ed453767e98da72ea56d4046f
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:36 2018 +0000

    present: Send PresentCompleteModeSuboptimalCopy appropriately
    
    Add 'check_flip2' hook for driver to let know the core
    about why flipping is not possible ('reason').
    If it is because of unsupported buffer format/modifier,
    a PresentCompleteNotify event is sent to the client with
    the PresentCompleteModeSuboptimalCopy mode.
    
    v2: Check for PresentOptionSuboptimal and check driver version
        before using 'check_flip2'.
    
    v3: Only require one of 'check_flip' or 'check_flip2' to be
        implemented by the driver.
        Refactor reasons list to enum
    
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Reviewed-by: Daniel Stone <daniels at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 47bf17452..e1ca8f974 100644
--- a/configure.ac
+++ b/configure.ac
@@ -753,7 +753,7 @@ DAMAGEPROTO="damageproto >= 1.1"
 XCMISCPROTO="xcmiscproto >= 1.2.0"
 BIGREQSPROTO="bigreqsproto >= 1.1.0"
 XTRANS="xtrans >= 1.3.5"
-PRESENTPROTO="presentproto >= 1.0"
+PRESENTPROTO="presentproto >= 1.1"
 
 dnl List of libraries that require a specific version
 LIBAPPLEWM="applewm >= 1.4"
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 938b9caa4..39cd2e909 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -69,7 +69,7 @@
 
 /* Present */
 #define SERVER_PRESENT_MAJOR_VERSION            1
-#define SERVER_PRESENT_MINOR_VERSION            0
+#define SERVER_PRESENT_MINOR_VERSION            1
 
 /* RandR */
 #define SERVER_RANDR_MAJOR_VERSION		1
diff --git a/present/meson.build b/present/meson.build
index a4296ca7a..cf725302a 100644
--- a/present/meson.build
+++ b/present/meson.build
@@ -13,7 +13,7 @@ libxserver_present = static_library('libxserver_present',
     include_directories: inc,
     dependencies: [
         common_dep,
-        dependency('presentproto', version: '>= 1.0')
+        dependency('presentproto', version: '>= 1.1')
     ],
     c_args: '-DHAVE_XORG_CONFIG_H'
 )
diff --git a/present/present.c b/present/present.c
index 176e89c0b..42e5fb4fc 100644
--- a/present/present.c
+++ b/present/present.c
@@ -118,19 +118,23 @@ present_flip_pending_pixmap(ScreenPtr screen)
 }
 
 static Bool
-present_check_flip(RRCrtcPtr    crtc,
-                   WindowPtr    window,
-                   PixmapPtr    pixmap,
-                   Bool         sync_flip,
-                   RegionPtr    valid,
-                   int16_t      x_off,
-                   int16_t      y_off)
+present_check_flip(RRCrtcPtr            crtc,
+                   WindowPtr            window,
+                   PixmapPtr            pixmap,
+                   Bool                 sync_flip,
+                   RegionPtr            valid,
+                   int16_t              x_off,
+                   int16_t              y_off,
+                   PresentFlipReason   *reason)
 {
     ScreenPtr                   screen = window->drawable.pScreen;
     PixmapPtr                   window_pixmap;
     WindowPtr                   root = screen->root;
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
 
+    if (reason)
+        *reason = PRESENT_FLIP_REASON_UNKNOWN;
+
     if (!screen_priv)
         return FALSE;
 
@@ -177,7 +181,12 @@ present_check_flip(RRCrtcPtr    crtc,
     }
 
     /* Ask the driver for permission */
-    if (screen_priv->info->check_flip) {
+    if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
+        if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
+            DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
+            return FALSE;
+        }
+    } else if (screen_priv->info->check_flip) {
         if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
             DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
             return FALSE;
@@ -564,6 +573,7 @@ present_check_flip_window (WindowPtr window)
     present_window_priv_ptr     window_priv = present_window_priv(window);
     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
     present_vblank_ptr          vblank;
+    PresentFlipReason           reason;
 
     /* If this window hasn't ever been used with Present, it can't be
      * flipping
@@ -580,7 +590,7 @@ present_check_flip_window (WindowPtr window)
          */
         if (flip_pending->window == window) {
             if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
-                                    flip_pending->sync_flip, NULL, 0, 0))
+                                    flip_pending->sync_flip, NULL, 0, 0, NULL))
                 present_set_abort_flip(screen);
         }
     } else {
@@ -588,15 +598,16 @@ present_check_flip_window (WindowPtr window)
          * Check current flip
          */
         if (window == screen_priv->flip_window) {
-            if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0))
+            if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
                 present_unflip(screen);
         }
     }
 
     /* Now check any queued vblanks */
     xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
-        if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) {
+        if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
             vblank->flip = FALSE;
+            vblank->reason = reason;
             if (vblank->sync_flip)
                 vblank->requeue = TRUE;
         }
@@ -756,10 +767,14 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
     /* Compute correct CompleteMode
      */
     if (vblank->kind == PresentCompleteKindPixmap) {
-        if (vblank->pixmap && vblank->window)
-            mode = PresentCompleteModeCopy;
-        else
+        if (vblank->pixmap && vblank->window) {
+            if (vblank->has_suboptimal && vblank->reason == PRESENT_FLIP_REASON_BUFFER_FORMAT)
+                mode = PresentCompleteModeSuboptimalCopy;
+            else
+                mode = PresentCompleteModeCopy;
+        } else {
             mode = PresentCompleteModeSkip;
+        }
     }
     else
         mode = PresentCompleteModeCopy;
@@ -795,6 +810,7 @@ present_pixmap(WindowPtr window,
     ScreenPtr                   screen = window->drawable.pScreen;
     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    PresentFlipReason           reason = PRESENT_FLIP_REASON_UNKNOWN;
 
     if (!window_priv)
         return BadAlloc;
@@ -912,22 +928,24 @@ present_pixmap(WindowPtr window,
     vblank->msc_offset = window_priv->msc_offset;
     vblank->notifies = notifies;
     vblank->num_notifies = num_notifies;
+    vblank->has_suboptimal = (options & PresentOptionSuboptimal);
 
     if (pixmap != NULL &&
         !(options & PresentOptionCopy) &&
         screen_priv->info) {
         if (msc_is_after(target_msc, crtc_msc) &&
-            present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off))
+            present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
         {
             vblank->flip = TRUE;
             vblank->sync_flip = TRUE;
             target_msc--;
         } else if ((screen_priv->info->capabilities & PresentCapabilityAsync) &&
-            present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off))
+            present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
         {
             vblank->flip = TRUE;
         }
     }
+    vblank->reason = reason;
 
     if (wait_fence) {
         vblank->wait_fence = present_fence_create(wait_fence);
diff --git a/present/present.h b/present/present.h
index aab2e168a..6542dc385 100644
--- a/present/present.h
+++ b/present/present.h
@@ -27,6 +27,11 @@
 #include "randrstr.h"
 #include "presentext.h"
 
+typedef enum {
+    PRESENT_FLIP_REASON_UNKNOWN,
+    PRESENT_FLIP_REASON_BUFFER_FORMAT
+} PresentFlipReason;
+
 typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
 
 /* Return the current CRTC for 'window'.
@@ -59,6 +64,10 @@ typedef void (*present_flush_ptr) (WindowPtr window);
  */
 typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);
 
+/* Same as 'check_flip' but it can return a 'reason' why the flip would fail.
+ */
+typedef Bool (*present_check_flip2_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip, PresentFlipReason *reason);
+
 /* Flip pixmap, return false if it didn't happen.
  *
  * 'crtc' is to be used for any necessary synchronization.
@@ -83,7 +92,7 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
 typedef void (*present_unflip_ptr) (ScreenPtr screen,
                                     uint64_t event_id);
 
-#define PRESENT_SCREEN_INFO_VERSION        0
+#define PRESENT_SCREEN_INFO_VERSION        1
 
 typedef struct present_screen_info {
     uint32_t                            version;
@@ -97,6 +106,7 @@ typedef struct present_screen_info {
     present_check_flip_ptr              check_flip;
     present_flip_ptr                    flip;
     present_unflip_ptr                  unflip;
+    present_check_flip2_ptr             check_flip2;
 
 } present_screen_info_rec, *present_screen_info_ptr;
 
diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bdea9..6980ddd11 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -75,6 +75,8 @@ struct present_vblank {
     Bool                flip_ready;     /* wants to flip, but waiting for previous flip or unflip */
     Bool                sync_flip;      /* do flip synchronous to vblank */
     Bool                abort_flip;     /* aborting this flip */
+    PresentFlipReason   reason;         /* reason for which flip is not possible */
+    Bool                has_suboptimal; /* whether client can support SuboptimalCopy mode */
 };
 
 typedef struct present_screen_priv {
commit 6e7c40f62db66f5b59b2cf59f1e6a26e4fd21bda
Author: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Date:   Wed Feb 28 01:19:35 2018 +0000

    dri3: Add multi-planar/modifier buffer requests
    
    Initial implementation for DRI3 v1.1. Only the DRI3 implementation
    is there, backends need to implement the proper hooks.
    
    Version is still set to 1.0 so clients shouldn't use the new
    requests yet.
    
    v2: Use depth/bpp instead of DRM formats in requests
    
    v3: Remove DMA fence requests from v1.1
        Add screen/drawable modifier sets
    
    v4: Free array returned by 'get_drawable_modifiers()'
    
    v5: Fix FD leak
    
    Signed-off-by: Daniel Stone <daniels at collabora.com>
    Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
    Acked-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 0ba7550a1..47bf17452 100644
--- a/configure.ac
+++ b/configure.ac
@@ -729,7 +729,7 @@ SCRNSAVERPROTO="scrnsaverproto >= 1.1"
 RESOURCEPROTO="resourceproto >= 1.2.0"
 DRIPROTO="xf86driproto >= 2.1.0"
 DRI2PROTO="dri2proto >= 2.8"
-DRI3PROTO="dri3proto >= 1.0"
+DRI3PROTO="dri3proto >= 1.2"
 XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 DGAPROTO="xf86dgaproto >= 2.0.99.1"
diff --git a/dri3/dri3.c b/dri3/dri3.c
index d042b8b7d..8ac0f3ae2 100644
--- a/dri3/dri3.c
+++ b/dri3/dri3.c
@@ -26,6 +26,8 @@
 
 #include "dri3_priv.h"
 
+#include <drm_fourcc.h>
+
 static int dri3_request;
 DevPrivateKeyRec dri3_screen_private_key;
 
@@ -99,3 +101,20 @@ dri3_extension_init(void)
 bail:
     FatalError("Cannot initialize DRI3 extension");
 }
+
+uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp)
+{
+    switch (bpp) {
+        case 16:
+            return DRM_FORMAT_RGB565;
+        case 24:
+            return DRM_FORMAT_XRGB8888;
+        case 30:
+            return DRM_FORMAT_XRGB2101010;
+        case 32:
+            return DRM_FORMAT_ARGB8888;
+        default:
+            return 0;
+    }
+}
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..89ad13ad9 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,7 @@
 #include <X11/extensions/dri3proto.h>
 #include <randrstr.h>
 
-#define DRI3_SCREEN_INFO_VERSION        1
+#define DRI3_SCREEN_INFO_VERSION        2
 
 typedef int (*dri3_open_proc)(ScreenPtr screen,
                               RRProviderPtr provider,
@@ -47,11 +47,43 @@ typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
                                                CARD8 depth,
                                                CARD8 bpp);
 
+typedef PixmapPtr (*dri3_pixmap_from_fds_proc) (ScreenPtr screen,
+                                                CARD8 num_fds,
+                                                int *fds,
+                                                CARD16 width,
+                                                CARD16 height,
+                                                CARD32 *strides,
+                                                CARD32 *offsets,
+                                                CARD8 depth,
+                                                CARD8 bpp,
+                                                CARD64 modifier);
+
 typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
                                          PixmapPtr pixmap,
                                          CARD16 *stride,
                                          CARD32 *size);
 
+typedef int (*dri3_fds_from_pixmap_proc) (ScreenPtr screen,
+                                          PixmapPtr pixmap,
+                                          int *fds,
+                                          CARD32 *strides,
+                                          CARD32 *offsets,
+                                          CARD64 *modifier);
+
+typedef int (*dri3_get_formats_proc) (ScreenPtr screen,
+                                      CARD32 *num_formats,
+                                      CARD32 **formats);
+
+typedef int (*dri3_get_modifiers_proc) (ScreenPtr screen,
+                                        CARD32 format,
+                                        CARD32 *num_modifiers,
+                                        CARD64 **modifiers);
+
+typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw,
+                                                 CARD32 format,
+                                                 CARD32 *num_modifiers,
+                                                 CARD64 **modifiers);
+
 typedef struct dri3_screen_info {
     uint32_t                    version;
 
@@ -62,6 +94,13 @@ typedef struct dri3_screen_info {
     /* Version 1 */
     dri3_open_client_proc       open_client;
 
+    /* Version 2 */
+    dri3_pixmap_from_fds_proc   pixmap_from_fds;
+    dri3_fds_from_pixmap_proc   fds_from_pixmap;
+    dri3_get_formats_proc       get_formats;
+    dri3_get_modifiers_proc     get_modifiers;
+    dri3_get_drawable_modifiers_proc get_drawable_modifiers;
+
 } dri3_screen_info_rec, *dri3_screen_info_ptr;
 
 extern _X_EXPORT Bool
@@ -70,6 +109,9 @@ dri3_screen_init(ScreenPtr screen, dri3_screen_info_ptr info);
 extern _X_EXPORT int
 dri3_send_open_reply(ClientPtr client, int fd);
 
+extern _X_EXPORT uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp);
+
 #endif
 
 #endif /* _DRI3_H_ */
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..8447680ba 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,21 @@
 
 extern DevPrivateKeyRec dri3_screen_private_key;
 
+typedef struct dri3_dmabuf_format {
+    uint32_t                    format;
+    uint32_t                    num_modifiers;
+    uint64_t                   *modifiers;
+} dri3_dmabuf_format_rec, *dri3_dmabuf_format_ptr;
+
 typedef struct dri3_screen_priv {
     CloseScreenProcPtr          CloseScreen;
     ConfigNotifyProcPtr         ConfigNotify;
     DestroyWindowProcPtr        DestroyWindow;
 
+    Bool                        formats_cached;
+    CARD32                      num_formats;
+    dri3_dmabuf_format_ptr      formats;
+
     dri3_screen_info_ptr        info;
 } dri3_screen_priv_rec, *dri3_screen_priv_ptr;
 
@@ -69,10 +79,21 @@ int
 dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd);
 
 int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
-                    CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp);
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, int *fds,
+                     CARD16 width, CARD16 height, CARD32 *strides, CARD32 *offsets,
+                     CARD8 depth, CARD8 bpp, CARD64 modifier);
+
+int
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD64 *modifier);
 
 int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+                             CARD8 depth, CARD8 bpp,
+                             CARD32 *num_drawable_modifiers,
+                             CARD64 **drawable_modifiers,
+                             CARD32 *num_screen_modifiers,
+                             CARD64 **screen_modifiers);
 
 #endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index b28d883a5..7f3f0d08c 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -30,6 +30,7 @@
 #include <xace.h>
 #include "../Xext/syncsdk.h"
 #include <protocol-versions.h>
+#include <drm_fourcc.h>
 
 static int
 proc_dri3_query_version(ClientPtr client)
@@ -124,6 +125,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
     int fd;
     DrawablePtr drawable;
     PixmapPtr pixmap;
+    CARD32 stride, offset;
     int rc;
 
     SetReqFds(client, 1);
@@ -159,11 +161,14 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
     if (fd < 0)
         return BadValue;
 
-    rc = dri3_pixmap_from_fd(&pixmap,
-                             drawable->pScreen, fd,
-                             stuff->width, stuff->height,
-                             stuff->stride, stuff->depth,
-                             stuff->bpp);
+    offset = 0;
+    stride = stuff->stride;
+    rc = dri3_pixmap_from_fds(&pixmap,
+                              drawable->pScreen, 1, &fd,
+                              stuff->width, stuff->height,
+                              &stride, &offset,
+                              stuff->depth, stuff->bpp,
+                              DRM_FORMAT_MOD_INVALID);
     close (fd);
     if (rc != Success)
         return rc;
@@ -195,7 +200,10 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         .length = 0,
     };
     int rc;
-    int fd;
+    int num_fds;
+    int fds[4];
+    uint32_t strides[4], offsets[4];
+    uint64_t modifier;
     PixmapPtr pixmap;
 
     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -211,9 +219,12 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
     rep.depth = pixmap->drawable.depth;
     rep.bpp = pixmap->drawable.bitsPerPixel;
 
-    rc = dri3_fd_from_pixmap(&fd, pixmap, &rep.stride, &rep.size);
-    if (rc != Success)
-        return rc;
+    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+    if (num_fds != 1)
+        return BadPixmap;
+
+    rep.stride = (CARD16) strides[0];
+    rep.size = rep.stride * rep.height;
 
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
@@ -223,8 +234,8 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
         swaps(&rep.height);
         swaps(&rep.stride);
     }
-    if (WriteFdToClient(client, fd, TRUE) < 0) {
-        close(fd);
+    if (WriteFdToClient(client, fds[0], TRUE) < 0) {
+        close(fds[0]);
         return BadAlloc;
     }
 
@@ -299,6 +310,216 @@ proc_dri3_fd_from_fence(ClientPtr client)
     return Success;
 }
 
+static int
+proc_dri3_get_supported_modifiers(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedModifiersReq);
+    xDRI3GetSupportedModifiersReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+    };
+    WindowPtr window;
+    ScreenPtr pScreen;
+    CARD64 *window_modifiers = NULL;
+    CARD64 *screen_modifiers = NULL;
+    CARD32 nwindowmodifiers = 0;
+    CARD32 nscreenmodifiers = 0;
+    int status;
+    int i;
+
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+    status = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
+    if (status != Success)
+        return status;
+    pScreen = window->drawable.pScreen;
+
+    dri3_get_supported_modifiers(pScreen, &window->drawable,
+				 stuff->depth, stuff->bpp,
+                                 &nwindowmodifiers, &window_modifiers,
+                                 &nscreenmodifiers, &screen_modifiers);
+
+    rep.numWindowModifiers = nwindowmodifiers;
+    rep.numScreenModifiers = nscreenmodifiers;
+    rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) +
+                 bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.numWindowModifiers);
+        swapl(&rep.numScreenModifiers);
+        for (i = 0; i < nwindowmodifiers; i++)
+            swapll(&window_modifiers[i]);
+        for (i = 0; i < nscreenmodifiers; i++)
+            swapll(&screen_modifiers[i]);
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+    WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers);
+    WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
+
+    free(window_modifiers);
+    free(screen_modifiers);
+
+    return Success;
+}
+
+static int
+proc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+    REQUEST(xDRI3PixmapFromBuffersReq);
+    int fds[4];
+    CARD32 strides[4], offsets[4];
+    ScreenPtr screen;
+    WindowPtr window;
+    PixmapPtr pixmap;
+    int rc;
+    int i;
+
+    SetReqFds(client, stuff->num_buffers);
+    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
+    rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+    if (rc != Success) {
+        client->errorValue = stuff->window;
+        return rc;
+    }
+    screen = window->drawable.pScreen;
+
+    if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
+        client->errorValue = 0;
+        return BadValue;
+    }
+
+    if (stuff->width > 32767 || stuff->height > 32767)
+        return BadAlloc;
+
+    if (stuff->depth != 1) {
+        DepthPtr depth = screen->allowedDepths;
+        int j;
+        for (j = 0; j < screen->numDepths; j++, depth++)
+            if (depth->depth == stuff->depth)
+                break;
+        if (j == screen->numDepths) {
+            client->errorValue = stuff->depth;
+            return BadValue;
+        }
+    }
+
+    if (!stuff->num_buffers || stuff->num_buffers > 4) {
+        client->errorValue = stuff->num_buffers;
+        return BadValue;
+    }
+
+    for (i = 0; i < stuff->num_buffers; i++) {
+        fds[i] = ReadFdFromClient(client);
+        if (fds[i] < 0) {
+            while (--i >= 0)
+                close(fds[i]);
+            return BadValue;
+        }
+    }
+
+    strides[0] = stuff->stride0;
+    strides[1] = stuff->stride1;
+    strides[2] = stuff->stride2;
+    strides[3] = stuff->stride3;
+    offsets[0] = stuff->offset0;
+    offsets[1] = stuff->offset1;
+    offsets[2] = stuff->offset2;
+    offsets[3] = stuff->offset3;
+
+    rc = dri3_pixmap_from_fds(&pixmap, screen,
+                              stuff->num_buffers, fds,
+                              stuff->width, stuff->height,
+                              strides, offsets,
+                              stuff->depth, stuff->bpp,
+                              stuff->modifier);
+
+    for (i = 0; i < stuff->num_buffers; i++)
+        close (fds[i]);
+
+    if (rc != Success)
+        return rc;
+
+    pixmap->drawable.id = stuff->pixmap;
+
+    /* security creation/labeling check */
+    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
+                  pixmap, RT_NONE, NULL, DixCreateAccess);
+
+    if (rc != Success) {
+        (*screen->DestroyPixmap) (pixmap);
+        return rc;
+    }
+    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
+        return BadAlloc;
+
+    return Success;
+}
+
+static int
+proc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+    REQUEST(xDRI3BuffersFromPixmapReq);
+    xDRI3BuffersFromPixmapReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+    };
+    int rc;
+    int fds[4];
+    int num_fds;
+    uint32_t strides[4], offsets[4];
+    uint64_t modifier;
+    int i;
+    PixmapPtr pixmap;
+
+    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
+    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
+                                 client, DixWriteAccess);
+    if (rc != Success) {
+        client->errorValue = stuff->pixmap;
+        return rc;
+    }
+
+    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+    if (num_fds == 0)
+        return BadPixmap;
+
+    rep.nfd = num_fds;
+    rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
+    rep.width = pixmap->drawable.width;
+    rep.height = pixmap->drawable.height;
+    rep.modifier = modifier;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swaps(&rep.width);
+        swaps(&rep.height);
+        swapll(&rep.modifier);
+        for (i = 0; i < num_fds; i++) {
+            swapl(&strides[i]);
+            swapl(&offsets[i]);
+        }
+    }
+
+    for (i = 0; i < num_fds; i++) {
+        if (WriteFdToClient(client, fds[i], TRUE) < 0) {
+            while (i--)
+                close(fds[i]);
+            return BadAlloc;
+        }
+    }
+
+    WriteToClient(client, sizeof(rep), &rep);
+    WriteToClient(client, num_fds * sizeof(CARD32), strides);
+    WriteToClient(client, num_fds * sizeof(CARD32), offsets);
+
+    return Success;
+}
+
 int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     proc_dri3_query_version,            /* 0 */
     proc_dri3_open,                     /* 1 */
@@ -306,6 +527,9 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     proc_dri3_buffer_from_pixmap,       /* 3 */
     proc_dri3_fence_from_fd,            /* 4 */
     proc_dri3_fd_from_fence,            /* 5 */
+    proc_dri3_get_supported_modifiers,  /* 6 */
+    proc_dri3_pixmap_from_buffers,      /* 7 */
+    proc_dri3_buffers_from_pixmap,      /* 8 */
 };
 
 int
@@ -394,6 +618,51 @@ sproc_dri3_fd_from_fence(ClientPtr client)
     return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
 }
 
+static int _X_COLD
+sproc_dri3_get_supported_modifiers(ClientPtr client)
+{
+    REQUEST(xDRI3GetSupportedModifiersReq);
+    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+    REQUEST(xDRI3PixmapFromBuffersReq);
+    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->pixmap);
+    swapl(&stuff->window);
+    swaps(&stuff->width);
+    swaps(&stuff->height);
+    swapl(&stuff->stride0);
+    swapl(&stuff->offset0);
+    swapl(&stuff->stride1);
+    swapl(&stuff->offset1);
+    swapl(&stuff->stride2);
+    swapl(&stuff->offset2);
+    swapl(&stuff->stride3);
+    swapl(&stuff->offset3);
+    swapll(&stuff->modifier);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+    REQUEST(xDRI3BuffersFromPixmapReq);
+    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
+
+    swaps(&stuff->length);
+    swapl(&stuff->pixmap);
+    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
 int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     sproc_dri3_query_version,           /* 0 */
     sproc_dri3_open,                    /* 1 */
@@ -401,6 +670,9 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
     sproc_dri3_buffer_from_pixmap,      /* 3 */
     sproc_dri3_fence_from_fd,           /* 4 */
     sproc_dri3_fd_from_fence,           /* 5 */
+    sproc_dri3_get_supported_modifiers, /* 6 */
+    sproc_dri3_pixmap_from_buffers,     /* 7 */
+    sproc_dri3_buffers_from_pixmap,     /* 8 */
 };
 
 int _X_COLD
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..df40f8281 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -29,6 +29,7 @@
 #include <misync.h>
 #include <misyncshm.h>
 #include <randrstr.h>
+#include <drm_fourcc.h>
 
 static inline Bool has_open(dri3_screen_info_ptr info) {
     if (info == NULL)
@@ -60,17 +61,30 @@ dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
 }
 
 int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
-                    CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
+                     CARD8 num_fds, int *fds,
+                     CARD16 width, CARD16 height,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD8 depth, CARD8 bpp, CARD64 modifier)
 {
     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
     dri3_screen_info_ptr        info = ds->info;
     PixmapPtr                   pixmap;
 
-    if (!info || !info->pixmap_from_fd)
+    if (!info)
         return BadImplementation;
 
-    pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+    if (info->version >= 2 && info->pixmap_from_fds != NULL) {
+        pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+                                           strides, offsets, depth, bpp, modifier);
+    } else if (info->pixmap_from_fd != NULL && num_fds == 1 &&
+               modifier == DRM_FORMAT_MOD_INVALID) {
+        pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
+                                          strides[0], depth, bpp);
+    } else {
+        return BadImplementation;
+    }
+
     if (!pixmap)
         return BadAlloc;
 
@@ -79,20 +93,182 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
 }
 
 int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+                     CARD32 *strides, CARD32 *offsets,
+                     CARD64 *modifier)
 {
     ScreenPtr                   screen = pixmap->drawable.pScreen;
     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
     dri3_screen_info_ptr        info = ds->info;
-    int                         fd;
 
-    if (!info || !info->fd_from_pixmap)
+    if (!info)
+        return 0;
+
+    if (info->version >= 2 && info->fds_from_pixmap != NULL) {
+        return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
+                                        modifier);
+    } else if (info->fd_from_pixmap != NULL) {
+        CARD16 stride;
+        CARD32 size;
+
+        fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
+        if (fds[0] < 0)
+            return 0;
+
+        strides[0] = stride;
+        offsets[0] = 0;
+        *modifier = DRM_FORMAT_MOD_INVALID;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int
+cache_formats_and_modifiers(ScreenPtr screen)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    dri3_screen_info_ptr        info = ds->info;
+    CARD32                     *formats = NULL;
+    CARD64                     *modifiers = NULL;
+    int                         i;
+
+    if (ds->formats_cached)
+        return Success;
+
+    if (!info)
         return BadImplementation;
 
-    fd = (*info->fd_from_pixmap)(screen, pixmap, stride, size);
-    if (fd < 0)
+    if (!info->get_formats || !info->get_modifiers) {
+        ds->formats = NULL;
+        ds->num_formats = 0;
+        ds->formats_cached = TRUE;
+        return Success;
+    }
+
+    (*info->get_formats) (screen, &ds->num_formats, &formats);
+    ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+    if (!ds->formats)
         return BadAlloc;
-    *pfd = fd;
+
+    for (i = 0; i < ds->num_formats; i++) {
+        dri3_dmabuf_format_ptr iter = &ds->formats[i];
+
+        iter->format = formats[i];
+        (*info->get_modifiers) (screen, formats[i],
+                                &iter->num_modifiers,
+                                &modifiers);
+
+        iter->modifiers = malloc(iter->num_modifiers * sizeof(CARD64));
+        if (iter->modifiers == NULL)
+            goto error;
+
+        memcpy(iter->modifiers, modifiers,
+               iter->num_modifiers * sizeof(CARD64));
+        goto done;
+
+error:
+        iter->num_modifiers = 0;
+        free(iter->modifiers);
+done:
+        free(modifiers);
+    }
+    free(formats);
+    ds->formats_cached = TRUE;
+
     return Success;
 }
 
+int
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+                             CARD8 depth, CARD8 bpp,
+                             CARD32 *num_intersect_modifiers,
+                             CARD64 **intersect_modifiers,
+                             CARD32 *num_screen_modifiers,
+                             CARD64 **screen_modifiers)
+{
+    dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
+    dri3_screen_info_ptr        info = ds->info;
+    int                         i, j;
+    int                         ret;
+    CARD32                      num_drawable_mods;
+    CARD64                     *drawable_mods;
+    CARD64                     *intersect_mods = NULL;
+    CARD64                     *screen_mods = NULL;
+    CARD32                      format;
+    dri3_dmabuf_format_ptr      screen_format = NULL;
+
+    ret = cache_formats_and_modifiers(screen);
+    if (ret != Success)
+        return ret;
+
+    format = drm_format_for_depth(depth, bpp);
+    if (format == 0)
+        return BadValue;
+
+    /* Find screen-global modifiers from cache
+     */
+    for (i = 0; i < ds->num_formats; i++) {
+        if (ds->formats[i].format == format) {
+            screen_format = &ds->formats[i];
+            break;
+        }
+    }
+    if (screen_format == NULL)
+        return BadMatch;
+
+    if (screen_format->num_modifiers == 0) {
+        *num_screen_modifiers = 0;
+        *num_intersect_modifiers = 0;
+        return Success;
+    }
+
+    if (info->get_drawable_modifiers)
+        (*info->get_drawable_modifiers) (drawable, format,
+                                         &num_drawable_mods,
+                                         &drawable_mods);
+
+    /* We're allocating slightly more memory than necessary but it reduces
+     * the complexity of finding the intersection set.
+     */
+    screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+    if (!screen_mods)
+        return BadAlloc;
+    if (num_drawable_mods > 0) {
+        intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+        if (!intersect_mods) {
+            free(screen_mods);
+            return BadAlloc;
+        }
+    }
+
+    *num_screen_modifiers = 0;
+    *num_intersect_modifiers = 0;
+    for (i = 0; i < screen_format->num_modifiers; i++) {
+        CARD64 modifier = screen_format->modifiers[i];
+        Bool intersect = FALSE;
+
+        for (j = 0; j < num_drawable_mods; j++) {
+            if (drawable_mods[j] == modifier) {
+                intersect = TRUE;
+                break;
+            }
+        }
+
+        if (intersect) {
+            intersect_mods[*num_intersect_modifiers] = modifier;
+            *num_intersect_modifiers += 1;
+        } else {
+            screen_mods[*num_screen_modifiers] = modifier;
+            *num_screen_modifiers += 1;
+        }
+    }
+
+    assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
+
+    *intersect_modifiers = intersect_mods;
+    *screen_modifiers = screen_mods;
+    free(drawable_mods);
+
+    return Success;
+}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 8ffb40d6f..0933e9411 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -59,7 +59,7 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
 }
 
 static uint32_t
-drm_format_for_depth(int depth)
+wl_drm_format_for_depth(int depth)
 {
     switch (depth) {
     case 15:
@@ -170,7 +170,7 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
         wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
                                    pixmap->drawable.width,
                                    pixmap->drawable.height,
-                                   drm_format_for_depth(pixmap->drawable.depth),
+                                   wl_drm_format_for_depth(pixmap->drawable.depth),
                                    0, gbm_bo_get_stride(xwl_pixmap->bo),
                                    0, 0,
                                    0, 0);
diff --git a/meson.build b/meson.build
index 430c770cb..d64fb0ca3 100644
--- a/meson.build
+++ b/meson.build
@@ -78,7 +78,7 @@ scrnsaverproto_dep = dependency('scrnsaverproto', version: '>= 1.1')
 resourceproto_dep = dependency('resourceproto', version: '>= 1.2.0')
 xf86driproto_dep = dependency('xf86driproto', version: '>= 2.1.0', required: get_option('dri1') == 'true')
 dri2proto_dep = dependency('dri2proto', version: '>= 2.8', required: get_option('dri2') == 'true')
-dri3proto_dep = dependency('dri3proto', version: '>= 1.0', required: get_option('dri3') == 'true')
+dri3proto_dep = dependency('dri3proto', version: '>= 1.2', required: get_option('dri3') == 'true')
 xineramaproto_dep = dependency('xineramaproto')
 xf86bigfontproto_dep = dependency('xf86bigfontproto', version: '>= 1.2.0')
 xf86vidmodeproto_dep = dependency('xf86vidmodeproto', version: '>= 2.2.99.1', required: false)


More information about the xorg-commit mailing list