From 32597e116d7317127ef8a7caf8dc75b50f48b8e1 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Tue, 11 Jan 2022 13:57:00 -0500 Subject: [PATCH] zink: implement GL semaphores this is basically just a wrapper around vulkan semaphores, so it maps fairly well the existing fence function was a big ??? and should never have been triggered like it was Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_batch.c | 20 +++++--- src/gallium/drivers/zink/zink_batch.h | 3 ++ src/gallium/drivers/zink/zink_context.c | 2 + src/gallium/drivers/zink/zink_fence.c | 68 ++++++++++++++++++++++--- src/gallium/drivers/zink/zink_fence.h | 5 ++ 5 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index b0674f8f1ab..2ea50393a5c 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -96,6 +96,9 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs) pipe_resource_reference(&bs->flush_res, NULL); bs->resource_size = 0; + bs->signal_semaphore = VK_NULL_HANDLE; + util_dynarray_clear(&bs->wait_semaphores); + util_dynarray_clear(&bs->wait_semaphore_stages); /* only reset submitted here so that tc fence desync can pick up the 'completed' flag * before the state is reused @@ -222,6 +225,8 @@ create_batch_state(struct zink_context *ctx) SET_CREATE_OR_FAIL(bs->bufferviews); SET_CREATE_OR_FAIL(bs->programs); SET_CREATE_OR_FAIL(bs->active_queries); + util_dynarray_init(&bs->wait_semaphores, NULL); + util_dynarray_init(&bs->wait_semaphore_stages, NULL); util_dynarray_init(&bs->zombie_samplers, NULL); util_dynarray_init(&bs->dead_framebuffers, NULL); util_dynarray_init(&bs->persistent_resources, NULL); @@ -369,11 +374,9 @@ submit_queue(void *data, void *gdata, int thread_index) uint64_t batch_id = bs->fence.batch_id; si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - si.waitSemaphoreCount = 0; - si.pWaitSemaphores = NULL; - si.signalSemaphoreCount = 0; - si.pSignalSemaphores = NULL; - si.pWaitDstStageMask = NULL; + si.waitSemaphoreCount = util_dynarray_num_elements(&bs->wait_semaphores, VkSemaphore); + si.pWaitSemaphores = bs->wait_semaphores.data; + si.pWaitDstStageMask = bs->wait_semaphore_stages.data; si.commandBufferCount = bs->has_barriers ? 2 : 1; VkCommandBuffer cmdbufs[2] = { bs->barrier_cmdbuf, @@ -381,14 +384,17 @@ submit_queue(void *data, void *gdata, int thread_index) }; si.pCommandBuffers = bs->has_barriers ? cmdbufs : &cmdbufs[1]; + VkSemaphore signals[2]; + si.signalSemaphoreCount = !!bs->signal_semaphore; + signals[0] = bs->signal_semaphore; + si.pSignalSemaphores = signals; VkTimelineSemaphoreSubmitInfo tsi = {0}; if (bs->have_timelines) { tsi.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; si.pNext = &tsi; tsi.signalSemaphoreValueCount = 1; tsi.pSignalSemaphoreValues = &batch_id; - si.signalSemaphoreCount = 1; - si.pSignalSemaphores = &screen->sem; + signals[si.signalSemaphoreCount++] = screen->sem; } struct wsi_memory_signal_submit_info mem_signal = { diff --git a/src/gallium/drivers/zink/zink_batch.h b/src/gallium/drivers/zink/zink_batch.h index ddf668f3d69..1e1b3f39329 100644 --- a/src/gallium/drivers/zink/zink_batch.h +++ b/src/gallium/drivers/zink/zink_batch.h @@ -68,6 +68,9 @@ struct zink_batch_state { VkCommandPool cmdpool; VkCommandBuffer cmdbuf; VkCommandBuffer barrier_cmdbuf; + VkSemaphore signal_semaphore; //external signal semaphore + struct util_dynarray wait_semaphores; //external wait semaphores + struct util_dynarray wait_semaphore_stages; //external wait semaphores VkQueue queue; //duplicated from batch for threading VkSemaphore sem; diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 38cacca5409..9c0fe34fda3 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -4115,7 +4115,9 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->base.clear_render_target = zink_clear_render_target; ctx->base.clear_depth_stencil = zink_clear_depth_stencil; + ctx->base.create_fence_fd = zink_create_fence_fd; ctx->base.fence_server_sync = zink_fence_server_sync; + ctx->base.fence_server_signal = zink_fence_server_signal; ctx->base.flush = zink_flush; ctx->base.memory_barrier = zink_memory_barrier; ctx->base.texture_barrier = zink_texture_barrier; diff --git a/src/gallium/drivers/zink/zink_fence.c b/src/gallium/drivers/zink/zink_fence.c index b2118618bc0..dbc4f9b3fec 100644 --- a/src/gallium/drivers/zink/zink_fence.c +++ b/src/gallium/drivers/zink/zink_fence.c @@ -36,6 +36,7 @@ destroy_fence(struct zink_screen *screen, struct zink_tc_fence *mfence) { mfence->fence = NULL; tc_unflushed_batch_token_reference(&mfence->tc_token, NULL); + VKSCR(DestroySemaphore)(screen->dev, mfence->sem, NULL); FREE(mfence); } @@ -196,20 +197,73 @@ fence_finish(struct pipe_screen *pscreen, struct pipe_context *pctx, timeout_ns); } +void +zink_fence_server_signal(struct pipe_context *pctx, struct pipe_fence_handle *pfence) +{ + struct zink_context *ctx = zink_context(pctx); + struct zink_tc_fence *mfence = (struct zink_tc_fence *)pfence; + + assert(!ctx->batch.state->signal_semaphore); + /* this is a deferred flush to reduce overhead */ + ctx->batch.state->signal_semaphore = mfence->sem; + pctx->flush(pctx, NULL, PIPE_FLUSH_ASYNC); +} + void zink_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *pfence) { - struct zink_tc_fence *mfence = zink_tc_fence(pfence); + struct zink_context *ctx = zink_context(pctx); + struct zink_tc_fence *mfence = (struct zink_tc_fence *)pfence; - if (mfence->deferred_ctx == pctx) + if (mfence->deferred_ctx == pctx || !mfence->sem) return; - if (mfence->deferred_ctx) { - zink_context(pctx)->batch.has_work = true; - /* this must be the current batch */ - pctx->flush(pctx, NULL, 0); + mfence->deferred_ctx = pctx; + /* this will be applied on the next submit */ + VkPipelineStageFlags flag = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + util_dynarray_append(&ctx->batch.state->wait_semaphores, VkSemaphore, mfence->sem); + util_dynarray_append(&ctx->batch.state->wait_semaphore_stages, VkPipelineStageFlags, flag); +} + +void +zink_create_fence_fd(struct pipe_context *pctx, struct pipe_fence_handle **pfence, int fd, enum pipe_fd_type type) +{ + struct zink_screen *screen = zink_screen(pctx->screen); + VkResult ret = VK_ERROR_UNKNOWN; + VkSemaphoreCreateInfo sci = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + NULL, + 0 + }; + struct zink_tc_fence *mfence = zink_create_tc_fence(); + VkExternalSemaphoreHandleTypeFlagBits flags[] = { + [PIPE_FD_TYPE_NATIVE_SYNC] = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + [PIPE_FD_TYPE_SYNCOBJ] = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + }; + VkImportSemaphoreFdInfoKHR sdi = {0}; + assert(type < ARRAY_SIZE(flags)); + + *pfence = NULL; + + if (VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &mfence->sem) != VK_SUCCESS) { + FREE(mfence); + return; } - zink_fence_finish(zink_screen(pctx->screen), pctx, mfence, PIPE_TIMEOUT_INFINITE); + + sdi.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; + sdi.semaphore = mfence->sem; + sdi.handleType = flags[type]; + sdi.fd = fd; + ret = VKSCR(ImportSemaphoreFdKHR)(screen->dev, &sdi); + + if (!zink_screen_handle_vkresult(screen, ret)) + goto fail; + *pfence = (struct pipe_fence_handle *)mfence; + return; + +fail: + VKSCR(DestroySemaphore)(screen->dev, mfence->sem, NULL); + FREE(mfence); } void diff --git a/src/gallium/drivers/zink/zink_fence.h b/src/gallium/drivers/zink/zink_fence.h index e900a4c69c0..a9b08914fec 100644 --- a/src/gallium/drivers/zink/zink_fence.h +++ b/src/gallium/drivers/zink/zink_fence.h @@ -46,6 +46,7 @@ struct zink_tc_fence { struct tc_unflushed_batch_token *tc_token; struct pipe_context *deferred_ctx; struct zink_fence *fence; + VkSemaphore sem; }; struct zink_fence { @@ -78,6 +79,10 @@ zink_fence_reference(struct zink_screen *screen, struct zink_tc_fence **ptr, struct zink_tc_fence *fence); +void +zink_create_fence_fd(struct pipe_context *pctx, struct pipe_fence_handle **pfence, int fd, enum pipe_fd_type type); +void +zink_fence_server_signal(struct pipe_context *pctx, struct pipe_fence_handle *pfence); void zink_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *pfence);