PR #23652 opened by kjg0724 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23652 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23652.patch
Implement `ff_lfe_x96_fixed_neon`, an AArch64 NEON fixed-point LFE x96 interpolation filter. Each input sample generates two output samples: ``` a = coeff_a * src[i] + coeff_b * prev b = coeff_b * src[i] + coeff_a * prev ``` where `coeff_a = 2097471` and `coeff_b = 6291137` (approximately 0.25 and 0.75 in 2^23 fixed-point). Two input samples are processed per iteration using SMULL/SMLAL for int32×int32 to int64 widening multiply-accumulate, SQRSHRN #23 for `norm23`, and SQSHL/SSHR #8 for `clip23`. ZIP1 interleaves the paired output values before storing. Benchmarked with `make fate` checkasm on Apple M1: ``` lfe_x96_fixed_c: ~190 cycles lfe_x96_fixed_neon: ~68 cycles (~2.8x) ``` Also adds a checkasm test for `lfe_x96_fixed`. From 9aac704b44058999747c6523caa7395dfa97845e Mon Sep 17 00:00:00 2001 From: Jeongkeun Kim <[email protected]> Date: Tue, 28 Apr 2026 13:51:25 +0900 Subject: [PATCH 1/2] tests/checkasm/llviddsp: fix add_left_pred_int16 buffer compare size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dst0/dst1 are uint16_t* allocated as width * sizeof(uint16_t), but the memcmp at the end of check_add_left_pred_16 only compared `width` bytes — missing the second half of each buffer. Same pattern used correctly in tests/checkasm/huffyuvdsp.c (memcmp with width * sizeof()). While at it, fix missing whitespace around & and || on the same line. Fixes: fbe91487797c ("checkasm/llviddsp : add test for other dsp func") Signed-off-by: Jeongkeun Kim <[email protected]> --- tests/checkasm/llviddsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/checkasm/llviddsp.c b/tests/checkasm/llviddsp.c index a8245b0d94..1094638229 100644 --- a/tests/checkasm/llviddsp.c +++ b/tests/checkasm/llviddsp.c @@ -145,7 +145,7 @@ static void check_add_left_pred_16(LLVidDSPContext *c, unsigned mask, int width, res0 = call_ref(dst0, src0, mask, width, acc); res1 = call_new(dst1, src1, mask, width, acc); - if ((res0 &0xFFFF) != (res1 &0xFFFF)|| memcmp(dst0, dst1, width)) + if ((res0 & 0xFFFF) != (res1 & 0xFFFF) || memcmp(dst0, dst1, width * sizeof(*dst0))) fail(); bench_new(dst1, src1, mask, width, acc); -- 2.52.0 From b777d35ba7fbf87b39add21b90621a1bb13bdadc Mon Sep 17 00:00:00 2001 From: Jeongkeun Kim <[email protected]> Date: Tue, 30 Jun 2026 11:31:05 +0900 Subject: [PATCH 2/2] avcodec/aarch64: add NEON lfe_x96_fixed for DCA DSP Implement ff_lfe_x96_fixed_neon, an AArch64 NEON fixed-point LFE x96 interpolation filter. Each input sample generates two output samples: a = coeff_a * src[i] + coeff_b * prev b = coeff_b * src[i] + coeff_a * prev where coeff_a = 2097471 and coeff_b = 6291137 (approximately 0.25 and 0.75 in 2^23 fixed-point). Two input samples are processed per iteration using SMULL/SMLAL for int32x32 to int64 widening multiply-accumulate, SQRSHRN #23 for norm23, and SQSHL/SSHR #8 for clip23. ZIP1 interleaves the paired output values before storing. Measured on Apple M1: lfe_x96_fixed_c: ~190 cycles lfe_x96_fixed_neon: ~68 cycles (~2.8x) Also adds a checkasm test for lfe_x96_fixed. --- libavcodec/aarch64/dcadsp_init_aarch64.c | 3 +++ libavcodec/aarch64/dcadsp_neon.S | 31 ++++++++++++++++++++++++ tests/checkasm/dcadsp.c | 23 ++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/libavcodec/aarch64/dcadsp_init_aarch64.c b/libavcodec/aarch64/dcadsp_init_aarch64.c index 1fc6ec7a32..acb4194e9d 100644 --- a/libavcodec/aarch64/dcadsp_init_aarch64.c +++ b/libavcodec/aarch64/dcadsp_init_aarch64.c @@ -30,6 +30,8 @@ void ff_lfe_fir0_float_neon(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks); void ff_lfe_fir1_float_neon(float *pcm_samples, const int32_t *lfe_samples, const float *filter_coeff, ptrdiff_t npcmblocks); +void ff_lfe_x96_fixed_neon(int32_t *dst, const int32_t *src, + int32_t *hist, ptrdiff_t len); av_cold void ff_dcadsp_init_aarch64(DCADSPContext *s) { @@ -38,5 +40,6 @@ av_cold void ff_dcadsp_init_aarch64(DCADSPContext *s) if (have_neon(cpu_flags)) { s->lfe_fir_float[0] = ff_lfe_fir0_float_neon; s->lfe_fir_float[1] = ff_lfe_fir1_float_neon; + s->lfe_x96_fixed = ff_lfe_x96_fixed_neon; } } diff --git a/libavcodec/aarch64/dcadsp_neon.S b/libavcodec/aarch64/dcadsp_neon.S index af149767fd..ae7ce7f906 100644 --- a/libavcodec/aarch64/dcadsp_neon.S +++ b/libavcodec/aarch64/dcadsp_neon.S @@ -99,3 +99,34 @@ function ff_lfe_fir1_float_neon, export=1 b.gt .Louter1 ret endfunc + +function ff_lfe_x96_fixed_neon, export=1 + ldr w4, [x2] + mov w9, #0x013F + movk w9, #0x0020, lsl #16 + dup v0.2s, w9 + mov w9, #0xFEC1 + movk w9, #0x005F, lsl #16 + dup v1.2s, w9 +.Lloopx96d: + ld1 {v2.2s}, [x1], #8 + dup v3.2s, w4 + ins v3.s[1], v2.s[0] + smull v4.2d, v2.2s, v0.2s + smlal v4.2d, v3.2s, v1.2s + smull v5.2d, v2.2s, v1.2s + smlal v5.2d, v3.2s, v0.2s + sqrshrn v16.2s, v4.2d, #23 + sqrshrn v17.2s, v5.2d, #23 + sqshl v16.2s, v16.2s, #8 + sshr v16.2s, v16.2s, #8 + sqshl v17.2s, v17.2s, #8 + sshr v17.2s, v17.2s, #8 + zip1 v18.4s, v16.4s, v17.4s + st1 {v18.4s}, [x0], #16 + umov w4, v2.s[1] + subs x3, x3, #2 + b.gt .Lloopx96d + str w4, [x2] + ret +endfunc diff --git a/tests/checkasm/dcadsp.c b/tests/checkasm/dcadsp.c index 809a0a0974..0879977208 100644 --- a/tests/checkasm/dcadsp.c +++ b/tests/checkasm/dcadsp.c @@ -86,6 +86,26 @@ static void test_lfe_fir_fixed(void) bench_new(dst1, lfe + LFE_HISTORY, coeffs, N); } +static void test_lfe_x96_fixed(const DCADSPContext *dca) +{ + LOCAL_ALIGNED_16(int32_t, dst0, [2 * BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, dst1, [2 * BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, src, [BUF_SIZE]); + int32_t hist0, hist1; + + declare_func(void, int32_t *dst, const int32_t *src, int32_t *hist, ptrdiff_t len); + + if (check_func(dca->lfe_x96_fixed, "lfe_x96_fixed")) { + randomize(src, BUF_SIZE); + hist0 = hist1 = (int16_t)rnd(); + call_ref(dst0, src, &hist0, BUF_SIZE); + call_new(dst1, src, &hist1, BUF_SIZE); + if (memcmp(dst0, dst1, 2 * BUF_SIZE * sizeof(int32_t))) + fail(); + bench_new(dst1, src, &hist1, BUF_SIZE); + } +} + void checkasm_check_dcadsp(void) { DCADSPContext dca; @@ -98,4 +118,7 @@ void checkasm_check_dcadsp(void) if (check_func(dca.lfe_fir_fixed, "lfe_fir_fixed")) test_lfe_fir_fixed(); report("lfe_fir_fixed"); + + test_lfe_x96_fixed(&dca); + report("lfe_x96_fixed"); } -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
