1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

avcodec/riscv: add vector FDCT implementation

This RVV FDCT is ported from the AArch64 NEON implementation in
libavcodec/aarch64/fdctdsp_neon.S, which is based on libjpeg-turbo.
The original license notice is retained in the assembly file.

Requires RVV 1.0 with 64-bit element support (Zve64x) and VLEN >= 128.
Achieves approximately 3.29x speedup on SG2044 (VLEN=128).

Add FF_DCT_RVV to the public API, bump minor version, and add
Doxygen documentation.

Also:
- Fix include guard in riscv/fdct.h to match file path.
- Use AV_CPU_FLAG_RVV_I64 in automatic dispatch to avoid illegal
  instruction on Zve32x-only CPUs.

Signed-off-by: yuanjia <yuan.jia@sanechips.com.cn>
This commit is contained in:
yuanjia
2026-09-09 16:28:47 +08:00
committed by michaelni
parent 5b614efc7e
commit c2bb5aa8d8
11 changed files with 450 additions and 2 deletions

View File

@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23.
API changes, most recent first:
2026-09-09 - xxxxxxxxxx - lavc 63.12.100 - avcodec.h
Add FF_DCT_RVV to enable the RISC-V Vector FDCT implementation.
2026-09-xx - xxxxxxxxxx - lavu 61.7.100 - samplefmt.h
Add AV_SAMPLE_FMT_DSD.

View File

