vulkan/wsi/x11: Add support for DRI3 v1.2
authorDaniel Stone <daniels@collabora.com>
Thu, 8 Jun 2017 16:24:30 +0000 (17:24 +0100)
committerDaniel Stone <daniels@collabora.com>
Fri, 9 Mar 2018 17:47:13 +0000 (17:47 +0000)
Adds support for multiple planes and buffer modifiers.

v4: Rename "has_dri3_v1_1" to "has_dri3_modifiers"
v12: Multi-planar/modifier support is now DRI3 v1.2; also update release
     versions

configure.ac
meson.build
src/vulkan/wsi/wsi_common_x11.c

index 40e7855994a6e76d744f192694d5060d39327d56..f84903dffebf39694f458d267793e39a03a0cf8d 100644 (file)
@@ -92,6 +92,7 @@ WAYLAND_REQUIRED=1.11
 WAYLAND_PROTOCOLS_REQUIRED=1.8
 XCB_REQUIRED=1.9.3
 XCBDRI2_REQUIRED=1.8
+XCBDRI3_REQUIRED=1.13
 XCBGLX_REQUIRED=1.8.1
 XDAMAGE_REQUIRED=1.1
 XSHMFENCE_REQUIRED=1.1
@@ -1849,7 +1850,7 @@ fi
 if test x"$enable_dri3" = xyes; then
     DEFINES="$DEFINES -DHAVE_DRI3"
 
-    dri3_modules="x11-xcb xcb >= $XCB_REQUIRED xcb-dri3 xcb-xfixes xcb-present xcb-sync xshmfence >= $XSHMFENCE_REQUIRED"
+    dri3_modules="x11-xcb xcb >= $XCB_REQUIRED xcb-dri3 >= $XCBDRI3_REQUIRED xcb-xfixes xcb-present xcb-sync xshmfence >= $XSHMFENCE_REQUIRED"
     PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules])
 fi
 
index 7658f6e63dae57920fd74a9e445efb07018fd227..34090de45257ea468474af8697760900feb1f341 100644 (file)
@@ -1234,7 +1234,7 @@ if with_platform_x11
 
     if with_dri3
       pre_args += '-DHAVE_DRI3'
-      dep_xcb_dri3 = dependency('xcb-dri3')
+      dep_xcb_dri3 = dependency('xcb-dri3', version : '>= 1.13')
       dep_xcb_present = dependency('xcb-present')
       dep_xcb_sync = dependency('xcb-sync')
       dep_xshmfence = dependency('xshmfence', version : '>= 1.1')
index e5e719e1d507d6ca4459d61bfa72b361fc79fefb..ab577868ab16bc0b29a6e3e8bd551b63c158f230 100644 (file)
@@ -36,6 +36,7 @@
 #include <fcntl.h>
 #include <poll.h>
 #include <xf86drm.h>
+#include <drm_fourcc.h>
 #include "util/hash_table.h"
 
 #include "vk_util.h"
@@ -50,6 +51,7 @@
 
 struct wsi_x11_connection {
    bool has_dri3;
+   bool has_dri3_modifiers;
    bool has_present;
    bool is_proprietary_x11;
 };
@@ -164,6 +166,17 @@ wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
    }
 
    wsi_conn->has_dri3 = dri3_reply->present != 0;
+   if (wsi_conn->has_dri3) {
+      xcb_dri3_query_version_cookie_t ver_cookie;
+      xcb_dri3_query_version_reply_t *ver_reply;
+
+      ver_cookie = xcb_dri3_query_version(conn, 1, 2);
+      ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL);
+      wsi_conn->has_dri3_modifiers =
+         (ver_reply->major_version > 1 || ver_reply->minor_version >= 2);
+      free(ver_reply);
+   }
+
    wsi_conn->has_present = pres_reply->present != 0;
    wsi_conn->is_proprietary_x11 = false;
    if (amd_reply && amd_reply->present)
