ffmpeg | branch: master | Lynne <d...@lynne.ee> | Mon May 12 18:42:09 2025 +0200| [a9b2c10eee9cf28ecbce2f1972564f4aa826a855] | committer: Lynne
hwcontext_vulkan: use host image copy > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=a9b2c10eee9cf28ecbce2f1972564f4aa826a855 --- libavutil/hwcontext_vulkan.c | 123 ++++++++++++++++++++++++++++++++++++++++++- libavutil/vulkan.c | 35 ++++++++++++ libavutil/vulkan.h | 2 + libavutil/vulkan_functions.h | 6 +++ libavutil/vulkan_loader.h | 1 + 5 files changed, 165 insertions(+), 2 deletions(-) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 6402030afe..e0024585cd 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; @@ -209,6 +210,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, @@ -285,6 +288,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 @@ -606,6 +610,7 @@ static const VulkanOptExtension optional_device_exts[] = { { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX }, { 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 @@ -2825,11 +2830,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 |= supported_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 | @@ -4148,6 +4157,113 @@ fail: return err; } +static int vulkan_transfer_host(AVHWFramesContext *hwfc, AVFrame *hwf, + AVFrame *swf, int upload) +{ + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; + AVVulkanFramesContext *hwfc_vk = hwfc->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); + + VkSemaphoreWaitInfo sem_wait; + VkHostImageLayoutTransitionInfo layout_ch_info[]; + int nb_layout_ch = 0; + + hwfc_vk->lock_frame(hwfc, hwf_vk); + + for (int i = 0; i < nb_images; i++) { + if (hwf_vk->layout[i]) + continue; + + layout_ch_info[nb_layout_ch++] = (VkHostImageLayoutTransitionInfo) { + .sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO, + .image = hwf_vk->img[i], + .oldLayout = hwf_vk->layout[i], + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + }; + }; + } + + if (nb_layout_ch) + vk->TransitionImageLayoutEXT(hwctx->act_dev, + nb_layout_ch, layout_ch_info); + + sem_wait = (VkSemaphoreWaitInfo) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .pSemaphores = hwf_vk->sem, + .pValues = hwf_vk->sem_value, + .semaphoreCount = nb_images, + }; + + vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX); + + 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); + } + } + + hwfc_vk->unlock_frame(hwfc, hwf_vk); + + return 0; +} + static int vulkan_transfer_frame(AVHWFramesContext *hwfc, AVFrame *swf, AVFrame *hwf, int upload) @@ -4184,6 +4300,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.c b/libavutil/vulkan.c index a989e080ab..661b9c1c54 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -162,6 +162,8 @@ int ff_vk_load_props(FFVulkanContext *s) VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT); FF_VK_STRUCT_EXT(s, &s->props, &s->optical_flow_props, FF_VK_EXT_OPTICAL_FLOW, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV); + FF_VK_STRUCT_EXT(s, &s->props, &s->host_image_props, FF_VK_EXT_HOST_IMAGE_COPY, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES); s->feats = (VkPhysicalDeviceFeatures2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, @@ -172,7 +174,39 @@ int ff_vk_load_props(FFVulkanContext *s) FF_VK_STRUCT_EXT(s, &s->feats, &s->atomic_float_feats, FF_VK_EXT_ATOMIC_FLOAT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT); + /* Try allocating 1024 layouts */ + s->host_image_copy_layouts = av_malloc(sizeof(*s->host_image_copy_layouts)*1024); + s->host_image_props.pCopySrcLayouts = s->host_image_copy_layouts; + s->host_image_props.copySrcLayoutCount = 512; + s->host_image_props.pCopyDstLayouts = s->host_image_copy_layouts + 512; + s->host_image_props.copyDstLayoutCount = 512; + vk->GetPhysicalDeviceProperties2(s->hwctx->phys_dev, &s->props); + + /* Check if we had enough memory for all layouts */ + if (s->host_image_props.copySrcLayoutCount == 512 || + s->host_image_props.copyDstLayoutCount == 512) { + VkImageLayout *new_array; + size_t new_size; + s->host_image_props.pCopySrcLayouts = + s->host_image_props.pCopyDstLayouts = NULL; + s->host_image_props.copySrcLayoutCount = + s->host_image_props.copyDstLayoutCount = NULL; + vk->GetPhysicalDeviceProperties2(s->hwctx->phys_dev, &s->props); + + new_size = s->host_image_props.copySrcLayoutCount + + s->host_image_props.copyDstLayoutCount; + new_size *= sizeof(*s->host_image_copy_layouts); + new_array = av_realloc(s->host_image_copy_layouts, new_size); + if (!new_array) + return AVERROR(ENOMEM); + + s->host_image_copy_layouts = new_array; + s->host_image_props.pCopySrcLayouts = new_array; + s->host_image_props.pCopyDstLayouts = new_array + s->host_image_props.copySrcLayoutCount; + vk->GetPhysicalDeviceProperties2(s->hwctx->phys_dev, &s->props); + } + vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops); vk->GetPhysicalDeviceFeatures2(s->hwctx->phys_dev, &s->feats); @@ -2927,6 +2961,7 @@ void ff_vk_uninit(FFVulkanContext *s) av_freep(&s->qf_props); av_freep(&s->video_props); av_freep(&s->coop_mat_props); + av_freep(&s->host_image_copy_layouts); av_buffer_unref(&s->device_ref); av_buffer_unref(&s->frames_ref); diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h index d5dd1bce41..e1c9a5792f 100644 --- a/libavutil/vulkan.h +++ b/libavutil/vulkan.h @@ -291,6 +291,8 @@ typedef struct FFVulkanContext { VkQueueFamilyVideoPropertiesKHR *video_props; VkQueueFamilyProperties2 *qf_props; int tot_nb_qfs; + VkPhysicalDeviceHostImageCopyPropertiesEXT host_image_props; + VkImageLayout *host_image_copy_layouts; VkCooperativeMatrixPropertiesKHR *coop_mat_props; uint32_t coop_mat_props_nb; diff --git a/libavutil/vulkan_functions.h b/libavutil/vulkan_functions.h index 8b413013e6..68fa7b802d 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_host_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 }, _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog To unsubscribe, visit link above, or email ffmpeg-cvslog-requ...@ffmpeg.org with subject "unsubscribe".