This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new a8a7a06196 avcodec/x86/hevc: add SSE2 ref_filter_3tap
a8a7a06196 is described below

commit a8a7a0619694629d21339a950ae5dcd0ed135cf7
Author:     Marcos Ashton Iglesias <[email protected]>
AuthorDate: Tue Aug 25 21:51:49 2026 +0100
Commit:     michaelni <[email protected]>
CommitDate: Wed Sep 9 14:58:33 2026 +0000

    avcodec/x86/hevc: add SSE2 ref_filter_3tap
    
    Smooths the intra reference samples for 8 bit, the second of the HEVC
    intra prediction groups x86 was missing; aarch64 NEON already has it.
    
    out[i] = (in[i-1] + 2*in[i] + in[i+1] + 2) >> 2 is exact in bytes.
    pavgb rounds up, so clearing the low bit of in[i-1]+in[i+1] before the
    second average gives the wanted result for every triple. The last
    sample is copied rather than filtered and is selected into the final
    store, since the destination has no room past it. The corner, which
    both arrays share, goes out as a dword because x86-32 has no byte
    register to spare here.
    
    SSE2 rather than SSSE3: nothing can be assumed aligned, so three
    unaligned loads beat a load plus two palignr.
    
    checkasm --bench on a Core Ultra 7 155H:
    hevc_ref_filter_3tap_8x8_8_c:         75.5
    hevc_ref_filter_3tap_8x8_8_sse2:       7.1 (10.49x)
    hevc_ref_filter_3tap_16x16_8_c:      187.7
    hevc_ref_filter_3tap_16x16_8_sse2:    12.0 (15.57x)
    hevc_ref_filter_3tap_32x32_8_c:      348.0
    hevc_ref_filter_3tap_32x32_8_sse2:    22.2 (15.37x)
    
    Part of #23022.
---
 libavcodec/x86/hevc/pred.asm    | 71 +++++++++++++++++++++++++++++++++++++++++
 libavcodec/x86/hevc/pred_init.c | 16 ++++++++++
 2 files changed, 87 insertions(+)

diff --git a/libavcodec/x86/hevc/pred.asm b/libavcodec/x86/hevc/pred.asm
index 2e07c5f759..3d1feee89f 100644
--- a/libavcodec/x86/hevc/pred.asm
+++ b/libavcodec/x86/hevc/pred.asm
@@ -43,6 +43,7 @@ pw_planar4_vy1: dw 1, 1, 1, 1, 0, 0, 0, 0   ; rows 2-3
 pw_planar4_yb0: dw 1, 1, 1, 1, 2, 2, 2, 2   ; y + 1, rows 0-1
 pw_planar4_yb1: dw 3, 3, 3, 3, 4, 4, 4, 4   ; rows 2-3
 
+cextern pb_1
 cextern pw_4
 cextern pw_8
 cextern pw_16
@@ -199,3 +200,73 @@ PRED_PLANAR4
 PRED_PLANAR  8, 1
 PRED_PLANAR 16, 2
 PRED_PLANAR 32, 3
