Commit ecd3b68059 for ffmpeg
commit ecd3b68059df4461b51416d6a9dd30b062f7be62
Author: Emil J. Tywoniak <emil@tywoniak.eu>
Date: Sun Oct 25 22:56:31 2026 +0100
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.
Assisted-by: Claude Opus 5.5
diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c
index 9d3c9b04c5..d654cf05d6 100644
--- a/libavcodec/vulkan_encode.c
+++ b/libavcodec/vulkan_encode.c
@@ -337,6 +337,13 @@ 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,
+ FFALIGN(encode_info.dstBufferOffset,
+ ctx->s.props.properties.limits.nonCoherentAtomSize),
+ 1));
+
vp->slices_offset = encode_info.dstBufferOffset;
/* Align buffer size to the nearest lower alignment requirement. */
@@ -492,6 +499,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 +528,26 @@ 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,
+ FFALIGN(vp->slices_offset + query_data[0] +
+ query_data[1] - offs,
+ ctx->s.props.properties.limits.nonCoherentAtomSize),
+ 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];