@@ -620,6 +633,8 @@ struct x11_image {
 struct x11_swapchain {
    struct wsi_swapchain                        base;
 
+   bool                                         has_dri3_modifiers;
+
    xcb_connection_t *                           conn;
    xcb_window_t                                 window;
    xcb_gc_t                                     gc;
@@ -966,7 +981,9 @@ static VkResult
 x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
                const VkSwapchainCreateInfoKHR *pCreateInfo,
                const VkAllocationCallbacks* pAllocator,
-               struct x11_image *image)
+               const uint64_t *const *modifiers,
+               const uint32_t *num_modifiers,
+               int num_tranches, struct x11_image *image)
 {
    xcb_void_cookie_t cookie;
    VkResult result;
@@ -976,28 +993,57 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
       result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base);
    } else {
       result = wsi_create_native_image(&chain->base, pCreateInfo,
-                                       0, NULL, NULL, &image->base);
+                                       num_tranches, num_modifiers, modifiers,
+                                       &image->base);
    }
    if (result < 0)
       return result;
 
    image->pixmap = xcb_generate_id(chain->conn);
 
-   /* Without passing modifiers, we can't have multi-plane RGB images. */
-   assert(image->base.num_planes == 1);
-
-   cookie =
-      xcb_dri3_pixmap_from_buffer_checked(chain->conn,
-                                          image->pixmap,
-                                          chain->window,
-                                          image->base.sizes[0],
-                                          pCreateInfo->imageExtent.width,
-                                          pCreateInfo->imageExtent.height,
-                                          image->base.row_pitches[0],
-                                          chain->depth, bpp,
-                                          image->base.fds[0]);
+   if (image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) {
+      /* If the image has a modifier, we must have DRI3 v1.1. */
+      assert(chain->has_dri3_modifiers);
+
+      cookie =
+         xcb_dri3_pixmap_from_buffers_checked(chain->conn,
+                                              image->pixmap,
+                                              chain->window,
+                                              image->base.num_planes,
+                                              pCreateInfo->imageExtent.width,
+                                              pCreateInfo->imageExtent.height,
+                                              image->base.row_pitches[0],
+                                              image->base.offsets[0],
+                                              image->base.row_pitches[1],
+                                              image->base.offsets[1],
+                                              image->base.row_pitches[2],
+                                              image->base.offsets[2],
+                                              image->base.row_pitches[3],
+                                              image->base.offsets[3],
+                                              chain->depth, bpp,
+                                              image->base.drm_modifier,
+                                              image->base.fds);
+   } else {
+      /* Without passing modifiers, we can't have multi-plane RGB images. */
+      assert(image->base.num_planes == 1);
+
+      cookie =
+         xcb_dri3_pixmap_from_buffer_checked(chain->conn,
+                                             image->pixmap,
+                                             chain->window,
+                                             image->base.sizes[0],
+                                             pCreateInfo->imageExtent.width,
+                                             pCreateInfo->imageExtent.height,
+                                             image->base.row_pitches[0],
+                                             chain->depth, bpp,
+                                             image->base.fds[0]);
+   }
+
    xcb_discard_reply(chain->conn, cookie.sequence);
-   image->base.fds[0] = -1; /* XCB has now taken ownership of the FD */
+
+   /* XCB has now taken ownership of the FDs. */
+   for (int i = 0; i < image->base.num_planes; i++)
+      image->base.fds[i] = -1;
 
    int fence_fd = xshmfence_alloc_shm();
    if (fence_fd < 0)
@@ -1048,6 +1094,82 @@ x11_image_finish(struct x11_swapchain *chain,
    wsi_destroy_image(&chain->base, &image->base);
 }
 
