This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit e3a228b1d0e0c93e2a9634c0c179921dec60c683 Author: Lynne <[email protected]> AuthorDate: Sat Nov 7 17:36:50 2026 +0800 Commit: Lynne <[email protected]> CommitDate: Sat Nov 7 22:20:30 2026 +0800 avfilter/vf_bwdif_vulkan: clip to the largest sample value bwdif clips its output to the largest value of the format's depth. The shader sees samples as fractions of their storage, so its results only saturated at the storage's largest value, which is above the format's whenever the format doesn't fill its storage: in low-aligned formats like yuv422p10, and high-aligned ones like P010. Pass the largest sample value to the shader, as a fraction of the storage, and clip to it. The 10-bit packed formats fill their storage, and float formats have no largest value, so they are left as they were. On moving, edge and still striped pictures in yuv420p, yuv422p10, yuv444p12, gbrp10, NV12 and P010, with both field orders and both modes, 20 of the 72 cases had samples above the format's range. None do now. Reported-by: oittaa --- libavfilter/vf_bwdif_vulkan.c | 21 ++++++++++++++++++++- libavfilter/vulkan/bwdif.comp.glsl | 9 ++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libavfilter/vf_bwdif_vulkan.c b/libavfilter/vf_bwdif_vulkan.c index 0f122f7642..9afd9ae409 100644 --- a/libavfilter/vf_bwdif_vulkan.c +++ b/libavfilter/vf_bwdif_vulkan.c @@ -20,6 +20,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <float.h> + +#include "libavutil/intfloat.h" #include "libavutil/random_seed.h" #include "libavutil/opt.h" #include "vulkan_filter.h" @@ -52,6 +55,8 @@ static av_cold int init_filter(AVFilterContext *ctx) FFVulkanContext *vkctx = &s->vkctx; const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(vkctx->output_format); + const VkFormat *vkfmts = av_vkfmt_from_pixfmt(vkctx->output_format); + float unit = 0.0f, clip_max = FLT_MAX; s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0); if (!s->qf) { @@ -62,9 +67,23 @@ static av_cold int init_filter(AVFilterContext *ctx) RET(ff_vk_exec_pool_init(vkctx, s->qf, &s->e, FF_VK_DEFAULT_EXEC_CONTEXTS, 0, 0, 0, NULL)); - SPEC_LIST_CREATE(sl, 2, 2*sizeof(int)) + /* The shader sees samples as fractions of their storage. bwdif clips to the + * largest sample value and decides on whole ones, so pass the largest and + * the size of a step. Float formats have neither. */ + if (vkfmts[0] == VK_FORMAT_A2R10G10B10_UNORM_PACK32 || + vkfmts[0] == VK_FORMAT_A2B10G10R10_UNORM_PACK32) { + unit = 1.0f / 1023; + } else if (!(desc->flags & AV_PIX_FMT_FLAG_FLOAT) && + desc->comp[0].depth + desc->comp[0].shift <= 16) { + int bits = desc->comp[0].depth + desc->comp[0].shift > 8 ? 16 : 8; + unit = (1 << desc->comp[0].shift) / (float)((1 << bits) - 1); + clip_max = ((1 << desc->comp[0].depth) - 1) * unit; + } + + SPEC_LIST_CREATE(sl, 3, 2*sizeof(int) + sizeof(float)) SPEC_LIST_ADD(sl, 0, 32, vkctx->output_height); SPEC_LIST_ADD(sl, 1, 32, AV_CEIL_RSHIFT(vkctx->output_height, desc->log2_chroma_h)); + SPEC_LIST_ADD(sl, 2, 32, av_float2int(clip_max)); ff_vk_shader_load(&s->shd, VK_SHADER_STAGE_COMPUTE_BIT, sl, (uint32_t [3]) { 1, 64, planes }, 0); diff --git a/libavfilter/vulkan/bwdif.comp.glsl b/libavfilter/vulkan/bwdif.comp.glsl index afe4486260..76d330cf9f 100644 --- a/libavfilter/vulkan/bwdif.comp.glsl +++ b/libavfilter/vulkan/bwdif.comp.glsl @@ -31,6 +31,9 @@ layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) in; layout (constant_id = 0) const int height = 0; layout (constant_id = 1) const int chroma_height = 0; +/* The largest sample value, which bwdif clips to */ +layout (constant_id = 2) const float clip_max = 1.0; + layout (set = 0, binding = 0) uniform writeonly image2D dst[]; layout (set = 0, binding = 1) uniform readonly image2D prev[]; layout (set = 0, binding = 2) uniform readonly image2D cur[]; @@ -62,7 +65,7 @@ void process_plane_intra(ivec2 pos, int h) dcur[1] = imageLoad(cur[idx], pos + ivec2(0, pos.y > 0 ? -1 : 1)); dcur[2] = imageLoad(cur[idx], pos + ivec2(0, pos.y + 1 < h ? 1 : -1)); dcur[3] = imageLoad(cur[idx], pos + ivec2(0, pos.y + 3 < h ? 3 : -1)); - imageStore(dst[idx], pos, process_intra(dcur)); + imageStore(dst[idx], pos, min(process_intra(dcur), clip_max)); } vec4 process_line(vec4 prev2[5], vec4 prev1[2], vec4 cur[4], vec4 next1[2], vec4 next2[5]) @@ -178,7 +181,7 @@ void process_plane(const ivec2 pos) next2[4] = imageLoad(next[idx], pos + ivec2(0, 4)); } - imageStore(dst[idx], pos, process_line(prev2, prev1, dcur, next1, next2)); + imageStore(dst[idx], pos, min(process_line(prev2, prev1, dcur, next1, next2), clip_max)); } void process_plane_edge(const ivec2 pos, int h) @@ -227,7 +230,7 @@ void process_plane_edge(const ivec2 pos, int h) next2[2] = imageLoad(next[idx], pos + d2); } - imageStore(dst[idx], pos, process_edge(prev2, prev1, dcur, next1, next2, spat)); + imageStore(dst[idx], pos, min(process_edge(prev2, prev1, dcur, next1, next2, spat), clip_max)); } void main() -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
