hwcontext_vulkan: split uploading and downloading contexts
authorLynne <dev@lynne.ee>
Thu, 14 May 2020 23:01:08 +0000 (00:01 +0100)
committerLynne <dev@lynne.ee>
Sat, 23 May 2020 18:07:45 +0000 (19:07 +0100)
This allows us to speed up only-uploading or only-downloading use cases.

libavutil/hwcontext_vulkan.c

index 3e70252..ff982db 100644 (file)
@@ -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;