vulkan/wsi: Implement GetPhysicalDevicePresentRectanglesKHR
[mesa.git] / src / vulkan / wsi / wsi_common_x11.c
index 1bfbc7c30019a63b65992fc961d334485fba0004..8c621ddf568ad7b22f19744973358ee48a8e6c74 100644 (file)
@@ -125,7 +125,7 @@ wsi_x11_check_dri3_compatible(xcb_connection_t *conn, int local_fd)
 }
 
 static struct wsi_x11_connection *
-wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
+wsi_x11_connection_create(struct wsi_device *wsi_dev,
                           xcb_connection_t *conn)
 {
    xcb_query_extension_cookie_t dri3_cookie, pres_cookie, amd_cookie, nv_cookie;
@@ -134,7 +134,7 @@ wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
    bool has_present_v1_2 = false;
 
    struct wsi_x11_connection *wsi_conn =
-      vk_alloc(alloc, sizeof(*wsi_conn), 8,
+      vk_alloc(&wsi_dev->instance_alloc, sizeof(*wsi_conn), 8,
                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
    if (!wsi_conn)
       return NULL;
@@ -163,7 +163,7 @@ wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
       free(pres_reply);
       free(amd_reply);
       free(nv_reply);
-      vk_free(alloc, wsi_conn);
+      vk_free(&wsi_dev->instance_alloc, wsi_conn);
       return NULL;
    }
 
@@ -211,10 +211,10 @@ wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
 }
 
 static void
-wsi_x11_connection_destroy(const VkAllocationCallbacks *alloc,
+wsi_x11_connection_destroy(struct wsi_device *wsi_dev,
                            struct wsi_x11_connection *conn)
 {
-   vk_free(alloc, conn);
+   vk_free(&wsi_dev->instance_alloc, conn);
 }
 
 static bool
@@ -231,7 +231,6 @@ wsi_x11_check_for_dri3(struct wsi_x11_connection *wsi_conn)
 
 static struct wsi_x11_connection *
 wsi_x11_get_connection(struct wsi_device *wsi_dev,
-                      const VkAllocationCallbacks *alloc,
                        xcb_connection_t *conn)
 {
    struct wsi_x11 *wsi =
@@ -247,7 +246,7 @@ wsi_x11_get_connection(struct wsi_device *wsi_dev,
       pthread_mutex_unlock(&wsi->mutex);
 
       struct wsi_x11_connection *wsi_conn =
-         wsi_x11_connection_create(alloc, conn);
+         wsi_x11_connection_create(wsi_dev, conn);
       if (!wsi_conn)
          return NULL;
 
@@ -256,7 +255,7 @@ wsi_x11_get_connection(struct wsi_device *wsi_dev,
       entry = _mesa_hash_table_search(wsi->connections, conn);
       if (entry) {
          /* Oops, someone raced us to it */
-         wsi_x11_connection_destroy(alloc, wsi_conn);
+         wsi_x11_connection_destroy(wsi_dev, wsi_conn);
       } else {
          entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
       }
@@ -382,7 +381,6 @@ visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
 
 VkBool32 wsi_get_physical_device_xcb_presentation_support(
     struct wsi_device *wsi_device,
-    VkAllocationCallbacks *alloc,
     uint32_t                                    queueFamilyIndex,
     int fd,
     bool can_handle_different_gpu,
@@ -390,7 +388,7 @@ VkBool32 wsi_get_physical_device_xcb_presentation_support(
     xcb_visualid_t                              visual_id)
 {
    struct wsi_x11_connection *wsi_conn =
-      wsi_x11_get_connection(wsi_device, alloc, connection);
+      wsi_x11_get_connection(wsi_device, connection);
 
    if (!wsi_conn)
       return false;
@@ -433,7 +431,6 @@ x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
 static VkResult
 x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
                         struct wsi_device *wsi_device,
-                        const VkAllocationCallbacks *alloc,
                         uint32_t queueFamilyIndex,
                         int local_fd,
                         VkBool32* pSupported)
@@ -442,7 +439,7 @@ x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
    xcb_window_t window = x11_surface_get_window(icd_surface);
 
    struct wsi_x11_connection *wsi_conn =
-      wsi_x11_get_connection(wsi_device, alloc, conn);
+      wsi_x11_get_connection(wsi_device, conn);
    if (!wsi_conn)
       return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -602,6 +599,66 @@ x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
       VK_INCOMPLETE : VK_SUCCESS;
 }
 
+static bool
+x11_surface_is_local_to_gpu(struct wsi_device *wsi_dev,
+                            int local_fd,
+                            xcb_connection_t *conn)
+{
+   struct wsi_x11_connection *wsi_conn =
+      wsi_x11_get_connection(wsi_dev, conn);
+
+   if (!wsi_conn)
+      return false;
+
+   if (!wsi_x11_check_for_dri3(wsi_conn))
+      return false;
+
+   if (!wsi_x11_check_dri3_compatible(conn, local_fd))
+      return false;
+
+   return true;
+}
+
+static VkResult
+x11_surface_get_present_rectangles(VkIcdSurfaceBase *icd_surface,
+                                   struct wsi_device *wsi_device,
+                                   int local_fd,
+                                   uint32_t* pRectCount,
+                                   VkRect2D* pRects)
+{
+   xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
+   xcb_window_t window = x11_surface_get_window(icd_surface);
+   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
+
+   if (x11_surface_is_local_to_gpu(wsi_device, local_fd, conn)) {
+      vk_outarray_append(&out, rect) {
+         xcb_generic_error_t *err = NULL;
+         xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, window);
+         xcb_get_geometry_reply_t *geom =
+            xcb_get_geometry_reply(conn, geom_cookie, &err);
+         free(err);
+         if (geom) {
+            *rect = (VkRect2D) {
+               .offset = { 0, 0 },
+               .extent = { geom->width, geom->height },
+            };
+         } else {
+            /* This can happen if the client didn't wait for the configure event
+             * to come back from the compositor.  In that case, we don't know the
+             * size of the window so we just return valid "I don't know" stuff.
+             */
+            *rect = (VkRect2D) {
+               .offset = { 0, 0 },
+               .extent = { -1, -1 },
+            };
+         }
+         free(geom);
+      }
+   }
+
+   return vk_outarray_status(&out);
+}
+
 VkResult wsi_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
                                const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
                                VkSurfaceKHR *pSurface)
@@ -948,11 +1005,11 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
 
 static VkResult
 x11_acquire_next_image(struct wsi_swapchain *anv_chain,
-                       uint64_t timeout,
-                       VkSemaphore semaphore,
+                       const VkAcquireNextImageInfoKHR *info,
                        uint32_t *image_index)
 {
    struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+   uint64_t timeout = info->timeout;
 
    if (chain->threaded) {
       return x11_acquire_next_image_from_queue(chain, image_index, timeout);
@@ -980,7 +1037,7 @@ static void *
 x11_manage_fifo_queues(void *state)
 {
    struct x11_swapchain *chain = state;
-   VkResult result;
+   VkResult result = VK_SUCCESS;
 
    assert(chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR);
 
@@ -991,7 +1048,7 @@ x11_manage_fifo_queues(void *state)
        * before that point so the client should be able to acquire any image
        * other than the currently presented one.
        */
-      uint32_t image_index;
+      uint32_t image_index = 0;
       result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
       assert(result != VK_TIMEOUT);
       if (result < 0) {
@@ -1024,7 +1081,7 @@ x11_manage_fifo_queues(void *state)
    }
 
 fail:
-   result = x11_swapchain_result(chain, result);
+   x11_swapchain_result(chain, result);
    wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
 
    return NULL;
@@ -1235,9 +1292,6 @@ x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
    struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
    xcb_void_cookie_t cookie;
 
-   for (uint32_t i = 0; i < chain->base.image_count; i++)
-      x11_image_finish(chain, pAllocator, &chain->images[i]);
-
    if (chain->threaded) {
       chain->status = VK_ERROR_OUT_OF_DATE_KHR;
       /* Push a UINT32_MAX to wake up the manager */
@@ -1247,6 +1301,9 @@ x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
       wsi_queue_destroy(&chain->present_queue);
    }
 
+   for (uint32_t i = 0; i < chain->base.image_count; i++)
+      x11_image_finish(chain, pAllocator, &chain->images[i]);
+
    xcb_unregister_for_special_event(chain->conn, chain->special_event);
    cookie = xcb_present_select_input_checked(chain->conn, chain->event_id,
                                              chain->window,
@@ -1279,7 +1336,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
 
    xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
    struct wsi_x11_connection *wsi_conn =
-      wsi_x11_get_connection(wsi_device, pAllocator, conn);
+      wsi_x11_get_connection(wsi_device, conn);
    if (!wsi_conn)
       return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -1325,7 +1382,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
     * mode which provokes reallocation when anything changes, to make
     * sure we have the most optimal allocation.
     */
-   struct x11_swapchain *old_chain = (void *) pCreateInfo->oldSwapchain;
+   struct x11_swapchain *old_chain = (void *)(intptr_t) pCreateInfo->oldSwapchain;
    if (old_chain)
       chain->last_present_mode = old_chain->last_present_mode;
    else
@@ -1469,11 +1526,11 @@ wsi_x11_init_wsi(struct wsi_device *wsi_device,
    }
 
    wsi->base.get_support = x11_surface_get_support;
-   wsi->base.get_capabilities = x11_surface_get_capabilities;
    wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
    wsi->base.get_formats = x11_surface_get_formats;
    wsi->base.get_formats2 = x11_surface_get_formats2;
    wsi->base.get_present_modes = x11_surface_get_present_modes;
+   wsi->base.get_present_rectangles = x11_surface_get_present_rectangles;
    wsi->base.create_swapchain = x11_surface_create_swapchain;
 
    wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
@@ -1502,7 +1559,7 @@ wsi_x11_finish_wsi(struct wsi_device *wsi_device,
    if (wsi) {
       struct hash_entry *entry;
       hash_table_foreach(wsi->connections, entry)
-         wsi_x11_connection_destroy(alloc, entry->data);
+         wsi_x11_connection_destroy(wsi_device, entry->data);
 
       _mesa_hash_table_destroy(wsi->connections, NULL);