PR #20999 opened by Lynne URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20999 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20999.patch
Nothing too major. >From 41c50176c70ae80b9e49ddb89555acf4da6256cf Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Thu, 13 Nov 2025 12:09:11 +0100 Subject: [PATCH 1/7] hwcontext_vulkan: enable runtime descriptor sizing We were already using this in places, but it seems validation layers finally got support to detect it. --- libavutil/hwcontext_vulkan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index a6bf9a590b..0408b9c117 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -307,6 +307,7 @@ static void device_features_copy_needed(VulkanDeviceFeatures *dst, VulkanDeviceF COPY_VAL(vulkan_1_2.vulkanMemoryModel); COPY_VAL(vulkan_1_2.vulkanMemoryModelDeviceScope); COPY_VAL(vulkan_1_2.uniformBufferStandardLayout); + COPY_VAL(vulkan_1_2.runtimeDescriptorArray); COPY_VAL(vulkan_1_3.dynamicRendering); COPY_VAL(vulkan_1_3.maintenance4); -- 2.49.1 >From 8e0adcb97f11f3f769d4e44eaf6ef291d43c25f4 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Thu, 20 Nov 2025 01:36:07 +0100 Subject: [PATCH 2/7] hwcontext_vulkan: enable host image copy but disable its automatic use This keeps the current behaviour and allows to use host image copy in more direct ways. --- libavutil/hwcontext_vulkan.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 0408b9c117..2834d45c41 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -656,6 +656,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_EXT_zero_initialize_device_memory { VK_EXT_ZERO_INITIALIZE_DEVICE_MEMORY_EXTENSION_NAME, FF_VK_EXT_ZERO_INITIALIZE }, #endif @@ -1707,25 +1708,6 @@ static void vulkan_device_uninit(AVHWDeviceContext *ctx) ff_vk_uninit(&p->vkctx); } -static int vulkan_device_has_rebar(AVHWDeviceContext *ctx) -{ - VulkanDevicePriv *p = ctx->hwctx; - VkDeviceSize max_vram = 0, max_visible_vram = 0; - - /* Get device memory properties */ - for (int i = 0; i < p->mprops.memoryTypeCount; i++) { - const VkMemoryType type = p->mprops.memoryTypes[i]; - const VkMemoryHeap heap = p->mprops.memoryHeaps[type.heapIndex]; - if (!(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) - continue; - max_vram = FFMAX(max_vram, heap.size); - if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) - max_visible_vram = FFMAX(max_visible_vram, heap.size); - } - - return max_vram - max_visible_vram < 1024; /* 1 kB tolerance */ -} - static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDeviceSelection *dev_select, int disable_multiplane, @@ -2079,7 +2061,7 @@ FF_ENABLE_DEPRECATION_WARNINGS vk->GetPhysicalDeviceMemoryProperties(hwctx->phys_dev, &p->mprops); /* Only use host image transfers if ReBAR is enabled */ - p->disable_host_transfer = !vulkan_device_has_rebar(ctx); + p->disable_host_transfer = 1; end: av_free(qf_vid); -- 2.49.1 >From 056a0bb269b1f35409946cd63d46cb7a41bcc3bd Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Wed, 5 Nov 2025 10:31:18 +0100 Subject: [PATCH 3/7] vulkan/common: add a function to flush/invalidate a buffer and use it Just for convenience. --- libavutil/hwcontext_vulkan.c | 45 ++++++++++++------------------------ libavutil/vulkan.c | 31 +++++++++++++++++++++++++ libavutil/vulkan.h | 7 ++++++ 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 2834d45c41..13332c1b5b 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -4154,29 +4154,10 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, AVBufferRef *buf, AVFrame *swf, VkBufferImageCopy *region, int planes, int upload) { - VkResult ret; + int err; VulkanDevicePriv *p = hwfc->device_ctx->hwctx; - FFVulkanFunctions *vk = &p->vkctx.vkfn; - AVVulkanDeviceContext *hwctx = &p->p; - FFVkBuffer *vkbuf = (FFVkBuffer *)buf->data; - const VkMappedMemoryRange flush_info = { - .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, - .memory = vkbuf->mem, - .size = VK_WHOLE_SIZE, - }; - - if (!upload && !(vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { - ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, 1, - &flush_info); - if (ret != VK_SUCCESS) { - av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; - } - } - if (upload) { for (int i = 0; i < planes; i++) av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset, @@ -4185,7 +4166,21 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, AVBufferRef *buf, swf->linesize[i], swf->linesize[i], region[i].imageExtent.height); + + err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 1); + if (err != VK_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n", + av_err2str(err)); + return AVERROR_EXTERNAL; + } } else { + err = ff_vk_flush_buffer(&p->vkctx, vkbuf, 0, VK_WHOLE_SIZE, 0); + if (err != VK_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n", + av_err2str(err)); + return AVERROR_EXTERNAL; + } + for (int i = 0; i < planes; i++) av_image_copy_plane(swf->data[i], swf->linesize[i], @@ -4195,16 +4190,6 @@ static int copy_buffer_data(AVHWFramesContext *hwfc, AVBufferRef *buf, region[i].imageExtent.height); } - if (upload && !(vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { - ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, 1, - &flush_info); - if (ret != VK_SUCCESS) { - av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; - } - } - return 0; } diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index 54448a32e5..c7f86d524c 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -1167,6 +1167,37 @@ int ff_vk_map_buffers(FFVulkanContext *s, FFVkBuffer **buf, uint8_t *mem[], return 0; } +int ff_vk_flush_buffer(FFVulkanContext *s, FFVkBuffer *buf, + size_t offset, size_t mem_size, + int flush) +{ + VkResult ret; + FFVulkanFunctions *vk = &s->vkfn; + + if (buf->host_ref || buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) + return 0; + + const VkMappedMemoryRange flush_data = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = buf->mem, + .offset = offset, + .size = mem_size, + }; + + if (flush) + ret = vk->FlushMappedMemoryRanges(s->hwctx->act_dev, 1, &flush_data); + else + ret = vk->InvalidateMappedMemoryRanges(s->hwctx->act_dev, 1, &flush_data); + + if (ret != VK_SUCCESS) { + av_log(s, AV_LOG_ERROR, "Failed to flush memory: %s\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + int ff_vk_unmap_buffers(FFVulkanContext *s, FFVkBuffer **buf, int nb_buffers, int flush) { diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h index e1c9a5792f..bdc20e4645 100644 --- a/libavutil/vulkan.h +++ b/libavutil/vulkan.h @@ -523,6 +523,13 @@ int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, void *pNext, void *alloc_pNext, VkBufferUsageFlags usage, VkMemoryPropertyFlagBits flags); +/** + * Flush or invalidate a single buffer, with a given size and offset. + */ +int ff_vk_flush_buffer(FFVulkanContext *s, FFVkBuffer *buf, + size_t offset, size_t mem_size, + int flush); + /** * Buffer management code. */ -- 2.49.1 >From d0c01040052b0f3187727a9d7094ccbdc964ea02 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Tue, 18 Nov 2025 12:09:51 +0100 Subject: [PATCH 4/7] vulkan/common: add reverse2 endian reversal macro --- libavcodec/vulkan/common.comp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libavcodec/vulkan/common.comp b/libavcodec/vulkan/common.comp index 6825693fa3..eda92ce28d 100644 --- a/libavcodec/vulkan/common.comp +++ b/libavcodec/vulkan/common.comp @@ -79,6 +79,9 @@ uint64_t align64(uint64_t src, uint64_t a) return src + a - res; } +#define reverse2(src) \ + (pack16(unpack8(uint16_t(src)).yx)) + #define reverse4(src) \ (pack32(unpack8(uint32_t(src)).wzyx)) -- 2.49.1 >From 43929dfed57249f14ead92e9cd3341c34a190b24 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Thu, 20 Nov 2025 18:09:17 +0100 Subject: [PATCH 5/7] ffv1enc: add entries for X2BGR10/X2RGB10 They are output by Vulkan decoders, and are also a very common display surface format. --- libavcodec/ffv1enc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index 8e5ebe773c..5daa3aa0cd 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -914,6 +914,8 @@ av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, case AV_PIX_FMT_GBRP9: if (!avctx->bits_per_raw_sample) s->bits_per_raw_sample = 9; + case AV_PIX_FMT_X2BGR10: + case AV_PIX_FMT_X2RGB10: case AV_PIX_FMT_GBRP10: case AV_PIX_FMT_GBRAP10: if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) -- 2.49.1 >From a4e99b52d565558a9dd0f7839ee7fd595b0d795e Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Sat, 22 Nov 2025 13:13:43 +0100 Subject: [PATCH 6/7] vulkan_ffv1/prores: remove unnecessary slice buffer unref The slice buffer is already unref'd by ff_vk_decode_free_frame(). --- libavcodec/vulkan_ffv1.c | 1 - libavcodec/vulkan_prores.c | 1 - 2 files changed, 2 deletions(-) diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c index 1ed9d7dd6c..66659e0069 100644 --- a/libavcodec/vulkan_ffv1.c +++ b/libavcodec/vulkan_ffv1.c @@ -1148,7 +1148,6 @@ static void vk_ffv1_free_frame_priv(AVRefStructOpaque _hwctx, void *data) i, status, crc_res); } - av_buffer_unref(&vp->slices_buf); av_buffer_unref(&fp->slice_state); av_buffer_unref(&fp->slice_offset_buf); av_buffer_unref(&fp->slice_status_buf); diff --git a/libavcodec/vulkan_prores.c b/libavcodec/vulkan_prores.c index 42e8fa0b06..edab4f8564 100644 --- a/libavcodec/vulkan_prores.c +++ b/libavcodec/vulkan_prores.c @@ -577,7 +577,6 @@ static void vk_prores_free_frame_priv(AVRefStructOpaque _hwctx, void *data) ff_vk_decode_free_frame(dev_ctx, &pp->vp); - av_buffer_unref(&vp->slices_buf); av_buffer_unref(&pp->metadata_buf); } -- 2.49.1 >From 982ec02c7ca278140e9612093e1ec05b7de25687 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Sat, 22 Nov 2025 22:37:17 +0100 Subject: [PATCH 7/7] vulkan_ffv1: initialize only the necessary shaders on init The decoder will reinit the hwaccel upon pixfmt/dimension changes, so we can remove the f->use32bit and is_rgb variants of all shaders. This speeds up init time. --- libavcodec/vulkan_ffv1.c | 91 ++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c index 66659e0069..430054cbe1 100644 --- a/libavcodec/vulkan_ffv1.c +++ b/libavcodec/vulkan_ffv1.c @@ -59,11 +59,11 @@ typedef struct FFv1VulkanDecodePicture { } FFv1VulkanDecodePicture; typedef struct FFv1VulkanDecodeContext { - AVBufferRef *intermediate_frames_ref[2]; /* 16/32 bit */ + AVBufferRef *intermediate_frames_ref; FFVulkanShader setup; FFVulkanShader reset[2]; /* AC/Golomb */ - FFVulkanShader decode[2][2][2]; /* 16/32 bit, AC/Golomb, Normal/RGB */ + FFVulkanShader decode[2]; /* AC/Golomb */ FFVkBuffer rangecoder_static_buf; FFVkBuffer quant_buf; @@ -239,7 +239,7 @@ static int vk_ffv1_start_frame(AVCodecContext *avctx, if (!vp->dpb_frame) return AVERROR(ENOMEM); - err = av_hwframe_get_buffer(fv->intermediate_frames_ref[f->use32bit], + err = av_hwframe_get_buffer(fv->intermediate_frames_ref, vp->dpb_frame, 0); if (err < 0) return err; @@ -527,7 +527,7 @@ static int vk_ffv1_end_frame(AVCodecContext *avctx) f->plane_count); /* Decode */ - decode_shader = &fv->decode[f->use32bit][f->ac == AC_GOLOMB_RICE][is_rgb]; + decode_shader = &fv->decode[f->ac == AC_GOLOMB_RICE]; ff_vk_shader_update_desc_buffer(&ctx->s, exec, decode_shader, 1, 0, 0, slice_state, @@ -823,7 +823,7 @@ static int init_decode_shader(FFV1Context *f, FFVulkanContext *s, FFVulkanShader *shd, AVHWFramesContext *dec_frames_ctx, AVHWFramesContext *out_frames_ctx, - int use32bit, int ac, int rgb) + int ac, int rgb) { int err; FFVulkanDescriptorSetBinding *desc_set; @@ -831,6 +831,7 @@ static int init_decode_shader(FFV1Context *f, FFVulkanContext *s, uint8_t *spv_data; size_t spv_len; void *spv_opaque = NULL; + int use_cached_reader = ac != AC_GOLOMB_RICE && s->driver_props.driverID == VK_DRIVER_ID_MESA_RADV; @@ -879,7 +880,7 @@ static int init_decode_shader(FFV1Context *f, FFVulkanContext *s, RET(ff_vk_shader_add_descriptor_set(s, shd, desc_set, 2, 1, 0)); - define_shared_code(shd, use32bit); + define_shared_code(shd, f->use32bit); if (ac == AC_GOLOMB_RICE) GLSLD(ff_source_ffv1_vlc_comp); @@ -977,16 +978,12 @@ static void vk_decode_ffv1_uninit(FFVulkanDecodeShared *ctx) ff_vk_shader_free(&ctx->s, &fv->setup); - for (int i = 0; i < 2; i++) /* 16/32 bit */ - av_buffer_unref(&fv->intermediate_frames_ref[i]); + av_buffer_unref(&fv->intermediate_frames_ref); - for (int i = 0; i < 2; i++) /* AC/Golomb */ + for (int i = 0; i < 2; i++) { /* AC/Golomb */ ff_vk_shader_free(&ctx->s, &fv->reset[i]); - - for (int i = 0; i < 2; i++) /* 16/32 bit */ - for (int j = 0; j < 2; j++) /* AC/Golomb */ - for (int k = 0; k < 2; k++) /* Normal/RGB */ - ff_vk_shader_free(&ctx->s, &fv->decode[i][j][k]); + ff_vk_shader_free(&ctx->s, &fv->decode[i]); + } ff_vk_free_buf(&ctx->s, &fv->quant_buf); ff_vk_free_buf(&ctx->s, &fv->rangecoder_static_buf); @@ -1008,6 +1005,11 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) FFv1VulkanDecodeContext *fv; FFVkSPIRVCompiler *spv; + AVHWFramesContext *hwfc = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + enum AVPixelFormat sw_format = hwfc->sw_format; + int is_rgb = !(f->colorspace == 0 && sw_format != AV_PIX_FMT_YA8) && + !(sw_format == AV_PIX_FMT_YA8); + if (f->version < 3 || (f->version == 4 && f->micro_version > 3)) return AVERROR(ENOTSUP); @@ -1032,36 +1034,27 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) ctx->sd_ctx_free = &vk_decode_ffv1_uninit; /* Intermediate frame pool for RCT */ - for (int i = 0; i < 2; i++) { /* 16/32 bit */ - RET(init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref[i], - i ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16)); - } + RET(init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref, + f->use32bit ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16)); /* Setup shader */ RET(init_setup_shader(f, &ctx->s, &ctx->exec_pool, spv, &fv->setup)); - /* Reset shaders */ for (int i = 0; i < 2; i++) { /* AC/Golomb */ + /* Reset shaders */ RET(init_reset_shader(f, &ctx->s, &ctx->exec_pool, spv, &fv->reset[i], !i ? AC_RANGE_CUSTOM_TAB : 0)); - } - /* Decode shaders */ - for (int i = 0; i < 2; i++) { /* 16/32 bit */ - for (int j = 0; j < 2; j++) { /* AC/Golomb */ - for (int k = 0; k < 2; k++) { /* Normal/RGB */ - AVHWFramesContext *dec_frames_ctx; - dec_frames_ctx = k ? (AVHWFramesContext *)fv->intermediate_frames_ref[i]->data : - (AVHWFramesContext *)avctx->hw_frames_ctx->data; - RET(init_decode_shader(f, &ctx->s, &ctx->exec_pool, - spv, &fv->decode[i][j][k], - dec_frames_ctx, - (AVHWFramesContext *)avctx->hw_frames_ctx->data, - i, - !j ? AC_RANGE_CUSTOM_TAB : AC_GOLOMB_RICE, - k)); - } - } + /* Decode shaders */ + AVHWFramesContext *dctx; + dctx = is_rgb ? (AVHWFramesContext *)fv->intermediate_frames_ref->data : + hwfc; + RET(init_decode_shader(f, &ctx->s, &ctx->exec_pool, + spv, &fv->decode[i], + dctx, + (AVHWFramesContext *)avctx->hw_frames_ctx->data, + !i ? AC_RANGE_CUSTOM_TAB : AC_GOLOMB_RICE, + is_rgb)); } /* Range coder data */ @@ -1092,21 +1085,17 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) VK_FORMAT_UNDEFINED)); /* Update decode global descriptors */ - for (int i = 0; i < 2; i++) { /* 16/32 bit */ - for (int j = 0; j < 2; j++) { /* AC/Golomb */ - for (int k = 0; k < 2; k++) { /* Normal/RGB */ - RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], - &fv->decode[i][j][k], 0, 0, 0, - &fv->rangecoder_static_buf, - 0, fv->rangecoder_static_buf.size, - VK_FORMAT_UNDEFINED)); - RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], - &fv->decode[i][j][k], 0, 1, 0, - &fv->quant_buf, - 0, fv->quant_buf.size, - VK_FORMAT_UNDEFINED)); - } - } + for (int i = 0; i < 2; i++) { /* AC/Golomb */ + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode[i], 0, 0, 0, + &fv->rangecoder_static_buf, + 0, fv->rangecoder_static_buf.size, + VK_FORMAT_UNDEFINED)); + RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], + &fv->decode[i], 0, 1, 0, + &fv->quant_buf, + 0, fv->quant_buf.size, + VK_FORMAT_UNDEFINED)); } fail: -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
