[FFmpeg-devel,PR] avfilter/scale_vulkan: normalize sampling by the hardware image size (PR #24821)
Commit Message
PR #24821 opened by Forgejo_Fairy
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24821
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24821.patch
Vulkan decoding can return a visible 1920×1080 frame backed by a 1920×1088 image. `scale_vulkan` currently divides the crop extent by the visible frame dimensions, so normalized texture sampling includes the image's padding and scales the wrong region.
Use `AVHWFramesContext.width` and `.height` for the normalization denominator while retaining the visible frame dimensions and cropping fields for the sampled region.
Related to #24051. The reproduced error affects both luma and chroma; the reporter's sample is still needed to establish whether this explains their specific symptom.
Validation on an NVIDIA RTX 5090 with driver 595.84:
- Software and Vulkan decoding produced identical NV12 pixels before scaling.
- For generated 1920×1080 H.264 input scaled to 640×360, unpatched Vulkan-decoded and CPU-uploaded paths differed in 12,483 luma bytes and 8,066 chroma bytes. After the fix, chroma matches exactly and only 43 luma samples differ by one level.
- Tested 15 scaling cases using input sizes 1920×1080, 854×480, 642×362, 1280×720, and 1920×1088, output sizes 640×360 and 1280×720, and nearest/bilinear sampling. After the fix, nearest comparisons are exact and bilinear differences are at most one level. Aligned controls match exactly.
- The original error also reproduces on e13b2e00e89d and release/8.1 at 1041abdc962f.
- Build and `git diff --check` passed.
The generated-input comparison script, measurements, and build instructions are preserved in `tools/issue24051/` on fairy/issue24051-tooling at 70f65891f191. These GPU measurements are not portable FATE reference outputs.
From 4819829f7a54ea3fd4995c6a747f2ba7dd0a58f7 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Tue, 29 Sep 2026 21:52:33 +0000
Subject: [PATCH] avfilter/scale_vulkan: normalize sampling by the hardware
image size
Vulkan decode can return a visible 1920x1080 frame backed by a
1920x1088 image. Dividing the crop extent by the visible frame dimensions
makes scale_vulkan sample the padding along with the picture.
Use the hardware frames context dimensions for normalized texture
coordinates. Keep the visible frame dimensions for the crop extent.
With a generated H.264 testsrc2 clip, this removes the scaling difference
between Vulkan decoding and software decoding followed by hwupload.
Tested padded widths and heights, aligned controls, up/downscaling,
and both bilinear and nearest sampling on an RTX 5090.
Related to issue #24051; confirmation with the reporter's input is still
needed because the observed padding error affects both luma and chroma.
Assisted-by: Fairy
---
libavfilter/vf_scale_vulkan.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
@@ -94,6 +94,7 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
int in_planes = av_pix_fmt_count_planes(s->vkctx.input_format);
int out_planes = av_pix_fmt_count_planes(s->vkctx.output_format);
+ const AVHWFramesContext *frames = (AVHWFramesContext *)in->hw_frames_ctx->data;
switch (s->scaler) {
case F_NEAREST:
@@ -167,8 +168,9 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
s->opts.yuv_matrix[3][3] = 1.0;
}
- s->opts.in_dims[0] = in->width;
- s->opts.in_dims[1] = in->height;
+ /* Normalized texture coordinates include hardware frame padding. */
+ s->opts.in_dims[0] = frames->width;
+ s->opts.in_dims[1] = frames->height;
RET(ff_vk_shader_link(vkctx, shd,
ff_scale_comp_spv_data,