@@ -1536,6 +1536,10 @@ typedef struct AVCodecContext {
#define FF_DCT_ALTIVEC 5
#define FF_DCT_FAAN 6
#define FF_DCT_NEON 7
/**
* Select a RISC-V Vector implementation of the forward DCT when available.
*/
#define FF_DCT_RVV 8
/**
* IDCT algorithm, see FF_IDCT_* below.

View File

@@ -48,5 +48,7 @@ av_cold void ff_fdctdsp_init(FDCTDSPContext *c, AVCodecContext *avctx)
ff_fdctdsp_init_ppc(c, avctx, high_bit_depth);
#elif ARCH_X86
ff_fdctdsp_init_x86(c, avctx, high_bit_depth);
#elif ARCH_RISCV
ff_fdctdsp_init_riscv(c, avctx, high_bit_depth);
#endif
}

View File

@@ -38,6 +38,8 @@ void ff_fdctdsp_init_ppc(FDCTDSPContext *c, struct AVCodecContext *avctx,
unsigned high_bit_depth);
void ff_fdctdsp_init_x86(FDCTDSPContext *c, struct AVCodecContext *avctx,
unsigned high_bit_depth);
void ff_fdctdsp_init_riscv(FDCTDSPContext *c, struct AVCodecContext *avctx,
unsigned high_bit_depth);
void ff_fdct_ifast(int16_t *data);
void ff_fdct_ifast248(int16_t *data);

View File

@@ -159,6 +159,7 @@ static const AVOption avcodec_options[] = {
{"altivec", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_ALTIVEC }, INT_MIN, INT_MAX, V|E, .unit = "dct"},
{"faan", "floating point AAN DCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FAAN }, INT_MIN, INT_MAX, V|E, .unit = "dct"},
{"neon", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_NEON }, INT_MIN, INT_MAX, V|E, .unit = "dct"},
{ "rvv", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_DCT_RVV }, INT_MIN, INT_MAX, V|E, .unit = "dct" },
{"lumi_mask", "compresses bright areas stronger than medium ones", OFFSET(lumi_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E},
{"tcplx_mask", "temporal complexity masking", OFFSET(temporal_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E},
{"scplx_mask", "spatial complexity masking", OFFSET(spatial_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E},

View File

@@ -6,6 +6,8 @@ OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_init.o
RV-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvb.o
RVV-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvv.o
RVVB-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvvb.o
OBJS-$(CONFIG_FDCTDSP) += riscv/fdctdsp_init.o
RVV-OBJS-$(CONFIG_FDCTDSP) += riscv/fdctdsp_rvv.o
OBJS-$(CONFIG_ALAC_DECODER) += riscv/alacdsp_init.o
RVV-OBJS-$(CONFIG_ALAC_DECODER) += riscv/alacdsp_rvv.o
OBJS-$(CONFIG_AUDIODSP) += riscv/audiodsp_init.o

26
libavcodec/riscv/fdct.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* 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
*/
#ifndef AVCODEC_RISCV_FDCT_H
#define AVCODEC_RISCV_FDCT_H
#include <stdint.h>
void ff_fdct_rvv(int16_t *block);
#endif /* AVCODEC_RISCV_FDCT_H */

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2026 Jia Yuan <yuan.jia@sanechips.com.cn>
*
* 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/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/riscv/cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/fdctdsp.h"
#include "fdct.h"
av_cold void ff_fdctdsp_init_riscv(FDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
#if HAVE_RVV
int cpu_flags = av_get_cpu_flags();
if (!(cpu_flags & AV_CPU_FLAG_RVV_I64) || !ff_rv_vlen_least(128)) {
return;
}
const int dct_algo = avctx->dct_algo;
if (!high_bit_depth) {
if (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_RVV) {
c->fdct = ff_fdct_rvv;
}
}
#endif
}

View File

@@ -0,0 +1,279 @@
/*
* Copyright (c) 2026 Jia Yuan <yuan.jia@sanechips.com.cn>
*
* 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
*/
/*
* This file is derived from libavcodec/aarch64/fdctdsp_neon.S,
* which is itself based on libjpeg-turbo. The original license
* notice is preserved below.
*
* Armv8 Neon optimizations for libjpeg-turbo
*
* Copyright (C) 2009-2011, Nokia Corporation and/or its subsidiary(-ies).
* All Rights Reserved.
* Author: Siarhei Siamashka <siarhei.siamashka@nokia.com>
* Copyright (C) 2013-2014, Linaro Limited. All Rights Reserved.
* Author: Ragesh Radhakrishnan <ragesh.r@linaro.org>
* Copyright (C) 2014-2016, 2020, D. R. Commander. All Rights Reserved.
* Copyright (C) 2015-2016, 2018, Matthieu Darbois. All Rights Reserved.
* Copyright (C) 2016, Siarhei Siamashka. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "libavutil/riscv/asm.S"
#include "rvv.S"
/* Constants for FDCT */
#define CONST_BITS 13
#ifndef EIGHT_BIT_SAMPLES
# define PASS1_BITS 1
#else
# define PASS1_BITS 2
#endif
#define DESCALE_P1 (CONST_BITS - PASS1_BITS) /* 12 or 11 */
#define DESCALE_P2 (CONST_BITS + PASS1_BITS) /* 14 or 15 */
/* FIX(x) = (int)( (x) * (1 << CONST_BITS) + 0.5 ) */
#define F_0_298 2446
#define F_0_390 3196
#define F_0_541 4433
#define F_0_765 6270
#define F_0_899 7373
#define F_1_175 9633
#define F_1_501 12299
#define F_1_847 15137
#define F_1_961 16069
#define F_2_053 16819
#define F_2_562 20995
#define F_3_072 25172
/* ------------------------------------------------------- */
/* One-dimensional FDCT (8 elements in, 8 elements out) */
/* pass: 0 = first pass (shift DESCALE_P1, shl out0/out4)*/
/* 1 = second pass (shift DESCALE_P2, srshr out0/4)*/
/* ------------------------------------------------------- */
.macro fdct_1d pass, r0, r1, r2, r3, r4, r5, r6, r7
/* Input : r0..r7 (int16, m1) */
/* During 32-bit arithmetic we switch to e32, m2 */
/* Output : v16..v23 (int16, m1) */
/* ---- Butterfly sums/differences (16-bit) ---- */
vadd.vv v24, \r0, \r7 /* tmp0 = S0 + S7 */
vsub.vv v31, \r0, \r7 /* tmp7 = S0 - S7 */
vadd.vv v25, \r1, \r6 /* tmp1 = S1 + S6 */
vsub.vv v30, \r1, \r6 /* tmp6 = S1 - S6 */
vadd.vv v26, \r2, \r5 /* tmp2 = S2 + S5 */
vsub.vv v29, \r2, \r5 /* tmp5 = S2 - S5 */
vadd.vv v27, \r3, \r4 /* tmp3 = S3 + S4 */
vsub.vv v28, \r3, \r4 /* tmp4 = S3 - S4 */
/* ---- Even part ---- */
vadd.vv v4, v24, v27 /* tmp10 = tmp0 + tmp3 */
vsub.vv v5, v24, v27 /* tmp13 = tmp0 - tmp3 */
vadd.vv v6, v25, v26 /* tmp11 = tmp1 + tmp2 */
vsub.vv v7, v25, v26 /* tmp12 = tmp1 - tmp2 */
vadd.vv v16, v4, v6 /* out0 = tmp10 + tmp11 */
vsub.vv v20, v4, v6 /* out4 = tmp10 - tmp11 */
vadd.vv v12, v7, v5 /* (tmp12 + tmp13) for z1 */
/* For the first pass: left shift out0 and out4 */
.if \pass == 0
vsll.vi v16, v16, PASS1_BITS
vsll.vi v20, v20, PASS1_BITS
.else
/* Second pass: rounding right shift out0 and out4 */
vsetivli zero, 8, e32, m2, ta, ma
vsext.vf2 v8, v16
vsext.vf2 v10, v20
vsetivli zero, 8, e16, m1, ta, ma
vnclip.wi v16, v8, PASS1_BITS
vnclip.wi v20, v10, PASS1_BITS
.endif
li t2, F_0_541
li t3, F_0_765
li t4, -(F_1_847)
/* z1 = (tmp12+tmp13) * F_0_541 */
vwmul.vx v18, v12, t2
vsetivli zero, 8, e32, m2, ta, ma
vmv.v.v v22, v18 /* copy for out6 */
/* out2 = z1 + tmp13 * F_0_765 */
vsetivli zero, 8, e16, m1, ta, ma
vwmacc.vx v18, t3, v5
/* out6 = z1 + tmp12 * (-F_1_847) */
vwmacc.vx v22, t4, v7
/* Narrow & shift (DESCALE_P1 or DESCALE_P2) */
vsetivli zero, 8, e16, m1, ta, ma
.if \pass == 0
vnclip.wi v18, v18, DESCALE_P1
vnclip.wi v22, v22, DESCALE_P1
.else
vnclip.wi v18, v18, DESCALE_P2
vnclip.wi v22, v22, DESCALE_P2
.endif
/* ---- Odd part ---- */
vadd.vv v2, v28, v31 /* z1 */
vadd.vv v3, v29, v30 /* z2 */
vadd.vv v6, v28, v30 /* z3 */
vadd.vv v7, v29, v31 /* z4 */
/* z5 = (z3 + z4) * F_1_175 */
li t2, F_1_175
vwmul.vx v4, v6, t2 /* z5 = z3 * F_1_175 */
vwmacc.vx v4, t2, v7 /* z5 += z4 * F_1_175 */
/* tmp4 = S4 * F_0_298, tmp5 = S5 * F_2_053,
tmp6 = S6 * F_3_072, tmp7 = S7 * F_1_501 */
li t3, F_0_298
li t4, F_2_053
li t5, F_3_072
li t6, F_1_501
vwmul.vx v8, v28, t3
vwmul.vx v10, v29, t4
vwmul.vx v12, v30, t5
vwmul.vx v14, v31, t6
/* z1..z4 with negative coefficients */
li t1, -(F_0_899)
li t2, -(F_2_562)
li t3, -(F_1_961)
li t4, -(F_0_390)
vwmul.vx v24, v2, t1
vwmul.vx v26, v3, t2
vwmul.vx v28, v6, t3
vwmul.vx v30, v7, t4
vsetivli zero, 8, e32, m2, ta, ma
/* z3 += z5, z4 += z5 */
vadd.vv v28, v28, v4
vadd.vv v30, v30, v4
/* tmp4 += z1 ; tmp5 += z2 ; tmp6 += z3 ; tmp7 += z4 */
vadd.vv v8, v8, v24 /* tmp4 += z1 */
vadd.vv v10, v10, v26 /* tmp5 += z2 */
vadd.vv v12, v12, v28 /* tmp6 += z3 */
vadd.vv v14, v14, v30 /* tmp7 += z4 */
/* tmp4 += z3 ; tmp5 += z4 ; tmp6 += z2 ; tmp7 += z1 */
vadd.vv v8, v8, v28 /* tmp4 += z3 */
vadd.vv v10, v10, v30 /* tmp5 += z4 */
vadd.vv v12, v12, v26 /* tmp6 += z2 */
vadd.vv v14, v14, v24 /* tmp7 += z1 */
/* ---- Restore 16-bit mode ---- */
vsetivli zero, 8, e16, m1, ta, ma
.if \pass == 0
vnclip.wi v23, v8, DESCALE_P1
vnclip.wi v21, v10, DESCALE_P1
vnclip.wi v19, v12, DESCALE_P1
vnclip.wi v17, v14, DESCALE_P1
.else
vnclip.wi v23, v8, DESCALE_P2
vnclip.wi v21, v10, DESCALE_P2
vnclip.wi v19, v12, DESCALE_P2
vnclip.wi v17, v14, DESCALE_P2
.endif
.endm
/* ------------------------------------------------------- */
/* 8x8 FDCT entry point */
/* void ff_fdct_rvv(int16_t *data) */
/* ------------------------------------------------------- */
func ff_fdct_rvv, zve64x
lpad 0
li t1, 0x55
vsetivli zero, 8, e16, m1, ta, ma
vmv.v.x v0, t1
csrwi vxrm, 0
/* Load 8x8 block (rows) */
mv t0, a0
vle16.v v16, (t0)
addi t0, t0, 16
vle16.v v17, (t0)
addi t0, t0, 16
vle16.v v18, (t0)
addi t0, t0, 16
vle16.v v19, (t0)
addi t0, t0, 16
vle16.v v20, (t0)
addi t0, t0, 16
vle16.v v21, (t0)
addi t0, t0, 16
vle16.v v22, (t0)
addi t0, t0, 16
vle16.v v23, (t0)
/* First transpose: rows -> columns */
TRANSPOSE_8x8 16, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23
/* First 1-D FDCT (columns) */
vsetivli zero, 8, e16, m1, ta, ma
fdct_1d 0, v8, v9, v10, v11, v12, v13, v14, v15
/* Transpose again: columns -> rows */
TRANSPOSE_8x8 16, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23
/* Second 1-D FDCT (rows) */
vsetivli zero, 8, e16, m1, ta, ma
fdct_1d 1, v8, v9, v10, v11, v12, v13, v14, v15
/* Store the final 8x8 block back to memory */
mv t0, a0
vse16.v v16, (t0)
addi t0, t0, 16
vse16.v v17, (t0)
addi t0, t0, 16
vse16.v v18, (t0)
addi t0, t0, 16
vse16.v v19, (t0)
addi t0, t0, 16
vse16.v v20, (t0)
addi t0, t0, 16
vse16.v v21, (t0)
addi t0, t0, 16
vse16.v v22, (t0)
addi t0, t0, 16
vse16.v v23, (t0)
ret
endfunc

85
libavcodec/riscv/rvv.S Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2026 Jia Yuan <yuan.jia@sanechips.com.cn>
*
* 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
*/
// v0 must be 0x55 as mask
.macro TRANSPOSE_8x8 es, d0, d1, d2, d3, d4, d5, d6, d7, r0, r1, r2, r3, r4, r5, r6, r7
vslideup.vi \d0, \r1, 1
vslidedown.vi \d1, \r0, 1
vslideup.vi \d2, \r3, 1
vslidedown.vi \d3, \r2, 1
vslideup.vi \d4, \r5, 1
vslidedown.vi \d5, \r4, 1
vslideup.vi \d6, \r7, 1
vslidedown.vi \d7, \r6, 1
vmerge.vvm \d0, \d0, \r0, v0
vmerge.vvm \d1, \r1, \d1, v0
vmerge.vvm \d2, \d2, \r2, v0
vmerge.vvm \d3, \r3, \d3, v0
vmerge.vvm \d4, \d4, \r4, v0
vmerge.vvm \d5, \r5, \d5, v0
vmerge.vvm \d6, \d6, \r6, v0
vmerge.vvm \d7, \r7, \d7, v0
.if \es == 16
vsetivli zero, 4, e32, m1, ta, ma
.elseif \es == 8
vsetivli zero, 4, e16, m1, ta, ma
.endif
vslideup.vi \r0, \d2, 1
vslidedown.vi \r1, \d0, 1
vslideup.vi \r2, \d3, 1
vslidedown.vi \r3, \d1, 1
vslideup.vi \r4, \d6, 1
vslidedown.vi \r5, \d4, 1
vslideup.vi \r6, \d7, 1
vslidedown.vi \r7, \d5, 1
vmerge.vvm \r0, \r0, \d0, v0
vmerge.vvm \r1, \d2, \r1, v0
vmerge.vvm \r2, \r2, \d1, v0
vmerge.vvm \r3, \d3, \r3, v0
vmerge.vvm \r4, \r4, \d4, v0
vmerge.vvm \r5, \d6, \r5, v0
vmerge.vvm \r6, \r6, \d5, v0
vmerge.vvm \r7, \d7, \r7, v0
.if \es == 16
vsetivli zero, 2, e64, m1, ta, ma
.elseif \es == 8
vsetivli zero, 2, e32, m1, ta, ma
.endif
vslideup.vi \d0, \r4, 1
vslidedown.vi \d4, \r0, 1
vslideup.vi \d1, \r6, 1
vslidedown.vi \d5, \r2, 1
vslideup.vi \d2, \r5, 1
vslidedown.vi \d6, \r1, 1
vslideup.vi \d3, \r7, 1
vslidedown.vi \d7, \r3, 1
vmerge.vvm \d0, \d0, \r0, v0
vmerge.vvm \d4, \r4, \d4, v0
vmerge.vvm \d1, \d1, \r2, v0
vmerge.vvm \d5, \r6, \d5, v0
vmerge.vvm \d2, \d2, \r1, v0
vmerge.vvm \d6, \r5, \d6, v0
vmerge.vvm \d3, \d3, \r3, v0
vmerge.vvm \d7, \r7, \d7, v0
.endm

View File

@@ -29,8 +29,8 @@
#include "version_major.h"
#define LIBAVCODEC_VERSION_MINOR 11
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_MINOR 12
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \