From d870e75c395a9ae5141f51849b1def229d5a0d11 Mon Sep 17 00:00:00 2001 From: Lynne Date: Fri, 15 May 2020 00:01:08 +0100 Subject: [PATCH] hwcontext_vulkan: split uploading and downloading contexts This allows us to speed up only-uploading or only-downloading use cases. --- libavutil/hwcontext_vulkan.c | 123 +++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 57 deletions(-) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 3e70252f02..ff982db6c6 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -72,10 +72,6 @@ typedef struct VulkanDevicePriv { /* Debug callback */ VkDebugUtilsMessengerEXT debug_ctx; - /* Image transfers */ - VulkanExecCtx upload_ctx; - VulkanExecCtx download_ctx; - /* Extensions */ uint64_t extensions; @@ -89,6 +85,10 @@ typedef struct VulkanDevicePriv { typedef struct VulkanFramesPriv { /* Image conversions */ VulkanExecCtx conv_ctx; + + /* Image transfers */ + VulkanExecCtx upload_ctx; + VulkanExecCtx download_ctx; } VulkanFramesPriv; typedef struct AVVkFrameInternal { @@ -732,11 +732,11 @@ fail: return AVERROR(ENOMEM); } -static int create_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, +static int create_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, int queue_family_index, int num_queues) { VkResult ret; - AVVulkanDeviceContext *hwctx = ctx->hwctx; + AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; VkCommandPoolCreateInfo cqueue_create = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -763,7 +763,7 @@ static int create_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, ret = vkCreateCommandPool(hwctx->act_dev, &cqueue_create, hwctx->alloc, &cmd->pool); if (ret != VK_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Command pool creation failure: %s\n", + av_log(hwfc, AV_LOG_ERROR, "Command pool creation failure: %s\n", vk_ret2str(ret)); return AVERROR_EXTERNAL; } @@ -773,7 +773,7 @@ static int create_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, /* Allocate command buffer */ ret = vkAllocateCommandBuffers(hwctx->act_dev, &cbuf_create, cmd->bufs); if (ret != VK_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Command buffer alloc failure: %s\n", + av_log(hwfc, AV_LOG_ERROR, "Command buffer alloc failure: %s\n", vk_ret2str(ret)); return AVERROR_EXTERNAL; } @@ -787,9 +787,9 @@ static int create_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, return 0; } -static void free_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) +static void free_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) { - AVVulkanDeviceContext *hwctx = ctx->hwctx; + AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; /* Make sure all queues have finished executing */ for (int i = 0; i < cmd->nb_queues; i++) { @@ -819,12 +819,12 @@ static void free_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) av_freep(&cmd->queues); } -static VkCommandBuffer get_buf_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) +static VkCommandBuffer get_buf_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) { return cmd->bufs[cmd->cur_queue_idx]; } -static void unref_exec_ctx_deps(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) +static void unref_exec_ctx_deps(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) { VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; @@ -833,10 +833,10 @@ static void unref_exec_ctx_deps(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) q->nb_buf_deps = 0; } -static int wait_start_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) +static int wait_start_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd) { VkResult ret; - AVVulkanDeviceContext *hwctx = ctx->hwctx; + AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; VulkanQueueCtx *q = &cmd->queues[cmd->cur_queue_idx]; VkCommandBufferBeginInfo cmd_start = { @@ -852,7 +852,7 @@ static int wait_start_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) ret = vkCreateFence(hwctx->act_dev, &fence_spawn, hwctx->alloc, &q->fence); if (ret != VK_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to queue frame fence: %s\n", + av_log(hwfc, AV_LOG_ERROR, "Failed to queue frame fence: %s\n", vk_ret2str(ret)); return AVERROR_EXTERNAL; } @@ -862,11 +862,11 @@ static int wait_start_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) } /* Discard queue dependencies */ - unref_exec_ctx_deps(ctx, cmd); + unref_exec_ctx_deps(hwfc, cmd); ret = vkBeginCommandBuffer(cmd->bufs[cmd->cur_queue_idx], &cmd_start); if (ret != VK_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Unable to init command buffer: %s\n", + av_log(hwfc, AV_LOG_ERROR, "Unable to init command buffer: %s\n", vk_ret2str(ret)); return AVERROR_EXTERNAL; } @@ -874,7 +874,7 @@ static int wait_start_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd) return 0; } -static int add_buf_dep_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, +static int add_buf_dep_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, AVBufferRef * const *deps, int nb_deps) { AVBufferRef **dst; @@ -900,11 +900,11 @@ static int add_buf_dep_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, return 0; err: - unref_exec_ctx_deps(ctx, cmd); + unref_exec_ctx_deps(hwfc, cmd); return AVERROR(ENOMEM); } -static int submit_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, +static int submit_exec_ctx(AVHWFramesContext *hwfc, VulkanExecCtx *cmd, VkSubmitInfo *s_info, int synchronous) { VkResult ret; @@ -912,9 +912,9 @@ static int submit_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, ret = vkEndCommandBuffer(cmd->bufs[cmd->cur_queue_idx]); if (ret != VK_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Unable to finish command buffer: %s\n", + av_log(hwfc, AV_LOG_ERROR, "Unable to finish command buffer: %s\n", vk_ret2str(ret)); - unref_exec_ctx_deps(ctx, cmd); + unref_exec_ctx_deps(hwfc, cmd); return AVERROR_EXTERNAL; } @@ -923,17 +923,17 @@ static int submit_exec_ctx(AVHWDeviceContext *ctx, VulkanExecCtx *cmd, ret = vkQueueSubmit(q->queue, 1, s_info, q->fence); if (ret != VK_SUCCESS) { - unref_exec_ctx_deps(ctx, cmd); + unref_exec_ctx_deps(hwfc, cmd); return AVERROR_EXTERNAL; } q->was_synchronous = synchronous; if (synchronous) { - AVVulkanDeviceContext *hwctx = ctx->hwctx; + AVVulkanDeviceContext *hwctx = hwfc->device_ctx->hwctx; vkWaitForFences(hwctx->act_dev, 1, &q->fence, VK_TRUE, UINT64_MAX); vkResetFences(hwctx->act_dev, 1, &q->fence); - unref_exec_ctx_deps(ctx, cmd); + unref_exec_ctx_deps(hwfc, cmd); } else { /* Rotate queues */ cmd->cur_queue_idx = (cmd->cur_queue_idx + 1) % cmd->nb_queues; } @@ -946,8 +946,6 @@ static void vulkan_device_free(AVHWDeviceContext *ctx) VulkanDevicePriv *p = ctx->internal->priv; AVVulkanDeviceContext *hwctx = ctx->hwctx; - free_exec_ctx(ctx, &p->cmd); - vkDestroyDevice(hwctx->act_dev, hwctx->alloc); if (p->debug_ctx) { @@ -1062,7 +1060,6 @@ end: static int vulkan_device_init(AVHWDeviceContext *ctx) { - int err; uint32_t queue_num; AVVulkanDeviceContext *hwctx = ctx->hwctx; VulkanDevicePriv *p = ctx->internal->priv; @@ -1105,12 +1102,6 @@ if (n >= queue_num) { (hwctx->queue_family_comp_index != hwctx->queue_family_tx_index)) p->qfs[p->num_qfs++] = hwctx->queue_family_comp_index; - /* Create exec context - if there's something invalid this will error out */ - err = create_exec_ctx(ctx, &p->cmd, hwctx->queue_family_tx_index, - GET_QUEUE_COUNT(hwctx, 0, 0, 1)); - if (err) - return err; - /* Get device capabilities */ vkGetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops); @@ -1431,7 +1422,6 @@ static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, uint32_t dst_qf; VkImageLayout new_layout; VkAccessFlags new_access; - AVHWDeviceContext *ctx = hwfc->device_ctx; const int planes = av_pix_fmt_count_planes(hwfc->sw_format); VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 }; @@ -1467,7 +1457,7 @@ static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, break; } - if ((err = wait_start_exec_ctx(ctx, ectx))) + if ((err = wait_start_exec_ctx(hwfc, ectx))) return err; /* Change the image layout to something more optimal for writes. @@ -1490,12 +1480,12 @@ static int prepare_frame(AVHWFramesContext *hwfc, VulkanExecCtx *ectx, frame->access[i] = img_bar[i].dstAccessMask; } - vkCmdPipelineBarrier(get_buf_exec_ctx(ctx, ectx), + vkCmdPipelineBarrier(get_buf_exec_ctx(hwfc, ectx), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, planes, img_bar); - return submit_exec_ctx(ctx, ectx, &s_info, 0); + return submit_exec_ctx(hwfc, ectx, &s_info, 0); } static int create_frame(AVHWFramesContext *hwfc, AVVkFrame **frame, @@ -1687,7 +1677,9 @@ static void vulkan_frames_uninit(AVHWFramesContext *hwfc) { VulkanFramesPriv *fp = hwfc->internal->priv; - free_exec_ctx(hwfc->device_ctx, &fp->conv_ctx); + free_exec_ctx(hwfc, &fp->conv_ctx); + free_exec_ctx(hwfc, &fp->upload_ctx); + free_exec_ctx(hwfc, &fp->download_ctx); } static int vulkan_frames_init(AVHWFramesContext *hwfc) @@ -1706,19 +1698,28 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) if (!hwctx->usage) hwctx->usage = DEFAULT_USAGE_FLAGS; - err = create_exec_ctx(hwfc->device_ctx, &fp->conv_ctx, + err = create_exec_ctx(hwfc, &fp->conv_ctx, dev_hwctx->queue_family_comp_index, GET_QUEUE_COUNT(dev_hwctx, 0, 1, 0)); if (err) - return err; + goto fail; + + err = create_exec_ctx(hwfc, &fp->upload_ctx, + dev_hwctx->queue_family_tx_index, + GET_QUEUE_COUNT(dev_hwctx, 0, 0, 1)); + if (err) + goto fail; + + err = create_exec_ctx(hwfc, &fp->download_ctx, + dev_hwctx->queue_family_tx_index, 1); + if (err) + goto fail; /* Test to see if allocation will fail */ err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->create_pnext); - if (err) { - free_exec_ctx(hwfc->device_ctx, &fp->conv_ctx); - return err; - } + if (err) + goto fail; vulkan_frame_free(hwfc, (uint8_t *)f); @@ -1729,12 +1730,19 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) hwfc, vulkan_pool_alloc, NULL); if (!hwfc->internal->pool_internal) { - free_exec_ctx(hwfc->device_ctx, &fp->conv_ctx); - return AVERROR(ENOMEM); + err = AVERROR(ENOMEM); + goto fail; } } return 0; + +fail: + free_exec_ctx(hwfc, &fp->conv_ctx); + free_exec_ctx(hwfc, &fp->upload_ctx); + free_exec_ctx(hwfc, &fp->download_ctx); + + return err; } static int vulkan_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) @@ -2776,13 +2784,13 @@ static int unmap_buffers(AVHWDeviceContext *ctx, AVBufferRef **bufs, return err; } -static int transfer_image_buf(AVHWDeviceContext *ctx, const AVFrame *f, +static int transfer_image_buf(AVHWFramesContext *hwfc, const AVFrame *f, AVBufferRef **bufs, const int *buf_stride, int w, int h, enum AVPixelFormat pix_fmt, int to_buf) { int err; AVVkFrame *frame = (AVVkFrame *)f->data[0]; - VulkanDevicePriv *s = ctx->internal->priv; + VulkanFramesPriv *fp = hwfc->internal->priv; int bar_num = 0; VkPipelineStageFlagBits sem_wait_dst[AV_NUM_DATA_POINTERS]; @@ -2791,7 +2799,8 @@ static int transfer_image_buf(AVHWDeviceContext *ctx, const AVFrame *f, const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); VkImageMemoryBarrier img_bar[AV_NUM_DATA_POINTERS] = { 0 }; - VkCommandBuffer cmd_buf = get_buf_exec_ctx(ctx, &s->cmd); + VulkanExecCtx *ectx = to_buf ? &fp->download_ctx : &fp->upload_ctx; + VkCommandBuffer cmd_buf = get_buf_exec_ctx(hwfc, ectx); VkSubmitInfo s_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, @@ -2802,7 +2811,7 @@ static int transfer_image_buf(AVHWDeviceContext *ctx, const AVFrame *f, .waitSemaphoreCount = planes, }; - if ((err = wait_start_exec_ctx(ctx, &s->cmd))) + if ((err = wait_start_exec_ctx(hwfc, ectx))) return err; /* Change the image layout to something more optimal for transfers */ @@ -2879,14 +2888,14 @@ static int transfer_image_buf(AVHWDeviceContext *ctx, const AVFrame *f, for (ref = 0; ref < AV_NUM_DATA_POINTERS; ref++) { if (!f->buf[ref]) break; - if ((err = add_buf_dep_exec_ctx(hwfc, &s->cmd, &f->buf[ref], 1))) + if ((err = add_buf_dep_exec_ctx(hwfc, ectx, &f->buf[ref], 1))) return err; } - if (ref && (err = add_buf_dep_exec_ctx(hwfc, &s->cmd, bufs, planes))) + if (ref && (err = add_buf_dep_exec_ctx(hwfc, ectx, bufs, planes))) return err; - return submit_exec_ctx(hwfc, &s->cmd, &s_info, !ref); + return submit_exec_ctx(hwfc, ectx, &s_info, !ref); } else { - return submit_exec_ctx(hwfc, &s->cmd, &s_info, 1); + return submit_exec_ctx(hwfc, ectx, &s_info, 1); } } @@ -2955,7 +2964,7 @@ static int vulkan_transfer_data_from_mem(AVHWFramesContext *hwfc, AVFrame *dst, goto end; /* Copy buffers to image */ - err = transfer_image_buf(dev_ctx, dst, bufs, tmp.linesize, + err = transfer_image_buf(hwfc, dst, bufs, tmp.linesize, src->width, src->height, src->format, 0); end: @@ -3100,7 +3109,7 @@ static int vulkan_transfer_data_to_mem(AVHWFramesContext *hwfc, AVFrame *dst, } /* Copy image to buffer */ - if ((err = transfer_image_buf(dev_ctx, src, bufs, tmp.linesize, + if ((err = transfer_image_buf(hwfc, src, bufs, tmp.linesize, dst->width, dst->height, dst->format, 1))) goto end; -- GitLab