+ return x11_swapchain_result(chain, VK_SUCCESS);
+}
+
+static VkResult
+x11_acquire_next_image(struct wsi_swapchain *anv_chain,
+ const VkAcquireNextImageInfoKHR *info,
+ uint32_t *image_index)
+{
+ struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+ uint64_t timeout = info->timeout;
+
+ /* If the swapchain is in an error state, don't go any further. */
+ if (chain->status < 0)
+ return chain->status;
+
+ if (chain->has_acquire_queue) {
+ return x11_acquire_next_image_from_queue(chain, image_index, timeout);
+ } else {
+ return x11_acquire_next_image_poll_x11(chain, image_index, timeout);
+ }
+}
+
+static VkResult
+x11_queue_present(struct wsi_swapchain *anv_chain,
+ uint32_t image_index,
+ const VkPresentRegionKHR *damage)
+{
+ struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+
+ /* If the swapchain is in an error state, don't go any further. */
+ if (chain->status < 0)
+ return chain->status;
+
+ chain->images[image_index].busy = true;
+ if (chain->has_present_queue) {
+ wsi_queue_push(&chain->present_queue, image_index);
+ return chain->status;
+ } else {
+ return x11_present_to_x11(chain, image_index, 0);
+ }
+}
+
+static void *
+x11_manage_fifo_queues(void *state)
+{
+ struct x11_swapchain *chain = state;
+ VkResult result = VK_SUCCESS;
+
+ assert(chain->has_present_queue);
+ while (chain->status >= 0) {
+ /* It should be safe to unconditionally block here. Later in the loop
+ * we blocks until the previous present has landed on-screen. At that
+ * point, we should have received IDLE_NOTIFY on all images presented
+ * before that point so the client should be able to acquire any image
+ * other than the currently presented one.
+ */
+ uint32_t image_index = 0;
+ result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
+ assert(result != VK_TIMEOUT);
+ if (result < 0) {
+ goto fail;
+ } else if (chain->status < 0) {
+ /* The status can change underneath us if the swapchain is destroyed
+ * from another thread.
+ */
+ return NULL;
+ }
+
+ if (chain->base.present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
+ result = chain->base.wsi->WaitForFences(chain->base.device, 1,
+ &chain->base.fences[image_index],
+ true, UINT64_MAX);
+ if (result != VK_SUCCESS) {
+ result = VK_ERROR_OUT_OF_DATE_KHR;
+ goto fail;
+ }
+ }
+
+ uint64_t target_msc = 0;
+ if (chain->has_acquire_queue)
+ target_msc = chain->last_present_msc + 1;
+
+ result = x11_present_to_x11(chain, image_index, target_msc);
+ if (result < 0)
+ goto fail;
+
+ if (chain->has_acquire_queue) {
+ while (chain->last_present_msc < target_msc) {
+ xcb_generic_event_t *event =
+ xcb_wait_for_special_event(chain->conn, chain->special_event);
+ if (!event) {
+ result = VK_ERROR_OUT_OF_DATE_KHR;
+ goto fail;
+ }
+
+ result = x11_handle_dri3_present_event(chain, (void *)event);
+ free(event);
+ if (result < 0)
+ goto fail;
+ }
+ }
+ }
+
+fail:
+ x11_swapchain_result(chain, result);
+ if (chain->has_acquire_queue)
+ wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
+
+ return NULL;