zink: handle implicit sync for dmabufs

this adds explicit queue transitions to FOREIGN at the end of the batch
for all written-to dmabufs, then also adds signal/wait semaphores
using the dmabuf fds

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24962>
This commit is contained in:
Mike Blumenkrantz 2023-08-16 12:55:30 -04:00 committed by Marge Bot
parent 4932e65f1e
commit d4f8ad27f2
5 changed files with 181 additions and 0 deletions

View file

@ -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);

View file

@ -80,6 +80,7 @@ bool zink_tracing = false;
#endif
#ifdef HAVE_LIBDRM
#include "drm-uapi/dma-buf.h"
#include <xf86drm.h>
#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)
{

View file

@ -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);

View file

@ -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);

View file

@ -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