PR #24975 opened by Kilian (lusoris)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24975
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24975.patch
This backports ac16cfb86e to release/9.0. Without it, downloading
Vulkan-decoded frames through the host-image-copy path transitions images out
of a video layout. That violates
VUID-VkHostImageLayoutTransitionInfo-oldLayout-09230 on drivers that do not
list video layouts as host-copyable. The cherry-pick (`-x`) applies without
conflicts.
## Reproduction on Linux (before / after)
Intel Arc A380, ANV (Mesa 26.2.4, `ANV_DEBUG=video-decode` to expose Vulkan
decode), Khronos validation layer. Built release/9.0 `fd5d616c29` with and
without the backport:
```sh
ANV_DEBUG=video-decode ffmpeg -v verbose -init_hw_device
vulkan=vk:A380,debug=validate \
-hwaccel vulkan -hwaccel_device vk -i in.h264 -f null -
```
`in.h264` is 50 frames of 1280x720 libx264 with B-frames.
| | VUID-...-oldLayout-09230 | decoded frames vs software h264 (showinfo
checksums) |
| --- | --- | --- |
| release/9.0 | 3 (`oldLayout is VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR which is
not one of the layouts returned in ...pCopySrcLayouts[18]`) | 50/50 match |
| with backport | 0 | 50/50 match |
ANV lists 18 host-copy source layouts, and none of them is a video layout.
After the backport, such frames take the GPU download path, so the output is
unchanged and the validation error is gone.
RADV (Raphael iGPU) lists the video layouts as copyable and shows 0 VUIDs both
ways for hwupload/hwdownload. NVIDIA does not use the host path. So on Linux,
the error shows up on ANV.
Both runs also report VUID-VkImageCreateInfo-pNext-06811 on ANV (5 before, 4
after). That one comes from image creation with the video profile list. It is
unrelated to this change and present before it.
`make fate-source` passes on the backport.
>From 490d1d4d39cd2f6bd3dba9cb9d0459024990e18b Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sun, 26 Jul 2026 19:10:08 +0800
Subject: [PATCH] hwcontext_vulkan: only originate host image layout
transitions from copyable layouts
Host image layout transitions may only originate from a layout in
pCopySrcLayouts, or from UNDEFINED, discarding the contents. The host
transfer path transitioned from whatever layout the frame was last
left in, which for pool-recycled frames can be a video layout, which
no driver lists as host-copyable.
Uploads overwrite the entire image, so transition from UNDEFINED
there. Downloads have to preserve the contents, so route frames in a
non-host-copyable layout through the GPU path.
(cherry picked from commit ac16cfb86e3cdba0c05778ab09309b7d900a136c)
Signed-off-by: lusoris <[email protected]>
---
libavutil/hwcontext_vulkan.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index 90d3d14dbb..26b7e8fd54 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -4584,10 +4584,12 @@ static int vulkan_transfer_host(AVHWFramesContext
*hwfc, AVFrame *hwf,
if (compat)
continue;
+ /* This should only ever happen on uploads, so using UNDEFINED is safe
*/
+ av_assert1(upload);
layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
.image = hwf_vk->img[i],
- .oldLayout = hwf_vk->layout[i],
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
@@ -4709,8 +4711,27 @@ static int vulkan_transfer_frame(AVHWFramesContext *hwfc,
if (swf->width > hwfc->width || swf->height > hwfc->height)
return AVERROR(EINVAL);
- if (hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
- !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY))
+ int host_copy = hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
+ !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY);
+
+ /* Host layout transitions may only originate from a host-copyable layout
*/
+ if (!upload && host_copy) {
+ for (int i = 0; i < nb_images; i++) {
+ int compat = 0;
+ for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount;
j++) {
+ if (hwf_vk->layout[i] ==
p->vkctx.host_image_props.pCopySrcLayouts[j]) {
+ compat = 1;
+ break;
+ }
+ }
+ if (!compat) {
+ host_copy = 0;
+ break;
+ }
+ }
+ }
+
+ if (host_copy)
return vulkan_transfer_host(hwfc, hwf, swf, upload);
for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]