diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index cd3c893879b..f23ebc3e843 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -350,6 +350,7 @@ create_batch_state(struct zink_context *ctx) SET_CREATE_OR_FAIL(&bs->programs); SET_CREATE_OR_FAIL(&bs->active_queries); + SET_CREATE_OR_FAIL(&bs->dmabuf_exports); util_dynarray_init(&bs->signal_semaphores, NULL); util_dynarray_init(&bs->wait_semaphores, NULL); util_dynarray_init(&bs->fd_wait_semaphores, NULL); @@ -584,6 +585,15 @@ submit_queue(void *data, void *gdata, int thread_index) assert(util_dynarray_num_elements(&bs->acquires, VkSemaphore) <= util_dynarray_num_elements(&bs->acquire_flags, VkPipelineStageFlags)); si[ZINK_SUBMIT_WAIT_ACQUIRE].pWaitDstStageMask = bs->acquire_flags.data; + si[ZINK_SUBMIT_WAIT_FD].waitSemaphoreCount = util_dynarray_num_elements(&bs->fd_wait_semaphores, VkSemaphore); + si[ZINK_SUBMIT_WAIT_FD].pWaitSemaphores = bs->fd_wait_semaphores.data; + while (util_dynarray_num_elements(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags) < si[ZINK_SUBMIT_WAIT_FD].waitSemaphoreCount) { + VkPipelineStageFlags mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + util_dynarray_append(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags, mask); + } + assert(util_dynarray_num_elements(&bs->fd_wait_semaphores, VkSemaphore) <= util_dynarray_num_elements(&bs->fd_wait_semaphore_stages, VkPipelineStageFlags)); + si[ZINK_SUBMIT_WAIT_FD].pWaitDstStageMask = bs->fd_wait_semaphore_stages.data; + if (si[ZINK_SUBMIT_WAIT_ACQUIRE].waitSemaphoreCount == 0) { num_si--; submit++; @@ -621,6 +631,10 @@ submit_queue(void *data, void *gdata, int thread_index) signals[si[ZINK_SUBMIT_CMDBUF].signalSemaphoreCount++] = bs->present; tsi.signalSemaphoreValueCount = si[ZINK_SUBMIT_CMDBUF].signalSemaphoreCount; + /* then the optional signal submit */ + si[ZINK_SUBMIT_SIGNAL].signalSemaphoreCount = util_dynarray_num_elements(&bs->signal_semaphores, VkSemaphore); + si[ZINK_SUBMIT_SIGNAL].pSignalSemaphores = bs->signal_semaphores.data; + VkResult result = VKSCR(EndCommandBuffer)(bs->cmdbuf); if (result != VK_SUCCESS) { mesa_loge("ZINK: vkEndCommandBuffer failed (%s)", vk_Result_to_str(result)); @@ -656,6 +670,18 @@ submit_queue(void *data, void *gdata, int thread_index) bs->is_device_lost = true; } simple_mtx_unlock(&screen->queue_lock); + + unsigned i = 0; + set_foreach_remove(&bs->dmabuf_exports, entry) { + struct zink_resource *res = (void*)entry->key; + VkSemaphore *sem = bs->signal_semaphores.data; + zink_screen_import_dmabuf_semaphore(screen, res, sem[i]); + i++; + + struct pipe_resource *pres = &res->base.b; + pipe_resource_reference(&pres, NULL); + } + bs->usage.submit_count++; end: cnd_broadcast(&bs->usage.flush); @@ -727,6 +753,47 @@ zink_end_batch(struct zink_context *ctx, struct zink_batch *batch) zink_query_sync(ctx, (void*)entry->key); } + set_foreach(&bs->dmabuf_exports, entry) { + struct zink_resource *res = (void*)entry->key; + if (screen->info.have_KHR_synchronization2) { + VkImageMemoryBarrier2 imb; + zink_resource_image_barrier2_init(&imb, res, res->layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + imb.srcQueueFamilyIndex = screen->gfx_queue; + imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT; + VkDependencyInfo dep = { + VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + NULL, + 0, + 0, + NULL, + 0, + NULL, + 1, + &imb + }; + VKCTX(CmdPipelineBarrier2)(bs->cmdbuf, &dep); + } else { + VkImageMemoryBarrier imb; + zink_resource_image_barrier_init(&imb, res, res->layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + imb.srcQueueFamilyIndex = screen->gfx_queue; + imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT; + VKCTX(CmdPipelineBarrier)( + bs->cmdbuf, + res->obj->access_stage, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, NULL, + 0, NULL, + 1, &imb + ); + } + res->queue = VK_QUEUE_FAMILY_FOREIGN_EXT; + + VkSemaphore sem = zink_create_exportable_semaphore(screen); + if (sem) + util_dynarray_append(&ctx->batch.state->signal_semaphores, VkSemaphore, sem); + } + if (screen->threaded_submit) { util_queue_add_job(&screen->flush_queue, bs, &bs->flush_completed, submit_queue, post_submit, 0); diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 7991961f29d..01feed1aa9c 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -80,6 +80,7 @@ bool zink_tracing = false; #endif #ifdef HAVE_LIBDRM +#include "drm-uapi/dma-buf.h" #include #endif @@ -2199,6 +2200,99 @@ zink_create_exportable_semaphore(struct zink_screen *screen) return ret == VK_SUCCESS ? sem : VK_NULL_HANDLE; } +VkSemaphore +zink_screen_export_dmabuf_semaphore(struct zink_screen *screen, struct zink_resource *res) +{ + VkSemaphore sem = VK_NULL_HANDLE; +#if defined(HAVE_LIBDRM) && (DETECT_OS_LINUX || DETECT_OS_BSD) + struct dma_buf_export_sync_file export = { + .flags = DMA_BUF_SYNC_RW, + .fd = -1, + }; + + int fd; + VkMemoryGetFdInfoKHR fd_info = {0}; + fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + fd_info.memory = zink_bo_get_mem(res->obj->bo); + fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + VKSCR(GetMemoryFdKHR)(screen->dev, &fd_info, &fd); + + int ret = drmIoctl(fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &export); + if (ret) { + if (errno == ENOTTY || errno == EBADF || errno == ENOSYS) { + assert(!"how did this fail?"); + return VK_NULL_HANDLE; + } else { + mesa_loge("MESA: failed to import sync file '%s'", strerror(errno)); + return VK_NULL_HANDLE; + } + } + + sem = zink_create_exportable_semaphore(screen); + + const VkImportSemaphoreFdInfoKHR sdi = { + .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, + .semaphore = sem, + .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + .fd = export.fd, + }; + bool success = VKSCR(ImportSemaphoreFdKHR)(screen->dev, &sdi) == VK_SUCCESS; + close(fd); + if (!success) { + VKSCR(DestroySemaphore)(screen->dev, sem, NULL); + return VK_NULL_HANDLE; + } +#endif + return sem; +} + +bool +zink_screen_import_dmabuf_semaphore(struct zink_screen *screen, struct zink_resource *res, VkSemaphore sem) +{ +#if defined(HAVE_LIBDRM) && (DETECT_OS_LINUX || DETECT_OS_BSD) + const VkSemaphoreGetFdInfoKHR get_fd_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, + .semaphore = sem, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + }; + int sync_file_fd = -1; + VkResult result = VKSCR(GetSemaphoreFdKHR)(screen->dev, &get_fd_info, &sync_file_fd); + if (result != VK_SUCCESS) { + return false; + } + + bool ret = false; + int fd; + VkMemoryGetFdInfoKHR fd_info = {0}; + fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + fd_info.memory = zink_bo_get_mem(res->obj->bo); + fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + if (VKSCR(GetMemoryFdKHR)(screen->dev, &fd_info, &fd) == VK_SUCCESS) { + struct dma_buf_import_sync_file import = { + .flags = DMA_BUF_SYNC_RW, + .fd = sync_file_fd, + }; + int ret = drmIoctl(fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import); + if (ret) { + if (errno == ENOTTY || errno == EBADF || errno == ENOSYS) { + assert(!"how did this fail?"); + } else { + mesa_loge("MESA: failed to import sync file '%s'", strerror(errno)); + } + } else { + ret = true; + } + } + + close(sync_file_fd); + close(fd); + return ret; +#else + return true; +#endif +} + bool zink_screen_timeline_wait(struct zink_screen *screen, uint64_t batch_id, uint64_t timeout) { diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index 9151db43fc1..e68291c124b 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -124,6 +124,10 @@ zink_screen_unlock_context(struct zink_screen *screen); VkSemaphore zink_create_exportable_semaphore(struct zink_screen *screen); +VkSemaphore +zink_screen_export_dmabuf_semaphore(struct zink_screen *screen, struct zink_resource *res); +bool +zink_screen_import_dmabuf_semaphore(struct zink_screen *screen, struct zink_resource *res, VkSemaphore sem); VkFormat zink_get_format(struct zink_screen *screen, enum pipe_format format); diff --git a/src/gallium/drivers/zink/zink_synchronization.cpp b/src/gallium/drivers/zink/zink_synchronization.cpp index 4ef12d7c091..93049044bc7 100644 --- a/src/gallium/drivers/zink/zink_synchronization.cpp +++ b/src/gallium/drivers/zink/zink_synchronization.cpp @@ -364,6 +364,7 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_resource *res, } assert(new_layout); bool marker = zink_cmd_debug_marker_begin(ctx, cmdbuf, "image_barrier(%s->%s)", vk_ImageLayout_to_str(res->layout), vk_ImageLayout_to_str(new_layout)); + bool queue_import = false; if (HAS_SYNC2) { VkImageMemoryBarrier2 imb; zink_resource_image_barrier2_init(&imb, res, new_layout, flags, pipeline); @@ -376,6 +377,7 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_resource *res, imb.srcQueueFamilyIndex = res->queue; imb.dstQueueFamilyIndex = zink_screen(ctx->base.screen)->gfx_queue; res->queue = VK_QUEUE_FAMILY_IGNORED; + queue_import = true; } VkDependencyInfo dep = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO, @@ -401,6 +403,7 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_resource *res, imb.srcQueueFamilyIndex = res->queue; imb.dstQueueFamilyIndex = zink_screen(ctx->base.screen)->gfx_queue; res->queue = VK_QUEUE_FAMILY_IGNORED; + queue_import = true; } VKCTX(CmdPipelineBarrier)( cmdbuf, @@ -427,6 +430,18 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_resource *res, if (cdt->swapchain->num_acquires && res->obj->dt_idx != UINT32_MAX) { cdt->swapchain->images[res->obj->dt_idx].layout = res->layout; } + } else if (res->obj->exportable) { + struct pipe_resource *pres = NULL; + bool found = false; + _mesa_set_search_or_add(&ctx->batch.state->dmabuf_exports, res, &found); + if (!found) { + pipe_resource_reference(&pres, &res->base.b); + } + } + if (res->obj->exportable && queue_import) { + VkSemaphore sem = zink_screen_export_dmabuf_semaphore(zink_screen(ctx->base.screen), res); + if (sem) + util_dynarray_append(&ctx->batch.state->fd_wait_semaphores, VkSemaphore, sem); } if (new_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) zink_resource_copies_reset(res); diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index 03aebc254cd..8550ccf01b1 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -621,6 +621,7 @@ struct zink_batch_state { struct util_queue_fence flush_completed; struct set programs; + struct set dmabuf_exports; #define BUFFER_HASHLIST_SIZE 32768 /* buffer_indices_hashlist[hash(bo)] returns -1 if the bo