From 16c96b0e9358c8727f9af29a7fc7fe9879cad45a Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Wed, 3 Apr 2024 11:13:38 +0200 Subject: [PATCH] v3dv: drop single sync kernel interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are now requiring a multisync kernel interface there is no reason to continue supporting the legacy interface. Reviewed-by: Alejandro PiƱeiro Part-of: --- src/broadcom/vulkan/v3dv_queue.c | 379 +++++++------------------------ 1 file changed, 85 insertions(+), 294 deletions(-) diff --git a/src/broadcom/vulkan/v3dv_queue.c b/src/broadcom/vulkan/v3dv_queue.c index 37483ff66fa..41277f04059 100644 --- a/src/broadcom/vulkan/v3dv_queue.c +++ b/src/broadcom/vulkan/v3dv_queue.c @@ -74,47 +74,31 @@ static VkResult queue_wait_idle(struct v3dv_queue *queue, struct v3dv_submit_sync_info *sync_info) { - if (queue->device->pdevice->caps.multisync) { - int ret = drmSyncobjWait(queue->device->pdevice->render_fd, - queue->last_job_syncs.syncs, 4, - INT64_MAX, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, - NULL); - if (ret) { - return vk_errorf(queue, VK_ERROR_DEVICE_LOST, - "syncobj wait failed: %m"); - } + int ret = drmSyncobjWait(queue->device->pdevice->render_fd, + queue->last_job_syncs.syncs, 4, + INT64_MAX, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, + NULL); + if (ret) + return vk_errorf(queue, VK_ERROR_DEVICE_LOST, "syncobj wait failed: %m"); - bool first = true; - for (int i = 0; i < 4; i++) { - if (!queue->last_job_syncs.first[i]) - first = false; - } + bool first = true; + for (int i = 0; i < 4; i++) { + if (!queue->last_job_syncs.first[i]) + first = false; + } - /* If we're not the first job, that means we're waiting on some - * per-queue-type syncobj which transitively waited on the semaphores - * so we can skip the semaphore wait. - */ - if (first) { - VkResult result = vk_sync_wait_many(&queue->device->vk, - sync_info->wait_count, - sync_info->waits, - VK_SYNC_WAIT_COMPLETE, - UINT64_MAX); - if (result != VK_SUCCESS) - return result; - } - } else { - /* Without multisync, all the semaphores are baked into the one syncobj - * at the start of each submit so we only need to wait on the one. - */ - int ret = drmSyncobjWait(queue->device->pdevice->render_fd, - &queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], 1, - INT64_MAX, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, - NULL); - if (ret) { - return vk_errorf(queue, VK_ERROR_DEVICE_LOST, - "syncobj wait failed: %m"); - } + /* If we're not the first job, that means we're waiting on some + * per-queue-type syncobj which transitively waited on the semaphores + * so we can skip the semaphore wait. + */ + if (first) { + VkResult result = vk_sync_wait_many(&queue->device->vk, + sync_info->wait_count, + sync_info->waits, + VK_SYNC_WAIT_COMPLETE, + UINT64_MAX); + if (result != VK_SUCCESS) + return result; } for (int i = 0; i < 4; i++) @@ -469,45 +453,35 @@ static VkResult export_perfmon_last_job_sync(struct v3dv_queue *queue, struct v3dv_job *job, int *fd) { int err; - if (job->device->pdevice->caps.multisync) { - static const enum v3dv_queue_type queues_to_sync[] = { - V3DV_QUEUE_CL, - V3DV_QUEUE_CSD, - }; + static const enum v3dv_queue_type queues_to_sync[] = { + V3DV_QUEUE_CL, + V3DV_QUEUE_CSD, + }; - for (uint32_t i = 0; i < ARRAY_SIZE(queues_to_sync); i++) { - enum v3dv_queue_type queue_type = queues_to_sync[i]; - int tmp_fd = -1; + for (uint32_t i = 0; i < ARRAY_SIZE(queues_to_sync); i++) { + enum v3dv_queue_type queue_type = queues_to_sync[i]; + int tmp_fd = -1; - err = drmSyncobjExportSyncFile(job->device->pdevice->render_fd, - queue->last_job_syncs.syncs[queue_type], - &tmp_fd); - - if (err) { - close(*fd); - return vk_errorf(&job->device->queue, VK_ERROR_UNKNOWN, - "sync file export failed: %m"); - } - - err = sync_accumulate("v3dv", fd, tmp_fd); - - if (err) { - close(tmp_fd); - close(*fd); - return vk_errorf(&job->device->queue, VK_ERROR_UNKNOWN, - "failed to accumulate sync files: %m"); - } - } - } else { err = drmSyncobjExportSyncFile(job->device->pdevice->render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - fd); + queue->last_job_syncs.syncs[queue_type], + &tmp_fd); if (err) { + close(*fd); return vk_errorf(&job->device->queue, VK_ERROR_UNKNOWN, "sync file export failed: %m"); } + + err = sync_accumulate("v3dv", fd, tmp_fd); + + if (err) { + close(tmp_fd); + close(*fd); + return vk_errorf(&job->device->queue, VK_ERROR_UNKNOWN, + "failed to accumulate sync files: %m"); + } } + return VK_SUCCESS; } @@ -921,147 +895,6 @@ handle_csd_indirect_cpu_job(struct v3dv_queue *queue, return VK_SUCCESS; } -/** - * This handles semaphore waits for the single sync path by accumulating - * wait semaphores into the QUEUE_ANY syncobj. Notice this is only required - * to ensure we accumulate any *external* semaphores (since for anything else - * we are already accumulating out syncs with each submission to the kernel). - */ -static VkResult -process_singlesync_waits(struct v3dv_queue *queue, - uint32_t count, struct vk_sync_wait *waits) -{ - struct v3dv_device *device = queue->device; - assert(!device->pdevice->caps.multisync); - - if (count == 0) - return VK_SUCCESS; - - VkResult result = VK_SUCCESS; - - int err = 0; - int fd = -1; - err = drmSyncobjExportSyncFile(device->pdevice->render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - &fd); - if (err) { - result = vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file export failed: %m"); - goto fail; - } - - for (uint32_t i = 0; i < count; i++) { - uint32_t syncobj = vk_sync_as_drm_syncobj(waits[i].sync)->syncobj; - int wait_fd = -1; - - err = drmSyncobjExportSyncFile(device->pdevice->render_fd, - syncobj, &wait_fd); - if (err) { - result = vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file export failed: %m"); - goto fail; - } - - err = sync_accumulate("v3dv", &fd, wait_fd); - close(wait_fd); - if (err) { - result = vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file merge failed: %m"); - goto fail; - } - } - - err = drmSyncobjImportSyncFile(device->pdevice->render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - fd); - if (err) { - result = vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file import failed: %m"); - } - -fail: - close(fd); - return result; -} - -/** - * This handles signaling for the single-sync path by importing the QUEUE_ANY - * syncobj into all syncs to be signaled. - */ -static VkResult -process_singlesync_signals(struct v3dv_queue *queue, - uint32_t count, struct vk_sync_signal *signals) -{ - struct v3dv_device *device = queue->device; - assert(!device->pdevice->caps.multisync && count > 0); - - if (device->pdevice->caps.multisync) - return VK_SUCCESS; - - int fd = -1; - drmSyncobjExportSyncFile(device->pdevice->render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - &fd); - if (fd == -1) { - return vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file export failed: %m"); - } - - VkResult result = VK_SUCCESS; - for (uint32_t i = 0; i < count; i++) { - uint32_t syncobj = vk_sync_as_drm_syncobj(signals[i].sync)->syncobj; - int err = drmSyncobjImportSyncFile(device->pdevice->render_fd, - syncobj, fd); - if (err) { - result = vk_errorf(queue, VK_ERROR_UNKNOWN, - "sync file import failed: %m"); - break; - } - } - - assert(fd >= 0); - close(fd); - - return result; -} - -/* This must be called after every submission in the single-sync path to - * accumulate the out_sync into the QUEUE_ANY sync so we can serialize - * jobs by waiting on the QUEUE_ANY sync. - */ -static int -update_any_queue_sync(struct v3dv_queue *queue, uint32_t out_sync) -{ - struct v3dv_device *device = queue->device; - assert(!device->pdevice->caps.multisync); - - int render_fd = device->pdevice->render_fd; - int fd_any = -1, fd_out_sync = -1; - int err; - err = drmSyncobjExportSyncFile(render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - &fd_any); - if (err) - goto fail; - - err = drmSyncobjExportSyncFile(render_fd, out_sync, &fd_out_sync); - if (err) - goto fail; - - err = sync_accumulate("v3dv", &fd_any, fd_out_sync); - if (err) - goto fail; - - err = drmSyncobjImportSyncFile(render_fd, - queue->last_job_syncs.syncs[V3DV_QUEUE_ANY], - fd_any); - -fail: - close(fd_any); - close(fd_out_sync); - return err; -} - static VkResult handle_cl_job(struct v3dv_queue *queue, struct v3dv_job *job, @@ -1162,25 +995,19 @@ handle_cl_job(struct v3dv_queue *queue, * multiple semaphores extension. */ struct drm_v3d_multi_sync ms = { 0 }; - if (device->pdevice->caps.multisync) { - enum v3d_queue wait_stage = needs_rcl_sync ? V3D_RENDER : V3D_BIN; - set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, - V3DV_QUEUE_CL, V3DV_QUEUE_CL, wait_stage, signal_syncs); - if (!ms.base.id) - return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + enum v3d_queue wait_stage = needs_rcl_sync ? V3D_RENDER : V3D_BIN; + set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, + V3DV_QUEUE_CL, V3DV_QUEUE_CL, wait_stage, signal_syncs); + if (!ms.base.id) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); - submit.flags |= DRM_V3D_SUBMIT_EXTENSION; - submit.extensions = (uintptr_t)(void *)&ms; - /* Disable legacy sync interface when multisync extension is used */ - submit.in_sync_rcl = 0; - submit.in_sync_bcl = 0; - submit.out_sync = 0; - } else { - uint32_t last_job_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_ANY]; - submit.in_sync_bcl = needs_bcl_sync ? last_job_sync : 0; - submit.in_sync_rcl = needs_rcl_sync ? last_job_sync : 0; - submit.out_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_CL]; - } + submit.flags |= DRM_V3D_SUBMIT_EXTENSION; + submit.extensions = (uintptr_t)(void *)&ms; + + /* We are using multisync so disable legacy single-sync interface */ + submit.in_sync_rcl = 0; + submit.in_sync_bcl = 0; + submit.out_sync = 0; v3dv_clif_dump(device, job, &submit); int ret = v3dv_ioctl(device->pdevice->render_fd, @@ -1193,9 +1020,6 @@ handle_cl_job(struct v3dv_queue *queue, warned = true; } - if (!device->pdevice->caps.multisync && ret == 0) - ret = update_any_queue_sync(queue, submit.out_sync); - free(bo_handles); multisync_free(device, &ms); @@ -1217,34 +1041,25 @@ handle_tfu_job(struct v3dv_queue *queue, struct v3dv_device *device = queue->device; - const bool needs_sync = sync_info->wait_count || job->serialize; - /* Replace single semaphore settings whenever our kernel-driver supports * multiple semaphore extension. */ struct drm_v3d_multi_sync ms = { 0 }; - if (device->pdevice->caps.multisync) { - set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, - V3DV_QUEUE_TFU, V3DV_QUEUE_TFU, V3D_TFU, signal_syncs); - if (!ms.base.id) - return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, + V3DV_QUEUE_TFU, V3DV_QUEUE_TFU, V3D_TFU, signal_syncs); + if (!ms.base.id) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + job->tfu.flags |= DRM_V3D_SUBMIT_EXTENSION; + job->tfu.extensions = (uintptr_t)(void *)&ms; + + /* We are using multisync so disable legacy single-sync interface */ + job->tfu.in_sync = 0; + job->tfu.out_sync = 0; - job->tfu.flags |= DRM_V3D_SUBMIT_EXTENSION; - job->tfu.extensions = (uintptr_t)(void *)&ms; - /* Disable legacy sync interface when multisync extension is used */ - job->tfu.in_sync = 0; - job->tfu.out_sync = 0; - } else { - uint32_t last_job_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_ANY]; - job->tfu.in_sync = needs_sync ? last_job_sync : 0; - job->tfu.out_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_TFU]; - } int ret = v3dv_ioctl(device->pdevice->render_fd, DRM_IOCTL_V3D_SUBMIT_TFU, &job->tfu); - if (!device->pdevice->caps.multisync && ret == 0) - ret = update_any_queue_sync(queue, job->tfu.out_sync); - multisync_free(device, &ms); queue->last_job_syncs.first[V3DV_QUEUE_TFU] = false; @@ -1287,31 +1102,26 @@ handle_csd_job(struct v3dv_queue *queue, assert(bo_idx == submit->bo_handle_count); submit->bo_handles = (uintptr_t)(void *)bo_handles; - const bool needs_sync = sync_info->wait_count || job->serialize; - /* Replace single semaphore settings whenever our kernel-driver supports * multiple semaphore extension. */ struct drm_v3d_multi_sync ms = { 0 }; - if (device->pdevice->caps.multisync) { - set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, - V3DV_QUEUE_CSD, V3DV_QUEUE_CSD, V3D_CSD, signal_syncs); - if (!ms.base.id) - return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + set_multisync(&ms, sync_info, NULL, 0, NULL, device, job, + V3DV_QUEUE_CSD, V3DV_QUEUE_CSD, V3D_CSD, signal_syncs); + if (!ms.base.id) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + submit->flags |= DRM_V3D_SUBMIT_EXTENSION; + submit->extensions = (uintptr_t)(void *)&ms; + + /* We are using multisync so disable legacy single-sync interface */ + submit->in_sync = 0; + submit->out_sync = 0; - submit->flags |= DRM_V3D_SUBMIT_EXTENSION; - submit->extensions = (uintptr_t)(void *)&ms; - /* Disable legacy sync interface when multisync extension is used */ - submit->in_sync = 0; - submit->out_sync = 0; - } else { - uint32_t last_job_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_ANY]; - submit->in_sync = needs_sync ? last_job_sync : 0; - submit->out_sync = queue->last_job_syncs.syncs[V3DV_QUEUE_CSD]; - } submit->perfmon_id = job->perf ? job->perf->kperfmon_ids[counter_pass_idx] : 0; queue->last_perfmon_id = submit->perfmon_id; + int ret = v3dv_ioctl(device->pdevice->render_fd, DRM_IOCTL_V3D_SUBMIT_CSD, submit); @@ -1322,9 +1132,6 @@ handle_csd_job(struct v3dv_queue *queue, warned = true; } - if (!device->pdevice->caps.multisync && ret == 0) - ret = update_any_queue_sync(queue, submit->out_sync); - free(bo_handles); multisync_free(device, &ms); @@ -1421,17 +1228,6 @@ 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; - /* If we do not have multisync we need to ensure we accumulate any wait - * semaphores into our QUEUE_ANY syncobj so we can handle waiting on - * external semaphores. - */ - if (!queue->device->pdevice->caps.multisync) { - result = - process_singlesync_waits(queue, sync_info.wait_count, sync_info.waits); - if (result != VK_SUCCESS) - return result; - } - /* FIXME: if suspend/resume chains are recorded into command buffers with * usage flag VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, then this won't * work and we would need to "clone" the jobs instead so we never patch a @@ -1494,18 +1290,13 @@ v3dv_queue_driver_submit(struct vk_queue *vk_queue, /* Handle signaling now */ if (submit->signal_count > 0) { - if (queue->device->pdevice->caps.multisync) { - /* Finish by submitting a no-op job that synchronizes across all queues. - * This will ensure that the signal semaphores don't get triggered until - * all work on any queue completes. See Vulkan's signal operation order - * requirements. - */ - return queue_submit_noop_job(queue, submit->perf_pass_index, - &sync_info, true); - } else { - return process_singlesync_signals(queue, sync_info.signal_count, - sync_info.signals); - } + /* Finish by submitting a no-op job that synchronizes across all queues. + * This will ensure that the signal semaphores don't get triggered until + * all work on any queue completes. See Vulkan's signal operation order + * requirements. + */ + return queue_submit_noop_job(queue, submit->perf_pass_index, + &sync_info, true); } return VK_SUCCESS;