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]