[PATCH 2/2] lavc/vvc: add AVX2 planar intra prediction

Gudikandula Samith via ffmpeg-devel <[email protected]> Sat, 25 Jul 2026 21:36:58 +0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <[email protected]>
Implements pred_planar for x86-64 AVX2 at 8 bit.

Benchmarks on AMD Ryzen 7 5825U:
  vvc_pred_planar_4x4_8_c:         52.8
  vvc_pred_planar_4x4_8_avx2:      24.1 (2.16x)
  vvc_pred_planar_8x8_8_c:        208.3
  vvc_pred_planar_8x8_8_avx2:      48.3 (4.31x)
  vvc_pred_planar_16x16_8_c:      778.0
  vvc_pred_planar_16x16_8_avx2:   160.4 (4.80x)
  vvc_pred_planar_32x32_8_c:     2356.0
  vvc_pred_planar_32x32_8_avx2:   580.3 (4.02x)
  vvc_pred_planar_64x64_8_c:     7414.0
  vvc_pred_planar_64x64_8_avx2:  2185.9 (3.27x)

Signed-off-by: Gudikandula Samith <[email protected]>
---
 libavcodec/x86/vvc/Makefile   |   1 +
 libavcodec/x86/vvc/dsp_init.c |  13 ++
 libavcodec/x86/vvc/intra.asm  | 224 ++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 libavcodec/x86/vvc/intra.asm

diff --git a/libavcodec/x86/vvc/Makefile b/libavcodec/x86/vvc/Makefile
index 0cebfb4e9e..b24ea6e692 100644
--- a/libavcodec/x86/vvc/Makefile
+++ b/libavcodec/x86/vvc/Makefile
@@ -4,6 +4,7 @@ clean::
 X86ASM-OBJS-$(CONFIG_VVC_DECODER)      += x86/vvc/dsp_init.o        \
                                           x86/vvc/alf.o             \
                                           x86/vvc/dmvr.o            \
+                                          x86/vvc/intra.o           \
                                           x86/vvc/mc.o              \
                                           x86/vvc/of.o              \
                                           x86/vvc/sad.o             \
diff --git a/libavcodec/x86/vvc/dsp_init.c b/libavcodec/x86/vvc/dsp_init.c
index 6802294795..4f187e1eb1 100644
--- a/libavcodec/x86/vvc/dsp_init.c
+++ b/libavcodec/x86/vvc/dsp_init.c
@@ -292,6 +292,16 @@ void bf(ff_vvc_alf_filter_chroma, bd, opt)(uint8_t *dst, ptrdiff_t dst_stride, \
     c->alf.classify       = bf(vvc_alf_classify, bd, opt);                     \
 } while (0)
 
+#define INTRA_PROTOTYPE(bd, opt)                                               \
+void ff_vvc_pred_planar_##bd##_##opt(uint8_t *src, const uint8_t *top,         \
+    const uint8_t *left, int w, int h, ptrdiff_t stride);
+
+INTRA_PROTOTYPE(8, avx2)
+
+#define INTRA_INIT(bd, opt) do {                                               \
+    c->intra.pred_planar = ff_vvc_pred_planar_##bd##_##opt;                    \
+} while (0)
+
 #endif
 
 
@@ -321,6 +331,9 @@ av_cold void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd)
             // filter
             ALF_INIT(8, avx2);
             SAO_INIT(8, avx2);
+
+            // intra
+            INTRA_INIT(8, avx2);
         }
 #endif
         break;
