[FFmpeg-devel] [PATCH] hwcontext_vulkan: use host image copy
Lynne
dev at lynne.ee
Mon Jun 2 19:58:26 EEST 2025
---
libavutil/hwcontext_vulkan.c | 84 +++++++++++++++++++++++++++++++++++-
libavutil/vulkan_functions.h | 6 +++
libavutil/vulkan_loader.h | 1 +
3 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index ce485a85a2..b22e4e375a 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -80,6 +80,7 @@ typedef struct VulkanDeviceFeatures {
VkPhysicalDeviceVulkan13Features vulkan_1_3;
VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore;
VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR subgroup_rotate;
+ VkPhysicalDeviceHostImageCopyFeaturesEXT host_image_copy;
#ifdef VK_KHR_shader_expect_assume
VkPhysicalDeviceShaderExpectAssumeFeaturesKHR expect_assume;
@@ -208,6 +209,8 @@ static void device_features_init(AVHWDeviceContext *ctx, VulkanDeviceFeatures *f
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES);
FF_VK_STRUCT_EXT(s, &feats->device, &feats->subgroup_rotate, FF_VK_EXT_SUBGROUP_ROTATE,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR);
+ FF_VK_STRUCT_EXT(s, &feats->device, &feats->host_image_copy, FF_VK_EXT_HOST_IMAGE_COPY,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT);
#ifdef VK_KHR_shader_expect_assume
FF_VK_STRUCT_EXT(s, &feats->device, &feats->expect_assume, FF_VK_EXT_EXPECT_ASSUME,
@@ -287,6 +290,7 @@ static void device_features_copy_needed(VulkanDeviceFeatures *dst, VulkanDeviceF
COPY_VAL(timeline_semaphore.timelineSemaphore);
COPY_VAL(subgroup_rotate.shaderSubgroupRotate);
+ COPY_VAL(host_image_copy.hostImageCopy);
COPY_VAL(video_maintenance_1.videoMaintenance1);
#ifdef VK_KHR_video_maintenance2
@@ -610,6 +614,7 @@ static const VulkanOptExtension optional_device_exts[] = {
{ VK_NV_OPTICAL_FLOW_EXTENSION_NAME, FF_VK_EXT_OPTICAL_FLOW },
{ VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT },
{ VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME, FF_VK_EXT_SUBGROUP_ROTATE },
+ { VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME, FF_VK_EXT_HOST_IMAGE_COPY },
#ifdef VK_KHR_shader_expect_assume
{ VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME, FF_VK_EXT_EXPECT_ASSUME },
#endif
@@ -2802,11 +2807,15 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
/* Image usage flags */
if (!hwctx->usage) {
- hwctx->usage = supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ hwctx->usage = supported_usage & (VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT);
+ if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY)
+ hwctx->usage |= VK_IMAGE_USAGE_HOST_TRANSFER_BIT;
+ else
+ hwctx->usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
/* Enables encoding of images, if supported by format and extensions */
if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
(p->vkctx.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE |
@@ -4125,6 +4134,74 @@ fail:
return err;
}
+static int vulkan_transfer_host(AVHWFramesContext *hwfc, AVFrame *hwf,
+ AVFrame *swf, int upload)
+{
+ VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
+ AVVulkanDeviceContext *hwctx = &p->p;
+ FFVulkanFunctions *vk = &p->vkctx.vkfn;
+
+ AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0];
+ const int planes = av_pix_fmt_count_planes(swf->format);
+ const int nb_images = ff_vk_count_images(hwf_vk);
+
+ if (upload) {
+ VkMemoryToImageCopy region_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY,
+ .imageSubresource = {
+ .layerCount = 1,
+ },
+ };
+ VkCopyMemoryToImageInfo copy_info = {
+ .sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO,
+ .flags = VK_HOST_IMAGE_COPY_MEMCPY,
+ .regionCount = 1,
+ .pRegions = ®ion_info,
+ };
+ for (int i = 0; i < planes; i++) {
+ int img_idx = FFMIN(i, (nb_images - 1));
+ uint32_t p_w, p_h;
+ get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
+
+ region_info.pHostPointer = swf->data[i];
+ region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
+ region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
+ copy_info.dstImage = hwf_vk->img[img_idx];
+ copy_info.dstImageLayout = hwf_vk->layout[img_idx];
+
+ vk->CopyMemoryToImageEXT(hwctx->act_dev, ©_info);
+ }
+ } else {
+ VkImageToMemoryCopy region_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY,
+ .imageSubresource = {
+ .layerCount = 1,
+ },
+ };
+ VkCopyImageToMemoryInfo copy_info = {
+ .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO,
+ .flags = VK_HOST_IMAGE_COPY_MEMCPY,
+ .regionCount = 1,
+ .pRegions = ®ion_info,
+ };
+ for (int i = 0; i < planes; i++) {
+ int img_idx = FFMIN(i, (nb_images - 1));
+ uint32_t p_w, p_h;
+ get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
+
+ region_info.pHostPointer = swf->data[i];
+ region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf, i);
+ region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
+ copy_info.srcImage = hwf_vk->img[img_idx];
+ copy_info.srcImageLayout = hwf_vk->layout[img_idx];
+
+ vk->CopyImageToMemoryEXT(hwctx->act_dev, ©_info);
+ }
+ }
+
+ return 0;
+}
+
static int vulkan_transfer_frame(AVHWFramesContext *hwfc,
AVFrame *swf, AVFrame *hwf,
int upload)
@@ -4161,6 +4238,9 @@ static int vulkan_transfer_frame(AVHWFramesContext *hwfc,
if (swf->width > hwfc->width || swf->height > hwfc->height)
return AVERROR(EINVAL);
+ if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY)
+ return vulkan_transfer_host(hwfc, hwf, swf, upload);
+
for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
uint32_t p_w, p_h;
get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
diff --git a/libavutil/vulkan_functions.h b/libavutil/vulkan_functions.h
index 8b413013e6..ea0f978bb9 100644
--- a/libavutil/vulkan_functions.h
+++ b/libavutil/vulkan_functions.h
@@ -49,6 +49,7 @@ typedef uint64_t FFVulkanExtensions;
#define FF_VK_EXT_RELAXED_EXTENDED_INSTR (1ULL << 15) /* VK_KHR_shader_relaxed_extended_instruction */
#define FF_VK_EXT_EXPECT_ASSUME (1ULL << 16) /* VK_KHR_shader_expect_assume */
#define FF_VK_EXT_SUBGROUP_ROTATE (1ULL << 17) /* VK_KHR_shader_subgroup_rotate */
+#define FF_VK_EXT_HOST_IMAGE_COPY (1ULL << 18) /* VK_EXT_image_copy */
/* Video extensions */
#define FF_VK_EXT_VIDEO_QUEUE (1ULL << 36) /* VK_KHR_video_queue */
@@ -207,6 +208,11 @@ typedef uint64_t FFVulkanExtensions;
/* sync2 */ \
MACRO(1, 1, FF_VK_EXT_NO_FLAG, CmdPipelineBarrier2) \
\
+ /* Host image copy */ \
+ MACRO(1, 1, FF_VK_EXT_HOST_IMAGE_COPY, TransitionImageLayoutEXT) \
+ MACRO(1, 1, FF_VK_EXT_HOST_IMAGE_COPY, CopyMemoryToImageEXT) \
+ MACRO(1, 1, FF_VK_EXT_HOST_IMAGE_COPY, CopyImageToMemoryEXT) \
+ \
/* Video queue */ \
MACRO(1, 1, FF_VK_EXT_VIDEO_QUEUE, CreateVideoSessionKHR) \
MACRO(1, 1, FF_VK_EXT_VIDEO_QUEUE, CreateVideoSessionParametersKHR) \
diff --git a/libavutil/vulkan_loader.h b/libavutil/vulkan_loader.h
index a7976fe560..7e805fdd4c 100644
--- a/libavutil/vulkan_loader.h
+++ b/libavutil/vulkan_loader.h
@@ -59,6 +59,7 @@ static inline uint64_t ff_vk_extensions_to_mask(const char * const *extensions,
{ VK_NV_OPTICAL_FLOW_EXTENSION_NAME, FF_VK_EXT_OPTICAL_FLOW },
{ VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT },
{ VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME, FF_VK_EXT_SUBGROUP_ROTATE },
+ { VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME, FF_VK_EXT_HOST_IMAGE_COPY },
{ VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_1 },
#ifdef VK_KHR_video_maintenance2
{ VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_2 },
--
2.49.0.395.g12beb8f557c
More information about the ffmpeg-devel
mailing list