+
+;-----------------------------------------------------------------------------
+; void ff_hevc_ref_filter_3tap_<size>x<size>_8(uint8_t *filtered_left,
+;                                              uint8_t *filtered_top,
+;                                              const uint8_t *left,
+;                                              const uint8_t *top, int size)
+;-----------------------------------------------------------------------------
+
+; out[i] = (in[i-1] + 2*in[i] + in[i+1] + 2) >> 2, exact in bytes: pavgb rounds
+; up, so clearing the low bit of in[i-1]+in[i+1] before the second average
+; gives the wanted result for every triple.
+; Nothing can be assumed aligned - plain stack arrays, pointers offset by one -
+; so three unaligned loads beat a load plus two palignr and this stays SSE2.
+; The last block reads in[2*size]; the input arrays carry 16 samples of slack
+; for that, and its result is discarded.
+; %1 = dst, %2 = src, %3 = offset. Leaves in[i] in m1 for the caller.
+%macro FILTER_3TAP_16 3
+    movu            m0, [%2 + (%3) - 1]
+    movu            m1, [%2 + (%3) + 1]
+    pxor            m2, m0, m1
+    pavgb           m0, m1
+    pand            m2, m3
+    psubb           m0, m2                  ; (in[i-1] + in[i+1]) >> 1
+    movu            m1, [%2 + (%3)]
+    pavgb           m0, m1
+%endmacro
+
+; %1 = dst, %2 = src, %3 = 2 * size
+%macro FILTER_3TAP_ARRAY 3
+%assign %%i 0
+%rep (%3) / 16
+    FILTER_3TAP_16  %1, %2, %%i
+%if %%i == (%3) - 16
+    pxor            m1, m0                  ; last sample is copied, not
+    pand            m1, m4                  ; filtered; select it out of m1 as
+    pxor            m0, m1                  ; the dst has no room past it
+%endif
+    movu  [%1 + %%i], m0
+%assign %%i %%i + 16
+%endrep
+%endmacro
+
+; %1 = size
+%macro REF_FILTER_3TAP 1
+%assign %%n 2 * %1
+cglobal hevc_ref_filter_3tap_%1x%1_8, 4, 6, 5, fleft, ftop, left, top
+    ; The corner is shared by both arrays. Store it as a dword: x86-32 has no
+    ; byte register to spare here, and the 3 bytes past it are filtered below.
+    movzx          r4d, byte [leftq - 1]
+    movzx          r5d, byte [leftq]
+    lea             r5, [r5 + r4*2 + 2]
+    movzx          r4d, byte [topq]
+    add            r5d, r4d
+    shr            r5d, 2
+    mov  [fleftq - 1], r5d
+    mov   [ftopq - 1], r5d
+
+    mova            m3, [pb_1]
+    pcmpeqb         m4, m4
+    pslldq          m4, 15                  ; selects the copied last sample
+
+    FILTER_3TAP_ARRAY fleftq, leftq, %%n
+    FILTER_3TAP_ARRAY  ftopq,  topq, %%n
+    RET
+%endmacro
+
+INIT_XMM sse2
+REF_FILTER_3TAP  8
+REF_FILTER_3TAP 16
+REF_FILTER_3TAP 32
diff --git a/libavcodec/x86/hevc/pred_init.c b/libavcodec/x86/hevc/pred_init.c
index 980e28b861..65b8190c2a 100644
--- a/libavcodec/x86/hevc/pred_init.c
+++ b/libavcodec/x86/hevc/pred_init.c
@@ -36,11 +36,27 @@ PRED_PLANAR_FUNC(1, ssse3)
 PRED_PLANAR_FUNC(2, ssse3)
 PRED_PLANAR_FUNC(3, ssse3)
 
+#define REF_FILTER_3TAP_FUNC(w, opt)                                          \
+void ff_hevc_ref_filter_3tap_ ## w ## x ## w ## _8_ ## opt(                   \
+                                               uint8_t *filtered_left,        \
+                                               uint8_t *filtered_top,         \
+                                               const uint8_t *left,           \
+                                               const uint8_t *top, int size);
+
+REF_FILTER_3TAP_FUNC( 8, sse2)
+REF_FILTER_3TAP_FUNC(16, sse2)
+REF_FILTER_3TAP_FUNC(32, sse2)
+
 av_cold void ff_hevc_pred_init_x86(HEVCPredContext *hpc, int bit_depth)
 {
     int cpu_flags = av_get_cpu_flags();
 
     if (bit_depth == 8) {
+        if (EXTERNAL_SSE2(cpu_flags)) {
+            hpc->ref_filter_3tap[0] = ff_hevc_ref_filter_3tap_8x8_8_sse2;
+            hpc->ref_filter_3tap[1] = ff_hevc_ref_filter_3tap_16x16_8_sse2;
+            hpc->ref_filter_3tap[2] = ff_hevc_ref_filter_3tap_32x32_8_sse2;
+        }
         if (EXTERNAL_SSSE3(cpu_flags)) {
             hpc->pred_planar[0] = ff_hevc_pred_planar_0_8_ssse3;
             hpc->pred_planar[1] = ff_hevc_pred_planar_1_8_ssse3;

-- 
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]

Reply via email to