PR #25463 opened by widlarizer
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25463
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25463.patch

# Summary of changes

## Context

I discovered H264 encoding errors caused by ffmpeg on a meteor lake laptop 
while debugging mesa vulkan encode issues for i915/xe. It turns out to be a 
cache coherence issue. Claude Opus 5.5 was used in debugging the problem and 
producing the patch but I kept it on a tight leash.

## Code

The packet buffer can be non-coherent (e.g. Intel non-LLC GPUs). The
headers written by the CPU were never flushed before submission, and
the readback flushed instead of invalidating. On Meteor Lake this
corrupted h264_vulkan and hevc_vulkan output at random.

## Tests

I'm not including any tests. Open to advice on this.

# Reproducer

## Environment

- ffmpeg 9.0 and master `46f23be8b197` (2026-10-17). Master still requests
  `HOST_CACHED` for the packet buffer whenever the device has a cached type
  (`s->host_cached_flag`), and on this GPU that type is non-coherent.
- Intel Meteor Lake (8086:7d55), i915, Linux 6.18.58
- Mesa ANV main `18879c94176c`
- ANV memory types on this machine:
  - `DEVICE_LOCAL | HOST_VISIBLE | HOST_COHERENT`
  - `DEVICE_LOCAL | HOST_VISIBLE | HOST_CACHED` (non-coherent),
    `nonCoherentAtomSize` 64

## Script

```sh
ffmpeg -f lavfi -i "testsrc2=s=1920x1080:r=100,noise=alls=12:allf=t+u" 
-frames:v 100 \
  -pix_fmt nv12 -f rawvideo src.yuv

for i in 1 2 3; do
  ffmpeg -init_hw_device vulkan=vk:0 -filter_hw_device vk \
    -f rawvideo -pix_fmt nv12 -s 1920x1080 -r 100 -stream_loop 2 -i src.yuv \
    -vf format=nv12,hwupload -c:v h264_vulkan -bf 0 -g 1000 \
    -rc_mode cbr -b:v 20M -maxrate 20M -bufsize 20M -y out$i.h264
  md5sum out$i.h264
  ffmpeg -v error -i out$i.h264 -f null - 2>&1 | wc -l    # decode errors
done
```

##




>From 99c61e23b396c59013cdaf64441e311f0b07a049 Mon Sep 17 00:00:00 2001
From: "Emil J. Tywoniak" <[email protected]>
Date: Sun, 25 Oct 2026 22:56:31 +0100
Subject: [PATCH] avcodec/vulkan_encode: flush and invalidate non-coherent
 packet buffers

The packet buffer can be non-coherent (e.g. Intel non-LLC GPUs). The
headers written by the CPU were never flushed before submission, and
the readback flushed instead of invalidating. On Meteor Lake this
corrupted h264_vulkan and hevc_vulkan output at random.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 libavcodec/vulkan_encode.c | 43 +++++++++++++++++---------------------
 1 file changed, 19 insertions(+), 24 deletions(-)

diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c
index 9d3c9b04c57..8b61c76abbf 100644
--- a/libavcodec/vulkan_encode.c
+++ b/libavcodec/vulkan_encode.c
@@ -337,6 +337,10 @@ static int vulkan_encode_issue(AVCodecContext *avctx,
         }
     }
 
+    /* Flush the headers written above if needed */
+    if (encode_info.dstBufferOffset)
+        RET(ff_vk_flush_buffer(&ctx->s, sd_buf, 0, VK_WHOLE_SIZE, 1));
+
     vp->slices_offset = encode_info.dstBufferOffset;
 
     /* Align buffer size to the nearest lower alignment requirement. */
@@ -492,6 +496,7 @@ static int vulkan_encode_output(AVCodecContext *avctx,
                                 FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
 {
     VkResult ret;
+    int err, offs;
     FFVulkanEncodePicture *vp = base_pic->priv;
     FFVulkanEncodeContext *ctx = avctx->priv_data;
     FFHWBaseEncodeContext *base_ctx = &ctx->base;
@@ -520,32 +525,22 @@ static int vulkan_encode_output(AVCodecContext *avctx,
         return AVERROR_EXTERNAL;
     }
 
-    /* Invalidate buffer if needed */
-    if (!(sd_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
-        FFVulkanFunctions *vk = &ctx->s.vkfn;
-        VkMappedMemoryRange invalidate_buf;
-
-        int offs = vp->slices_offset;
-        /* If the non-coherent alignment is greater than the bitstream buffer
-         * offset's alignment, and the offs value is not aligned already,
-         * align it to the previous alignment point. */
-        if (ctx->s.props.properties.limits.nonCoherentAtomSize >
-            ctx->caps.minBitstreamBufferOffsetAlignment && offs &&
-            (FFALIGN(offs, ctx->s.props.properties.limits.nonCoherentAtomSize) 
!= offs)) {
-            offs -= ctx->s.props.properties.limits.nonCoherentAtomSize;
-            offs = FFALIGN(FFMAX(offs, 0), 
ctx->s.props.properties.limits.nonCoherentAtomSize);
-        }
-
-        invalidate_buf = (VkMappedMemoryRange) {
-            .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
-            .memory = sd_buf->mem,
-            .offset = offs,
-            .size = VK_WHOLE_SIZE,
-        };
-
-        vk->FlushMappedMemoryRanges(ctx->s.hwctx->act_dev, 1, &invalidate_buf);
+    /* If the non-coherent alignment is greater than the bitstream buffer
+     * offset's alignment, and the offs value is not aligned already,
+     * align it to the previous alignment point. */
+    offs = vp->slices_offset;
+    if (ctx->s.props.properties.limits.nonCoherentAtomSize >
+        ctx->caps.minBitstreamBufferOffsetAlignment && offs &&
+        (FFALIGN(offs, ctx->s.props.properties.limits.nonCoherentAtomSize) != 
offs)) {
+        offs -= ctx->s.props.properties.limits.nonCoherentAtomSize;
+        offs = FFALIGN(FFMAX(offs, 0), 
ctx->s.props.properties.limits.nonCoherentAtomSize);
     }
 
+    /* Invalidate buffer if needed */
+    err = ff_vk_flush_buffer(&ctx->s, sd_buf, offs, VK_WHOLE_SIZE, 0);
+    if (err < 0)
+        return err;
+
     if (vp->non_independent_frame) {
         av_assert0(!ctx->prev_buf_ref);
         size_t prev_buf_size = vp->slices_offset + query_data[0] + 
query_data[1];
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to