aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLynne <dev@lynne.ee>2024-08-14 17:25:00 +0200
committerLynne <dev@lynne.ee>2024-08-16 01:22:16 +0200
commit18d964fc2c520dd690aa3d737aea62e60fc3786b (patch)
tree326f875a03f1d8d9d04729e88807a18f069ea6e5
parent46c13834b6a08d4e7d9b2c457805bfdca55f4613 (diff)
downloadffmpeg-18d964fc2c520dd690aa3d737aea62e60fc3786b.tar.gz
vulkan: enable encoding of images if video_maintenance1 is enabled
Vulkan encoding was designed in a very... consolidated way. You had to know the exact codec and profile that the image was going to eventually be encoded as at... image creation time. Unfortunately, as good as our code is, glimpsing into the exact future isn't what its capable of. video_maintenance1 removed that requirement, which only then made encoding images practically possible.
-rw-r--r--libavcodec/vulkan_decode.c10
-rw-r--r--libavfilter/vulkan_filter.c41
-rw-r--r--libavutil/hwcontext_vulkan.c28
3 files changed, 67 insertions, 12 deletions
diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index c7a32cc439..e73d4f93c2 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -934,6 +934,10 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_
VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE |
+ FF_VK_EXT_VIDEO_MAINTENANCE_1))
+ fmt_info.imageUsage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
}
/* Get the format of the images necessary */
@@ -1023,6 +1027,7 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
AVVulkanFramesContext *hwfc = frames_ctx->hwctx;
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
FFVulkanDecodeProfileData *prof;
+ FFVulkanDecodeShared *ctx;
frames_ctx->sw_format = AV_PIX_FMT_NONE;
@@ -1059,6 +1064,11 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
if (!dec->dedicated_dpb)
hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
+ ctx = dec->shared_ctx;
+ if (ctx->s.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE |
+ FF_VK_EXT_VIDEO_MAINTENANCE_1))
+ hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
+
return err;
}
diff --git a/libavfilter/vulkan_filter.c b/libavfilter/vulkan_filter.c
index 2878d9063b..6221e0206d 100644
--- a/libavfilter/vulkan_filter.c
+++ b/libavfilter/vulkan_filter.c
@@ -37,6 +37,7 @@ int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s,
if (frames_ref) {
int no_storage = 0;
FFVulkanFunctions *vk;
+ VkImageUsageFlagBits usage_req;
const VkFormat *sub = av_vkfmt_from_pixfmt(sw_format);
frames_ctx = (AVHWFramesContext *)frames_ref->data;
@@ -57,18 +58,41 @@ int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s,
if (vk_frames->tiling != VK_IMAGE_TILING_OPTIMAL)
goto skip;
- /* Usage mismatch */
- if ((vk_frames->usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) !=
- (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT))
- goto skip;
-
s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions,
vk_dev->nb_enabled_dev_extensions);
+
+ /* More advanced format checks */
err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1);
if (err < 0)
return err;
vk = &s->vkfn;
+ /* Usage mismatch */
+ usage_req = VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_STORAGE_BIT;
+
+ /* If format supports hardware encoding, make sure
+ * the context includes it. */
+ if (vk_frames->format[1] == VK_FORMAT_UNDEFINED &&
+ (s->extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE |
+ FF_VK_EXT_VIDEO_MAINTENANCE_1))) {
+ VkFormatProperties3 fprops = {
+ .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3,
+ };
+ VkFormatProperties2 prop = {
+ .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
+ .pNext = &fprops,
+ };
+ vk->GetPhysicalDeviceFormatProperties2(vk_dev->phys_dev,
+ vk_frames->format[0],
+ &prop);
+ if (fprops.optimalTilingFeatures & VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR)
+ usage_req |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
+ }
+
+ if ((vk_frames->usage & usage_req) != usage_req)
+ goto skip;
+
/* Check if the subformats can do storage */
for (int i = 0; sub[i] != VK_FORMAT_UNDEFINED; i++) {
VkFormatProperties2 prop = {
@@ -113,13 +137,6 @@ skip:
frames_ctx->width = width;
frames_ctx->height = height;
- vk_frames = frames_ctx->hwctx;
- vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL;
- vk_frames->usage = VK_IMAGE_USAGE_SAMPLED_BIT |
- VK_IMAGE_USAGE_STORAGE_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-
err = av_hwframe_ctx_init(frames_ref);
if (err < 0) {
av_buffer_unref(&frames_ref);
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index b897a54621..3e00781e9e 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -2632,6 +2632,12 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_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 |
+ FF_VK_EXT_VIDEO_MAINTENANCE_1)))
+ hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
}
/* Image creation flags.
@@ -2650,6 +2656,28 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc)
}
}
+ /* If the image has an ENCODE_SRC usage, and the maintenance1
+ * extension is supported, check if it has a profile list.
+ * If there's no profile list, or it has no encode operations,
+ * then allow creating the image with no specific profile. */
+ if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) &&
+ p->video_maint_1_features.videoMaintenance1) {
+ const VkVideoProfileListInfoKHR *pl;
+ pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
+ if (!pl) {
+ hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
+ } else {
+ uint32_t i;
+ for (i = 0; i < pl->profileCount; i++) {
+ /* Video ops start at exactly 0x00010000 */
+ if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000)
+ break;
+ }
+ if (i == pl->profileCount)
+ hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR;
+ }
+ }
+
if (!hwctx->lock_frame)
hwctx->lock_frame = lock_frame;