[Mesa-dev] [RFC v2 4/5] vulkan: Add support for out-fences in vkAcquireNextImage
Louis-Francis Ratté-Boulianne
lfrb at collabora.com
Thu Sep 28 08:25:27 UTC 2017
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
---
src/vulkan/wsi/wsi_common.h | 3 +
src/vulkan/wsi/wsi_common_x11.c | 152 +++++++++++++++++++++++++++++++---------
2 files changed, 121 insertions(+), 34 deletions(-)
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index e81c7be11a..9375678e82 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -61,6 +61,9 @@ struct wsi_image_fns {
const VkSemaphore *semaphores,
uint32_t semaphore_count,
int *fd);
+ VkResult (*import_semaphore_fd)(VkDevice device,
+ VkSemaphore semaphore,
+ int fd);
};
struct wsi_swapchain {
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index 1179eed9c7..1f6ba6da55 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -655,6 +655,7 @@ struct x11_image {
bool busy;
struct xshmfence * shm_fence;
uint32_t wait_fence;
+ uint32_t idle_fence;
uint32_t sync_fence;
};
@@ -745,6 +746,7 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain,
for (unsigned i = 0; i < chain->base.image_count; i++) {
if (chain->images[i].pixmap == idle->pixmap) {
+ chain->images[i].idle_fence = idle->idle_fence;
chain->images[i].busy = false;
if (chain->images[i].wait_fence) {
xcb_void_cookie_t cookie;
@@ -804,21 +806,79 @@ static uint64_t wsi_get_absolute_timeout(uint64_t timeout)
return current_time + timeout;
}
+static int
+x11_wait_for_fence(struct x11_swapchain *chain,
+ struct x11_image *image,
+ VkSemaphore semaphore)
+{
+ VkResult ret = VK_SUCCESS;
+
+#if XCB_DRI3_MAJOR_VERSION > 1 || XCB_DRI3_MINOR_VERSION >= 2
+ if (image->idle_fence) {
+ xcb_void_cookie_t tmp_cookie;
+
+ if (semaphore) {
+ struct wsi_swapchain *anv_chain = (struct wsi_swapchain *)chain;
+ xcb_dri3_dma_fence_fd_from_fence_cookie_t cookie;
+ xcb_dri3_dma_fence_fd_from_fence_reply_t *reply;
+ xcb_generic_error_t *error = NULL;
+ int *fds;
+
+ cookie = xcb_dri3_dma_fence_fd_from_fence(chain->conn,
+ image->pixmap,
+ image->idle_fence);
+ reply = xcb_dri3_dma_fence_fd_from_fence_reply(chain->conn,
+ cookie,
+ &error);
+ if (error)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ fds = xcb_dri3_dma_fence_fd_from_fence_reply_fds(chain->conn,
+ reply);
+ free(reply);
+ ret = chain->base.image_fns->import_semaphore_fd(anv_chain->device,
+ semaphore, fds[0]);
+ if (ret != VK_SUCCESS)
+ close(fds[0]);
+ } else {
+ xcb_sync_await_fence_checked(chain->conn, 1, &image->idle_fence);
+ }
+ tmp_cookie = xcb_sync_destroy_fence(chain->conn, image->idle_fence);
+ xcb_discard_reply(chain->conn, tmp_cookie.sequence);
+ image->idle_fence = 0;
+ } else if (!chain->has_dma_fence)
+#endif
+ {
+ xshmfence_await(image->shm_fence);
+ }
+
+ return ret;
+}
+
static VkResult
x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
- uint32_t *image_index, uint64_t timeout)
+ uint32_t *image_index,
+ VkSemaphore semaphore,
+ uint64_t timeout)
{
xcb_generic_event_t *event;
struct pollfd pfds;
uint64_t atimeout;
while (1) {
- for (uint32_t i = 0; i < chain->base.image_count; i++) {
- if (!chain->images[i].busy) {
- /* We found a non-busy image */
- xshmfence_await(chain->images[i].shm_fence);
- *image_index = i;
- chain->images[i].busy = true;
- return VK_SUCCESS;
+ // XXX first pass, try to find non-busy images, second pass, idle_fence is fine
+ // XXX if there is no semaphore, we need to wait for the fence
+ // XXX this way we can use all available images instead of waiting for the first
+ // XXX one to be free. (problem is we might wait for an older one if all queued)
+ uint32_t num_passes = chain->has_dma_fence ? 2 : 1;
+
+ for (uint32_t p = 0; p < num_passes; p++) {
+ for (uint32_t i = 0; i < chain->base.image_count; i++) {
+ if (!chain->images[i].busy &&
+ ((p == 0 && !chain->images[i].idle_fence) || p == 1)) {
+ x11_wait_for_fence(chain, &chain->images[i], semaphore);
+ *image_index = i;
+ chain->images[i].busy = true;
+ return VK_SUCCESS;
+ }
}
}
@@ -866,7 +926,9 @@ x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
static VkResult
x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
- uint32_t *image_index_out, uint64_t timeout)
+ uint32_t *image_index_out,
+ VkSemaphore semaphore,
+ uint64_t timeout)
{
assert(chain->threaded);
@@ -880,7 +942,7 @@ x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
}
assert(image_index < chain->base.image_count);
- xshmfence_await(chain->images[image_index].shm_fence);
+ x11_wait_for_fence(chain, &chain->images[image_index], semaphore);
*image_index_out = image_index;
@@ -899,11 +961,19 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
int64_t divisor = 0;
int64_t remainder = 0;
+ uint32_t idle_fence = image->sync_fence;
if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
options |= XCB_PRESENT_OPTION_ASYNC;
- xshmfence_reset(image->shm_fence);
+ if (chain->has_dma_fence) {
+#if XCB_PRESENT_MAJOR_VERSION > 1 || XCB_PRESENT_MINOR_VERSION >= 2
+ options |= XCB_PRESENT_OPTION_IDLE_FENCE;
+ idle_fence = xcb_generate_id(chain->conn);
+#endif
+ } else {
+ xshmfence_reset(image->shm_fence);
+ }
++chain->send_sbc;
xcb_void_cookie_t cookie =
@@ -917,7 +987,7 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
0, /* y_off */
XCB_NONE, /* target_crtc */
image->wait_fence,
- image->sync_fence,
+ idle_fence,
options,
target_msc,
divisor,
@@ -941,9 +1011,11 @@ x11_acquire_next_image(struct wsi_swapchain *anv_chain,
VkResult result;
if (chain->threaded) {
- result = x11_acquire_next_image_from_queue(chain, image_index, timeout);
+ result = x11_acquire_next_image_from_queue(chain, image_index,
+ semaphore, timeout);
} else {
- result = x11_acquire_next_image_poll_x11(chain, image_index, timeout);
+ result = x11_acquire_next_image_poll_x11(chain, image_index,
+ semaphore, timeout);
}
if (result != VK_SUCCESS) {
@@ -1159,28 +1231,32 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
image->wait_fence = 0;
image->busy = false;
- int fence_fd = xshmfence_alloc_shm();
- if (fence_fd < 0)
- goto fail_pixmap;
-
- image->shm_fence = xshmfence_map_shm(fence_fd);
- if (image->shm_fence == NULL)
- goto fail_shmfence_alloc;
+ if (chain->has_dma_fence) {
+ image->shm_fence = 0;
+ image->sync_fence = 0;
+ } else {
+ int fence_fd = xshmfence_alloc_shm();
+ if (fence_fd < 0)
+ goto fail_pixmap;
+
+ image->shm_fence = xshmfence_map_shm(fence_fd);
+ if (image->shm_fence == NULL) {
+ close(fence_fd);
+ goto fail_pixmap;
+ }
- image->sync_fence = xcb_generate_id(chain->conn);
- xcb_dri3_fence_from_fd(chain->conn,
- image->pixmap,
- image->sync_fence,
- false,
- fence_fd);
+ image->sync_fence = xcb_generate_id(chain->conn);
+ xcb_dri3_fence_from_fd(chain->conn,
+ image->pixmap,
+ image->sync_fence,
+ false,
+ fence_fd);
- xshmfence_trigger(image->shm_fence);
+ xshmfence_trigger(image->shm_fence);
+ }
return VK_SUCCESS;
-fail_shmfence_alloc:
- close(fence_fd);
-
fail_pixmap:
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
@@ -1197,9 +1273,11 @@ x11_image_finish(struct x11_swapchain *chain,
{
xcb_void_cookie_t cookie;
- cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
- xcb_discard_reply(chain->conn, cookie.sequence);
- xshmfence_unmap_shm(image->shm_fence);
+ if (!chain->has_dma_fence) {
+ cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
+ xcb_discard_reply(chain->conn, cookie.sequence);
+ xshmfence_unmap_shm(image->shm_fence);
+ }
if (image->wait_fence) {
cookie = xcb_sync_destroy_fence(chain->conn, image->wait_fence);
@@ -1207,6 +1285,12 @@ x11_image_finish(struct x11_swapchain *chain,
image->wait_fence = 0;
}
+ if (image->idle_fence) {
+ cookie = xcb_sync_destroy_fence(chain->conn, image->idle_fence);
+ xcb_discard_reply(chain->conn, cookie.sequence);
+ image->idle_fence = 0;
+ }
+
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
--
2.13.0
More information about the mesa-dev
mailing list