#include "util/hash_table.h"
#include "vk_util.h"
-#include "wsi_common.h"
+#include "wsi_common_private.h"
#include "wsi_common_x11.h"
#include "wsi_common_queue.h"
const VkAllocationCallbacks *alloc,
uint32_t queueFamilyIndex,
int local_fd,
- bool can_handle_different_gpu,
VkBool32* pSupported)
{
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
return VK_SUCCESS;
}
- if (!can_handle_different_gpu)
- if (!wsi_x11_check_dri3_compatible(conn, local_fd))
- return false;
-
unsigned visual_depth;
if (!get_visualtype_for_window(conn, window, &visual_depth)) {
*pSupported = false;
struct x11_image {
struct wsi_image base;
- struct wsi_image linear_base;
xcb_pixmap_t pixmap;
bool busy;
struct xshmfence * shm_fence;
struct x11_image images[0];
};
+/**
+ * Update the swapchain status with the result of an operation, and return
+ * the combined status. The chain status will eventually be returned from
+ * AcquireNextImage and QueuePresent.
+ *
+ * We make sure to 'stick' more pessimistic statuses: an out-of-date error
+ * is permanent once seen, and every subsequent call will return this. If
+ * this has not been seen, success will be returned.
+ */
static VkResult
-x11_get_images(struct wsi_swapchain *anv_chain,
- uint32_t* pCount, VkImage *pSwapchainImages)
+x11_swapchain_result(struct x11_swapchain *chain, VkResult result)
{
- struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
- uint32_t ret_count;
- VkResult result;
-
- if (pSwapchainImages == NULL) {
- *pCount = chain->base.image_count;
- return VK_SUCCESS;
- }
+ /* Prioritise returning existing errors for consistency. */
+ if (chain->status < 0)
+ return chain->status;
- result = VK_SUCCESS;
- ret_count = chain->base.image_count;
- if (chain->base.image_count > *pCount) {
- ret_count = *pCount;
- result = VK_INCOMPLETE;
+ /* If we have a new error, mark it as permanent on the chain and return. */
+ if (result < 0) {
+ chain->status = result;
+ return result;
}
- for (uint32_t i = 0; i < ret_count; i++)
- pSwapchainImages[i] = chain->images[i].base.image;
+ /* Return temporary errors, but don't persist them. */
+ if (result == VK_TIMEOUT || result == VK_NOT_READY)
+ return result;
- return result;
+ /* No changes, so return the last status. */
+ return chain->status;
}
-static void
-x11_get_image_and_linear(struct wsi_swapchain *drv_chain,
- int imageIndex, VkImage *image, VkImage *linear_image)
+static struct wsi_image *
+x11_get_wsi_image(struct wsi_swapchain *wsi_chain, uint32_t image_index)
{
- struct x11_swapchain *chain = (struct x11_swapchain *)drv_chain;
- *image = chain->images[imageIndex].base.image;
- *linear_image = chain->images[imageIndex].linear_base.image;
+ struct x11_swapchain *chain = (struct x11_swapchain *)wsi_chain;
+ return &chain->images[image_index].base;
}
+/**
+ * Process an X11 Present event. Does not update chain->status.
+ */
static VkResult
x11_handle_dri3_present_event(struct x11_swapchain *chain,
xcb_present_generic_event_t *event)
xshmfence_await(chain->images[i].shm_fence);
*image_index = i;
chain->images[i].busy = true;
- return VK_SUCCESS;
+ return x11_swapchain_result(chain, VK_SUCCESS);
}
}
if (timeout == UINT64_MAX) {
event = xcb_wait_for_special_event(chain->conn, chain->special_event);
if (!event)
- return VK_ERROR_OUT_OF_DATE_KHR;
+ return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
} else {
event = xcb_poll_for_special_event(chain->conn, chain->special_event);
if (!event) {
int ret;
if (timeout == 0)
- return VK_NOT_READY;
+ return x11_swapchain_result(chain, VK_NOT_READY);
atimeout = wsi_get_absolute_timeout(timeout);
pfds.events = POLLIN;
ret = poll(&pfds, 1, timeout / 1000 / 1000);
if (ret == 0)
- return VK_TIMEOUT;
+ return x11_swapchain_result(chain, VK_TIMEOUT);
if (ret == -1)
- return VK_ERROR_OUT_OF_DATE_KHR;
+ return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
/* If a non-special event happens, the fd will still
* poll. So recalculate the timeout now just in case.
}
}
+ /* Update the swapchain status here. We may catch non-fatal errors here,
+ * in which case we need to update the status and continue.
+ */
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
free(event);
- if (result != VK_SUCCESS)
- return result;
+ if (result < 0)
+ return x11_swapchain_result(chain, result);
}
}
uint32_t image_index;
VkResult result = wsi_queue_pull(&chain->acquire_queue,
&image_index, timeout);
- if (result != VK_SUCCESS) {
- return result;
- } else if (chain->status != VK_SUCCESS) {
+ if (result < 0 || result == VK_TIMEOUT) {
+ /* On error, the thread has shut down, so safe to update chain->status.
+ * Calling x11_swapchain_result with VK_TIMEOUT won't modify
+ * chain->status so that is also safe.
+ */
+ return x11_swapchain_result(chain, result);
+ } else if (chain->status < 0) {
return chain->status;
}
*image_index_out = image_index;
- return VK_SUCCESS;
+ return chain->status;
}
static VkResult
xcb_flush(chain->conn);
- return VK_SUCCESS;
+ return x11_swapchain_result(chain, VK_SUCCESS);
}
static VkResult
assert(chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR);
- while (chain->status == VK_SUCCESS) {
+ 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
*/
uint32_t image_index;
result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
- if (result != VK_SUCCESS) {
+ assert(result != VK_TIMEOUT);
+ if (result < 0) {
goto fail;
- } else if (chain->status != VK_SUCCESS) {
+ } else if (chain->status < 0) {
+ /* The status can change underneath us if the swapchain is destroyed
+ * from another thread.
+ */
return NULL;
}
uint64_t target_msc = chain->last_present_msc + 1;
result = x11_present_to_x11(chain, image_index, target_msc);
- if (result != VK_SUCCESS)
+ if (result < 0)
goto fail;
while (chain->last_present_msc < target_msc) {
xcb_generic_event_t *event =
xcb_wait_for_special_event(chain->conn, chain->special_event);
- if (!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 != VK_SUCCESS)
+ if (result < 0)
goto fail;
}
}
fail:
- chain->status = result;
+ result = x11_swapchain_result(chain, result);
wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
return NULL;
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) {
- result = chain->base.image_fns->create_wsi_image(device_h,
- pCreateInfo,
- pAllocator,
- chain->base.needs_linear_copy,
- true,
- &image->linear_base);
-
- if (result != VK_SUCCESS) {
- chain->base.image_fns->free_wsi_image(device_h, pAllocator,
- &image->base);
- return result;
- }
+ if (chain->base.use_prime_blit) {
+ result = wsi_create_prime_image(&chain->base, pCreateInfo, &image->base);
+ } else {
+ result = wsi_create_native_image(&chain->base, pCreateInfo,
+ 0, NULL, NULL, &image->base);
}
+ if (result < 0)
+ return result;
image->pixmap = xcb_generate_id(chain->conn);
- struct wsi_image *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->base.num_planes == 1);
+
cookie =
xcb_dri3_pixmap_from_buffer_checked(chain->conn,
image->pixmap,
chain->window,
- image_ws->size,
+ image->base.sizes[0],
pCreateInfo->imageExtent.width,
pCreateInfo->imageExtent.height,
- image_ws->row_pitch,
+ image->base.row_pitches[0],
chain->depth, bpp,
- image_ws->fd);
+ image->base.fds[0]);
xcb_discard_reply(chain->conn, cookie.sequence);
- image_ws->fd = -1; /* XCB has now taken ownership of the FD */
+ image->base.fds[0] = -1; /* XCB has now taken ownership of the FD */
int fence_fd = xshmfence_alloc_shm();
if (fence_fd < 0)
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
- if (chain->base.needs_linear_copy) {
- chain->base.image_fns->free_wsi_image(device_h, pAllocator,
- &image->linear_base);
- }
- chain->base.image_fns->free_wsi_image(device_h, pAllocator, &image->base);
+ wsi_destroy_image(&chain->base, &image->base);
return result;
}
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
- if (chain->base.needs_linear_copy) {
- chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
- &image->linear_base);
- }
- chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
- &image->base);
+ wsi_destroy_image(&chain->base, &image->base);
}
static VkResult
XCB_PRESENT_EVENT_MASK_NO_EVENT);
xcb_discard_reply(chain->conn, cookie.sequence);
+ wsi_swapchain_finish(&chain->base);
+
vk_free(pAllocator, chain);
return VK_SUCCESS;
int local_fd,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks* pAllocator,
- const struct wsi_image_fns *image_fns,
struct wsi_swapchain **swapchain_out)
{
struct x11_swapchain *chain;
if (chain == NULL)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- chain->base.device = device;
+ result = wsi_swapchain_init(wsi_device, &chain->base, device,
+ pCreateInfo, pAllocator);
+ if (result != VK_SUCCESS)
+ goto fail_alloc;
+
chain->base.destroy = x11_swapchain_destroy;
- chain->base.get_images = x11_get_images;
- chain->base.get_image_and_linear = x11_get_image_and_linear;
+ chain->base.get_wsi_image = x11_get_wsi_image;
chain->base.acquire_next_image = x11_acquire_next_image;
chain->base.queue_present = x11_queue_present;
- chain->base.image_fns = image_fns;
chain->base.present_mode = pCreateInfo->presentMode;
chain->base.image_count = num_images;
chain->conn = conn;
chain->threaded = false;
chain->status = VK_SUCCESS;
-
- chain->base.needs_linear_copy = false;
if (!wsi_x11_check_dri3_compatible(conn, local_fd))
- chain->base.needs_linear_copy = true;
+ chain->base.use_prime_blit = true;
chain->event_id = xcb_generate_id(chain->conn);
xcb_present_select_input(chain->conn, chain->event_id, chain->window,
fail_register:
xcb_unregister_for_special_event(chain->conn, chain->special_event);
+ wsi_swapchain_finish(&chain->base);
+
+fail_alloc:
vk_free(pAllocator, chain);
return result;