From 45f9208cca1a5b87f778ed96bf1d791740c9f162 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Wed, 12 Feb 2025 11:55:42 +0100 Subject: [PATCH] v3dv: improve handling of trailing barriers When a command buffer ends with pending barriers we were emitting a serialized noop job, but this only works to ensure serialization of follow-up CL jobs, it won't do what we want if the barrier was intended for compute or TFU transfers for example. Fix this by merging the barrier state into follow-up jobs in the same queue submission. Reviewed-by: Juan A. Suarez Part-of: --- src/broadcom/vulkan/v3dv_queue.c | 39 ++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/broadcom/vulkan/v3dv_queue.c b/src/broadcom/vulkan/v3dv_queue.c index 2db8f6cecd5..6038d477ca5 100644 --- a/src/broadcom/vulkan/v3dv_queue.c +++ b/src/broadcom/vulkan/v3dv_queue.c @@ -1171,13 +1171,34 @@ handle_csd_job(struct v3dv_queue *queue, return VK_SUCCESS; } +static void +queue_apply_barrier_state(struct v3dv_job *job, + struct v3dv_barrier_state *barrier) +{ + if (!v3dv_job_apply_barrier_state(job, barrier)) + return; + + if (job->type != V3DV_JOB_TYPE_GPU_CL) + return; + + if (job->serialize && + (barrier->bcl_buffer_access || barrier->bcl_image_access)) { + job->needs_bcl_sync = true; + barrier->bcl_buffer_access = barrier->bcl_image_access = 0; + } +} + static VkResult queue_handle_job(struct v3dv_queue *queue, struct v3dv_job *job, uint32_t counter_pass_idx, + struct v3dv_barrier_state *barrier, struct v3dv_submit_sync_info *sync_info, bool signal_syncs) { + if (barrier) + queue_apply_barrier_state(job, barrier); + if (unlikely(V3D_DBG(SYNC))) { job->serialize = V3DV_BARRIER_ALL; job->needs_bcl_sync = job->type == V3DV_JOB_TYPE_GPU_CL; @@ -1240,7 +1261,7 @@ queue_submit_noop_job(struct v3dv_queue *queue, } assert(queue->noop_job); - return queue_handle_job(queue, queue->noop_job, counter_pass_idx, + return queue_handle_job(queue, queue->noop_job, counter_pass_idx, NULL, sync_info, signal_syncs); } @@ -1262,6 +1283,7 @@ v3dv_queue_driver_submit(struct vk_queue *vk_queue, for (int i = 0; i < V3DV_QUEUE_COUNT; i++) queue->last_job_syncs.first[i] = true; + struct v3dv_barrier_state pending_barrier = { 0 }; struct v3dv_job *first_suspend_job = NULL; struct v3dv_job *current_suspend_job = NULL; for (uint32_t i = 0; i < submit->command_buffer_count; i++) { @@ -1299,7 +1321,7 @@ v3dv_queue_driver_submit(struct vk_queue *vk_queue, first_suspend_job : job; result = queue_handle_job(queue, submit_job, submit->perf_pass_index, - &sync_info, false); + &pending_barrier, &sync_info, false); if (result != VK_SUCCESS) return result; @@ -1308,17 +1330,10 @@ v3dv_queue_driver_submit(struct vk_queue *vk_queue, } } - /* If the command buffer ends with a barrier we need to consume it now. - * - * FIXME: this will drain all hw queues. Instead, we could use the pending - * barrier state to limit the queues we serialize against. + /* If the command buffer ends with a barrier, save the pending barrier + * state so we can apply it on the next command buffer. */ - if (cmd_buffer->state.barrier.dst_mask) { - result = queue_submit_noop_job(queue, submit->perf_pass_index, - &sync_info, false); - if (result != VK_SUCCESS) - return result; - } + v3dv_merge_barrier_state(&pending_barrier, &cmd_buffer->state.barrier); } assert(!first_suspend_job);