+static void
+wsi_x11_get_dri3_modifiers(struct wsi_x11_connection *wsi_conn,
+                           xcb_connection_t *conn, xcb_window_t window,
+                           uint8_t depth, uint8_t bpp,
+                           VkCompositeAlphaFlagsKHR vk_alpha,
+                           uint64_t **modifiers_in, uint32_t *num_modifiers_in,
+                           uint32_t *num_tranches_in,
+                           const VkAllocationCallbacks *pAllocator)
+{
+   if (!wsi_conn->has_dri3_modifiers)
+      goto out;
+
+   xcb_generic_error_t *error = NULL;
+   xcb_dri3_get_supported_modifiers_cookie_t mod_cookie =
+      xcb_dri3_get_supported_modifiers(conn, window, depth, bpp);
+   xcb_dri3_get_supported_modifiers_reply_t *mod_reply =
+      xcb_dri3_get_supported_modifiers_reply(conn, mod_cookie, &error);
+   free(error);
+
+   if (!mod_reply || (mod_reply->num_window_modifiers == 0 &&
+                      mod_reply->num_screen_modifiers == 0)) {
+      free(mod_reply);
+      goto out;
+   }
+
+   uint32_t n = 0;
+   uint32_t counts[2];
+   uint64_t *modifiers[2];
+
+   if (mod_reply->num_window_modifiers) {
+      counts[n] = mod_reply->num_window_modifiers;
+      modifiers[n] = vk_alloc(pAllocator,
+                              counts[n] * sizeof(uint64_t),
+                              8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+      if (!modifiers[n]) {
+         free(mod_reply);
+         goto out;
+      }
+
+      memcpy(modifiers[n],
+             xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply),
+             counts[n] * sizeof(uint64_t));
+      n++;
+   }
+
+   if (mod_reply->num_screen_modifiers) {
+      counts[n] = mod_reply->num_screen_modifiers;
+      modifiers[n] = vk_alloc(pAllocator,
+                              counts[n] * sizeof(uint64_t),
+                              8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+      if (!modifiers[n]) {
+        if (n > 0)
+            vk_free(pAllocator, modifiers[0]);
+         free(mod_reply);
+         goto out;
+      }
+
+      memcpy(modifiers[n],
+             xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply),
+             counts[n] * sizeof(uint64_t));
+      n++;
+   }
+
+   for (int i = 0; i < n; i++) {
+      modifiers_in[i] = modifiers[i];
+      num_modifiers_in[i] = counts[i];
+   }
+   *num_tranches_in = n;
+
+   free(mod_reply);
+   return;
+
+out:
+   *num_tranches_in = 0;
+}
+
 static VkResult
 x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
                       const VkAllocationCallbacks *pAllocator)
@@ -1097,8 +1219,13 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
 
    const unsigned num_images = pCreateInfo->minImageCount;
 
-   /* Check for whether or not we have a window up-front */
    xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
+   struct wsi_x11_connection *wsi_conn =
+      wsi_x11_get_connection(wsi_device, pAllocator, conn);
+   if (!wsi_conn)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   /* Check for whether or not we have a window up-front */
    xcb_window_t window = x11_surface_get_window(icd_surface);
    xcb_get_geometry_reply_t *geometry =
       xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL);
@@ -1132,6 +1259,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
    chain->last_present_msc = 0;
    chain->threaded = false;
    chain->status = VK_SUCCESS;
+   chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers;
 
    if (!wsi_x11_check_dri3_compatible(conn, local_fd))
        chain->base.use_prime_blit = true;
@@ -1163,9 +1291,20 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
                           (uint32_t []) { 0 });
    xcb_discard_reply(chain->conn, cookie.sequence);
 
+   uint64_t *modifiers[2] = {NULL, NULL};
+   uint32_t num_modifiers[2] = {0, 0};
+   uint32_t num_tranches = 0;
+   if (wsi_device->supports_modifiers)
+      wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32,
+                                 pCreateInfo->compositeAlpha,
+                                 modifiers, num_modifiers, &num_tranches,
+                                 pAllocator);
+
    uint32_t image = 0;
    for (; image < chain->base.image_count; image++) {
       result = x11_image_init(device, chain, pCreateInfo, pAllocator,
+                              (const uint64_t *const *)modifiers,
+                              num_modifiers, num_tranches,
                               &chain->images[image]);
       if (result != VK_SUCCESS)
          goto fail_init_images;
@@ -1202,6 +1341,8 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
       }
    }
 
+   for (int i = 0; i < 2; i++)
+      vk_free(pAllocator, modifiers[i]);
    *swapchain_out = &chain->base;
 
    return VK_SUCCESS;
@@ -1211,6 +1352,9 @@ fail_init_images:
       x11_image_finish(chain, pAllocator, &chain->images[j]);
 
 fail_register:
+   for (int i = 0; i < 2; i++)
+      vk_free(pAllocator, modifiers[i]);
+
    xcb_unregister_for_special_event(chain->conn, chain->special_event);
 
    wsi_swapchain_finish(&chain->base);