diff --git a/libavcodec/x86/vvc/intra.asm b/libavcodec/x86/vvc/intra.asm
new file mode 100644
index 0000000000..c18c17193a
--- /dev/null
+++ b/libavcodec/x86/vvc/intra.asm
@@ -0,0 +1,224 @@
+; /*
+; * Provide SIMD planar intra prediction functions for VVC decoding
+; *
+; * Copyright (c) 2026 Gudikandula Samith <[email protected]>
+; *
+; * This file is part of FFmpeg.
+; *
+; * FFmpeg is free software; you can redistribute it and/or
+; * modify it under the terms of the GNU Lesser General Public
+; * License as published by the Free Software Foundation; either
+; * version 2.1 of the License, or (at your option) any later version.
+; *
+; * FFmpeg is distributed in the hope that it will be useful,
+; * but WITHOUT ANY WARRANTY; without even the implied warranty of
+; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; * Lesser General Public License for more details.
+; *
+; * You should have received a copy of the GNU Lesser General Public
+; * License along with FFmpeg; if not, write to the Free Software
+; * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+; */
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+pw_wm1x_w4:  dw  3,  2,  1,  0,  0,  0,  0,  0
+pw_xp1_w4:   dw  1,  2,  3,  4,  0,  0,  0,  0
+pw_wm1x_w8:  dw  7,  6,  5,  4,  3,  2,  1,  0
+pw_xp1_w8:   dw  1,  2,  3,  4,  5,  6,  7,  8
+pw_wm1x_w16: dw  15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0  ; (w - 1 - x)
+pw_xp1_w16:  dw  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16  ; (x + 1)
+pw_wm1x_w32: dw  31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \
+                 15, 14, 13, 12, 11, 10, 9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+pw_xp1_w32:  dw  1,  2,  3,  4,  5,  6,  7,  8, 9,  10, 11, 12, 13, 14, 15, 16, \
+                 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+pw_wm1x_w64: dw  63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, \
+                 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, \
+                 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \
+                 15, 14, 13, 12, 11, 10, 9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+pw_xp1_w64:  dw  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, \
+                 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, \
+                 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, \
+                 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+
+
+SECTION .text
+
+%if ARCH_X86_64
+%if HAVE_AVX2_EXTERNAL
+
+INIT_YMM avx2
+
+; Per-row scalars, broadcast into vector registers:
+; m8 = A = (h-1-y)
+; m9 = B = (y+1) * left[h]
+; m10 = C = left[y]
+%macro ROW_CONSTANTS 0
+    mov           eax, r12d
+    sub           eax, r11d           ;A=(h-1-y)
+    movd          xm8, eax
+    vpbroadcastw   m8, xm8
+    lea            eax, [r11d+1]
+    imul           eax, r10d          ;B=(y+1)*left[h]
+    movd           xm9, eax
+    vpbroadcastw    m9, xm9
+    movzx           eax, byte [leftq+r11]
+    movd           xm10, eax
+    vpbroadcastw   m10, xm10
+%endmacro
+; Block-constant setup shared by every width.
+;  %1 = logw (immediate), %2 = top[w] byte offset (=width)
+%macro PLANAR_SETUP 2
+    mov            r13d, hd
+    bsr             r6d, hd
+    lea             r7d, [r6d +%1 +1]
+    mov             r8d, hd
+    shl             r8d, %1          ;size=w*h= h<<logw
+    movzx           r9d, byte [topq + %2]
+    movzx          r10d, byte [leftq +r13]
+    movd            xm3, r9d
+    vpbroadcastw     m3, xm3
+    movd            xm4, r8d
+    vpbroadcastd     m4, xm4
+    movd            xm5, r6d
+    movd             xm6, r7d
+    mov             r12d, hd
+    dec             r12d
+    xor             r11d, r11d
+%endmacro
+
+; Process 16 columns starting at column offset %3.
+;   %1 = (w-1-x) table, %2 = (x+1) table, %3 = column offset, %4 = logw immediate
+%macro PLANAR16 4
+    pmovzxbw         m0, [topq+%3]
+    movu             m1, [%1 + %3*2]
+    movu             m2, [%2 + %3*2]
+    vpmullw          m11, m0, m8
+    vpaddw           m11, m11, m9
+    vpmullw          m12, m1, m10
+    vpmullw           m2, m2, m3
+    vpaddw           m12, m12, m2
+    pmovzxwd         m13, xm11
+    pmovzxwd         m14, xm12
+    vpslld           m13, m13, %4
+    vpslld           m14, m14, xm5
+    vpaddd           m13, m13, m14
+    vpaddd           m13, m13, m4
+    vpsrad           m13, m13, xm6
+    vextracti128     xm11, m11, 1
+    vextracti128     xm12, m12, 1
+    pmovzxwd         m14, xm11
+    pmovzxwd         m15, xm12
+    vpslld           m14, m14, %4
+    vpslld           m15, m15, xm5
+    vpaddd           m14, m14, m15
+    vpaddd           m14, m14, m4
+    vpsrad           m14, m14, xm6
+    packusdw         m13, m13, m14
+    vpermq           m13, m13, 11011000b
+    packuswb         m13, m13, m13
+    vpermq           m13, m13, 11011000b
+    movu   [srcq + %3], xm13
+%endmacro
+
+; Process a narrow row of 4 or 8 columns (offset 0).
+;   %1 = (w-1-x) table, %2 = (x+1) table, %3 = logw immediate, %4 = store instruction
+%macro PLANAR_NARROW 4
+    pmovzxbw          xm0, [topq]
+    movu              xm1, [%1]
+    movu              xm2, [%2]
+    vpmullw           xm11, xm0, xm8
+    vpaddw            xm11, xm11, xm9
+    vpmullw           xm12, xm1, xm10
+    vpmullw           xm2, xm2, xm3
+    vpaddw            xm12, xm12, xm2
+    pmovzxwd          m13, xm11
+    pmovzxwd          m14, xm12
+    vpslld            m13, m13, %3
+    vpslld            m14, m14, xm5
+    vpaddd            m13, m13, m14
+    vpaddd            m13, m13, m4
+    vpsrad            m13, m13, xm6
+    packusdw          m13, m13, m13
+    vpermq            m13, m13, 11011000b
+    packuswb          m13, m13, m13
+    %4      [srcq], xm13
+%endmacro
+
+; void ff_vvc_pred_planar_8_avx2(uint8_t *src, const uint8_t *top,
+;                                const uint8_t *left, int w, int h,
+;                                ptrdiff_t stride);
+cglobal vvc_pred_planar_8, 6, 14, 16, src, top, left, w, h, stride
+    cmp             wd, 16
+    je .w16
+    cmp             wd, 8
+    je .w8
+    cmp             wd, 32
+    je .w32
+    cmp             wd, 64
+    je .w64
+    ; fall through to width 4
+
+.w4:
+    PLANAR_SETUP 2, 4
+.w4_row:
+    ROW_CONSTANTS
+    PLANAR_NARROW pw_wm1x_w4, pw_xp1_w4, 2, movd
+    add            srcq, strideq
+    inc            r11d
+    cmp            r11d, hd
+    jl .w4_row
+    RET
+
+.w8:
+    PLANAR_SETUP 3, 8
+.w8_row:
+    ROW_CONSTANTS
+    PLANAR_NARROW pw_wm1x_w8, pw_xp1_w8, 3, movq
+    add            srcq, strideq
+    inc            r11d
+    cmp            r11d, hd
+    jl .w8_row
+    RET
+
+.w16:
+    PLANAR_SETUP 4, 16
+.w16_row:
+    ROW_CONSTANTS
+    PLANAR16 pw_wm1x_w16, pw_xp1_w16, 0, 4
+    add            srcq, strideq
+    inc            r11d
+    cmp            r11d, hd
+    jl .w16_row
+    RET
+
+.w32:
+    PLANAR_SETUP 5, 32
+.w32_row:
+    ROW_CONSTANTS
+    PLANAR16 pw_wm1x_w32, pw_xp1_w32, 0,  5
+    PLANAR16 pw_wm1x_w32, pw_xp1_w32, 16, 5
+    add            srcq, strideq
+    inc            r11d
+    cmp            r11d, hd
+    jl .w32_row
+    RET
+
+.w64:
+    PLANAR_SETUP 6, 64
+.w64_row:
+    ROW_CONSTANTS
+    PLANAR16 pw_wm1x_w64, pw_xp1_w64, 0,  6
+    PLANAR16 pw_wm1x_w64, pw_xp1_w64, 16, 6
+    PLANAR16 pw_wm1x_w64, pw_xp1_w64, 32, 6
+    PLANAR16 pw_wm1x_w64, pw_xp1_w64, 48, 6
+    add            srcq, strideq
+    inc            r11d
+    cmp            r11d, hd
+    jl .w64_row
+    RET
+
+%endif
+%endif
-- 
2.53.0

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