From: Daniel Stone <dani...@collabora.com>

Adds support for multiple planes and buffer modifiers.

v4: Rename "has_dri3_v1_1" to "has_dri3_modifiers"
---
 src/vulkan/wsi/wsi_common_x11.c | 238 +++++++++++++++++++++++++++++++++-------
 1 file changed, 199 insertions(+), 39 deletions(-)

diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index e48d746305..0417166409 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -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,19 @@ wsi_x11_connection_create(const VkAllocationCallbacks 
*alloc,
    }
 
    wsi_conn->has_dri3 = dri3_reply->present != 0;
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+   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, 1);
+      ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL);
+      wsi_conn->has_dri3_v1_1 =
+         (ver_reply->major_version > 1 || ver_reply->minor_version >= 1);
+      free(ver_reply);
+   }
+#endif
+
    wsi_conn->has_present = pres_reply->present != 0;
    wsi_conn->is_proprietary_x11 = false;
    if (amd_reply && amd_reply->present)
@@ -626,6 +641,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;
@@ -679,7 +696,10 @@ x11_get_image_and_linear(struct wsi_swapchain *drv_chain,
 {
    struct x11_swapchain *chain = (struct x11_swapchain *)drv_chain;
    *image = chain->images[imageIndex].base.image;
-   *linear_image = chain->images[imageIndex].linear_base.image;
+   if (chain->images[imageIndex].base.linear_image != VK_NULL_HANDLE)
+      *linear_image = chain->images[imageIndex].base.linear_image;
+   else
+      *linear_image = chain->images[imageIndex].linear_base.image;
 }
 
 static VkResult
@@ -954,56 +974,100 @@ static VkResult
 x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
                const VkSwapchainCreateInfoKHR *pCreateInfo,
                const VkAllocationCallbacks* pAllocator,
-               struct x11_image *image)
+               uint64_t **modifiers, int *num_modifiers,
+               int num_tranches, struct x11_image *image)
 {
    xcb_void_cookie_t cookie;
    VkResult result;
    uint32_t bpp = 32;
-
-   result = chain->base.image_fns->create_wsi_image(device_h,
-                                                    pCreateInfo,
-                                                    pAllocator,
-                                                    
!chain->base.needs_linear_copy,
-                                                    false,
-                                                    &image->base);
-   if (result != VK_SUCCESS)
-      return result;
-
-   if (chain->base.needs_linear_copy) {
+   int i;
+
+   image->linear_base.image = VK_NULL_HANDLE;
+   image->linear_base.memory = VK_NULL_HANDLE;
+
+   if (chain->base.image_fns->create_wsi_image_with_modifiers) {
+      result = chain->base.image_fns->create_wsi_image_with_modifiers(device_h,
+                                                                      
pCreateInfo,
+                                                                      
pAllocator,
+                                                                      
chain->base.needs_linear_copy,
+                                                                      
modifiers,
+                                                                      
num_modifiers,
+                                                                      
num_tranches,
+                                                                      
&image->base);
+      if (result != VK_SUCCESS)
+         return result;
+   } else {
       result = chain->base.image_fns->create_wsi_image(device_h,
                                                        pCreateInfo,
                                                        pAllocator,
-                                                       true,
-                                                       true,
-                                                       &image->linear_base);
-
-      if (result != VK_SUCCESS) {
-         chain->base.image_fns->free_wsi_image(device_h, pAllocator,
-                                               &image->base);
+                                                       
!chain->base.needs_linear_copy,
+                                                       false,
+                                                       &image->base);
+      if (result != VK_SUCCESS)
          return result;
+
+      if (chain->base.needs_linear_copy) {
+         result = chain->base.image_fns->create_wsi_image(device_h,
+                                                          pCreateInfo,
+                                                          pAllocator,
+                                                          true,
+                                                          true,
+                                                          &image->linear_base);
+      
+         if (result != VK_SUCCESS) {
+            chain->base.image_fns->free_wsi_image(device_h, pAllocator,
+                                                  &image->base);
+            return result;
+         }
       }
    }
 
    image->pixmap = xcb_generate_id(chain->conn);
 
-   struct wsi_image_base *image_ws =
-      chain->base.needs_linear_copy ? &image->linear_base : &image->base;
-
-   /* Without passing modifiers, we can't have multi-plane RGB images. */
-   assert(image_ws->num_planes == 1);
-
-   cookie =
-      xcb_dri3_pixmap_from_buffer_checked(chain->conn,
-                                          image->pixmap,
-                                          chain->window,
-                                          image_ws->sizes[0],
-                                          pCreateInfo->imageExtent.width,
-                                          pCreateInfo->imageExtent.height,
-                                          image_ws->row_pitches[0],
-                                          chain->depth, bpp,
-                                          image_ws->fds[0]);
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+   if (chain->has_dri3_modifiers &&
+       image->base.drm_modifier != DRM_FORMAT_MOD_INVALID) {
+      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
+#endif
+   {
+      /* 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_ws->fds[0] = -1; /* XCB has now taken ownership of the FD */
+
+   /* XCB has now taken ownership of the FDs. */
+   for (i = 0; i < image->base.num_planes; i++)
+      image->base.fds[i] = -1;
 
    int fence_fd = xshmfence_alloc_shm();
    if (fence_fd < 0)
@@ -1032,7 +1096,7 @@ fail_pixmap:
    cookie = xcb_free_pixmap(chain->conn, image->pixmap);
    xcb_discard_reply(chain->conn, cookie.sequence);
 
-   if (chain->base.needs_linear_copy) {
+   if (image->linear_base.image != VK_NULL_HANDLE) {
       chain->base.image_fns->free_wsi_image(device_h, pAllocator,
                                             &image->linear_base);
    }
@@ -1055,7 +1119,7 @@ x11_image_finish(struct x11_swapchain *chain,
    cookie = xcb_free_pixmap(chain->conn, image->pixmap);
    xcb_discard_reply(chain->conn, cookie.sequence);
 
-   if (chain->base.needs_linear_copy) {
+   if (image->linear_base.image != VK_NULL_HANDLE) {
       chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
                                             &image->linear_base);
    }
@@ -1063,6 +1127,82 @@ x11_image_finish(struct x11_swapchain *chain,
                                          &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, int *num_modifiers_in,
+                           int *num_tranches_in,
+                           const VkAllocationCallbacks *pAllocator)
+{
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 1
+   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_drawable_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_drawable_modifiers) {
+      counts[n] = mod_reply->num_drawable_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_drawable_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]) {
+         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;
+#endif
+
+out:
+   *num_tranches_in = 0;
+}
+
 static VkResult
 x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
                       const VkAllocationCallbacks *pAllocator)
@@ -1104,6 +1244,9 @@ x11_surface_create_swapchain(VkIcdSurfaceBase 
*icd_surface,
                              struct wsi_swapchain **swapchain_out)
 {
    struct x11_swapchain *chain;
+   uint64_t *modifiers[2] = {NULL, NULL};
+   int num_modifiers[2] = {0, 0};
+   int num_tranches = 0;
    xcb_void_cookie_t cookie;
    VkResult result;
 
@@ -1145,10 +1288,21 @@ x11_surface_create_swapchain(VkIcdSurfaceBase 
*icd_surface,
 
    free(geometry);
 
+   struct wsi_x11_connection *wsi_conn =
+      wsi_x11_get_connection(wsi_device, pAllocator, conn);
+   if (!wsi_conn)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   chain->has_dri3_modifiers = wsi_conn->has_dri3_modifiers;
+
    chain->base.needs_linear_copy = false;
    if (!wsi_x11_check_dri3_compatible(conn, local_fd))
        chain->base.needs_linear_copy = true;
 
+   wsi_x11_get_dri3_modifiers(wsi_conn, conn, window, chain->depth, 32,
+                              pCreateInfo->compositeAlpha,
+                              modifiers, num_modifiers, &num_tranches, 
pAllocator);
+
    chain->event_id = xcb_generate_id(chain->conn);
    xcb_present_select_input(chain->conn, chain->event_id, chain->window,
                             XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
@@ -1179,6 +1333,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase 
*icd_surface,
    uint32_t image = 0;
    for (; image < chain->base.image_count; image++) {
       result = x11_image_init(device, chain, pCreateInfo, pAllocator,
+                              modifiers, num_modifiers, num_tranches,
                               &chain->images[image]);
       if (result != VK_SUCCESS)
          goto fail_init_images;
@@ -1215,6 +1370,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;
@@ -1224,6 +1381,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);
 
    vk_free(pAllocator, chain);
-- 
2.13.0

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to