From 0f04a90ea331da353634c686600cc1bc93def71a Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 15 Jan 2021 13:21:09 -0500 Subject: [PATCH] zink: emit some barriers out of renderpass where possible when emitting barriers, we don't need to end the renderpass in some cases this handles the case of emitting barriers for new resources which have never before been accessed and thus do not require synchronization at a specific point in the batch Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_batch.c | 20 +++++++++- src/gallium/drivers/zink/zink_batch.h | 2 + src/gallium/drivers/zink/zink_context.c | 47 +++++++++++++++++++----- src/gallium/drivers/zink/zink_resource.c | 1 + src/gallium/drivers/zink/zink_resource.h | 1 + 5 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index bef60cb06df..cedada5af04 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -96,6 +96,7 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs) * before the state is reused */ bs->fence.submitted = false; + bs->has_barriers = false; zink_screen_update_last_finished(screen, bs->fence.batch_id); bs->fence.batch_id = 0; bs->work_count[0] = bs->work_count[1] = 0; @@ -135,6 +136,8 @@ zink_batch_state_destroy(struct zink_screen *screen, struct zink_batch_state *bs if (bs->cmdbuf) vkFreeCommandBuffers(screen->dev, bs->cmdpool, 1, &bs->cmdbuf); + if (bs->barrier_cmdbuf) + vkFreeCommandBuffers(screen->dev, bs->cmdpool, 1, &bs->barrier_cmdbuf); if (bs->cmdpool) vkDestroyCommandPool(screen->dev, bs->cmdpool, NULL); @@ -171,6 +174,9 @@ create_batch_state(struct zink_context *ctx) if (vkAllocateCommandBuffers(screen->dev, &cbai, &bs->cmdbuf) != VK_SUCCESS) goto fail; + if (vkAllocateCommandBuffers(screen->dev, &cbai, &bs->barrier_cmdbuf) != VK_SUCCESS) + goto fail; + #define SET_CREATE_OR_FAIL(ptr) \ ptr = _mesa_pointer_set_create(bs); \ if (!ptr) \ @@ -279,6 +285,8 @@ zink_start_batch(struct zink_context *ctx, struct zink_batch *batch) cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; if (vkBeginCommandBuffer(batch->state->cmdbuf, &cbbi) != VK_SUCCESS) debug_printf("vkBeginCommandBuffer failed\n"); + if (vkBeginCommandBuffer(batch->state->barrier_cmdbuf, &cbbi) != VK_SUCCESS) + debug_printf("vkBeginCommandBuffer failed\n"); batch->state->fence.batch_id = ctx->curr_batch; batch->state->fence.completed = false; @@ -317,8 +325,12 @@ submit_queue(void *data, int thread_index) si.signalSemaphoreCount = 0; si.pSignalSemaphores = NULL; si.pWaitDstStageMask = NULL; - si.commandBufferCount = 1; - si.pCommandBuffers = &bs->cmdbuf; + si.commandBufferCount = bs->has_barriers ? 2 : 1; + VkCommandBuffer cmdbufs[2] = { + bs->barrier_cmdbuf, + bs->cmdbuf, + }; + si.pCommandBuffers = bs->has_barriers ? cmdbufs : &cmdbufs[1]; VkTimelineSemaphoreSubmitInfo tsi = {}; if (bs->have_timelines) { @@ -485,6 +497,10 @@ zink_end_batch(struct zink_context *ctx, struct zink_batch *batch) debug_printf("vkEndCommandBuffer failed\n"); return; } + if (vkEndCommandBuffer(batch->state->barrier_cmdbuf) != VK_SUCCESS) { + debug_printf("vkEndCommandBuffer failed\n"); + return; + } vkResetFences(zink_screen(ctx->base.screen)->dev, 1, &batch->state->fence.fence); struct zink_screen *screen = zink_screen(ctx->base.screen); diff --git a/src/gallium/drivers/zink/zink_batch.h b/src/gallium/drivers/zink/zink_batch.h index 566c230ae98..b8e467d8baa 100644 --- a/src/gallium/drivers/zink/zink_batch.h +++ b/src/gallium/drivers/zink/zink_batch.h @@ -55,6 +55,8 @@ struct zink_batch_state { struct zink_context *ctx; VkCommandPool cmdpool; VkCommandBuffer cmdbuf; + VkCommandBuffer barrier_cmdbuf; + bool has_barriers; 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 ae0f1981cf3..32e79a5cc48 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -1803,6 +1803,20 @@ zink_resource_image_barrier_init(VkImageMemoryBarrier *imb, struct zink_resource return zink_resource_image_needs_barrier(res, new_layout, flags, pipeline); } +static inline VkCommandBuffer +get_cmdbuf(struct zink_context *ctx, struct zink_resource *res) +{ + if ((res->access && !res->unordered_barrier) || !ctx->batch.in_rp) { + struct zink_batch *batch = zink_batch_no_rp(ctx); + assert(!batch->in_rp); + res->unordered_barrier = false; + return batch->state->cmdbuf; + } + res->unordered_barrier = true; + ctx->batch.state->has_barriers = true; + return ctx->batch.state->barrier_cmdbuf; +} + void zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *res, VkImageLayout new_layout, VkAccessFlags flags, VkPipelineStageFlags pipeline) @@ -1813,11 +1827,10 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch, if (!pipeline) pipeline = pipeline_dst_stage(new_layout); /* only barrier if we're changing layout or doing something besides read -> read */ - batch = zink_batch_no_rp(ctx); - assert(!batch->in_rp); + VkCommandBuffer cmdbuf = get_cmdbuf(ctx, res); assert(new_layout); vkCmdPipelineBarrier( - batch->state->cmdbuf, + cmdbuf, res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, pipeline, 0, @@ -1826,9 +1839,14 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch, 1, &imb ); + if (res->unordered_barrier) { + res->access |= imb.dstAccessMask; + res->access_stage |= pipeline; + } else { + res->access = imb.dstAccessMask; + res->access_stage = pipeline; + } res->layout = new_layout; - res->access_stage = pipeline; - res->access = imb.dstAccessMask; } @@ -1908,11 +1926,13 @@ zink_resource_buffer_barrier(struct zink_context *ctx, struct zink_batch *batch, return; if (!pipeline) pipeline = pipeline_access_stage(flags); + if (!zink_resource_buffer_needs_barrier(res, flags, pipeline)) + return; + + VkCommandBuffer cmdbuf = get_cmdbuf(ctx, res); /* only barrier if we're changing layout or doing something besides read -> read */ - batch = zink_batch_no_rp(ctx); - assert(!batch->in_rp); vkCmdPipelineBarrier( - batch->state->cmdbuf, + cmdbuf, res->access_stage ? res->access_stage : pipeline_access_stage(res->access), pipeline, 0, @@ -1920,8 +1940,14 @@ zink_resource_buffer_barrier(struct zink_context *ctx, struct zink_batch *batch, 1, &bmb, 0, NULL ); - res->access = bmb.dstAccessMask; - res->access_stage = pipeline; + + if (res->unordered_barrier) { + res->access |= bmb.dstAccessMask; + res->access_stage |= pipeline; + } else { + res->access = bmb.dstAccessMask; + res->access_stage = pipeline; + } } bool @@ -2806,6 +2832,7 @@ zink_context_replace_buffer_storage(struct pipe_context *pctx, struct pipe_resou zink_resource_object_reference(zink_screen(pctx->screen), &d->obj, s->obj); d->access = s->access; d->access_stage = s->access_stage; + d->unordered_barrier = s->unordered_barrier; zink_resource_rebind(zink_context(pctx), d); } diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index b8ec6dfc648..8cb062bc5d6 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -718,6 +718,7 @@ invalidate_buffer(struct zink_context *ctx, struct zink_resource *res) res->obj = new_obj; res->access_stage = 0; res->access = 0; + res->unordered_barrier = false; zink_resource_rebind(ctx, res); zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj); zink_resource_object_reference(screen, &old_obj, NULL); diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h index 8e7b37eec0f..d2caf0a2f3e 100644 --- a/src/gallium/drivers/zink/zink_resource.h +++ b/src/gallium/drivers/zink/zink_resource.h @@ -86,6 +86,7 @@ struct zink_resource { VkPipelineStageFlagBits access_stage; VkAccessFlags access; + bool unordered_barrier; struct zink_resource_object *obj; struct zink_resource_object *scanout_obj; //TODO: remove for wsi