Merge branch 'master' into 'master'

core: Add RISC-V V optimized sconv pa_sconv_s16le_from_float32ne

See merge request pulseaudio/pulseaudio!833
This commit is contained in:
sun yuechi 2025-10-14 14:41:42 +00:00
commit d64cfc70fd
8 changed files with 210 additions and 0 deletions

View file

@ -293,6 +293,7 @@ endif
check_usable_headers = [
'cpuid.h',
'sys/auxv.h',
]
foreach h : check_usable_headers
@ -594,6 +595,18 @@ if host_machine.cpu_family() == 'arm'
endif
# NEON checks are automatically done by the unstable-simd module
if host_machine.cpu_family() == 'riscv64'
if cc.compiles('''
int main() {
__asm__ __volatile__ (
".option arch, +v\nvsetivli zero, 0, e8, m1, ta, ma"
);
}
''', name : 'rvv code')
cdata.set('HAVE_RVV', 1)
endif
endif
# Dependencies common to client, daemon and modules
if get_option('ipv6')

57
src/pulsecore/cpu-riscv.c Normal file
View file

@ -0,0 +1,57 @@
/***
This file is part of PulseAudio.
Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS).
PulseAudio 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.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdint.h>
#if HAVE_SYS_AUXV_H
#include <sys/auxv.h>
#define HWCAP_RV(letter) (1ul << ((letter) - 'A'))
#endif
#include <pulsecore/log.h>
#include "cpu-riscv.h"
void pa_cpu_get_riscv_flags(pa_cpu_riscv_flag_t *flags) {
#if HAVE_SYS_AUXV_H
const unsigned long hwcap = getauxval(AT_HWCAP);
if (hwcap & HWCAP_RV('V'))
*flags |= PA_CPU_RISCV_V;
pa_log_info("CPU flags: %s", (*flags & PA_CPU_RISCV_V) ? "V" : "");
#endif
}
bool pa_cpu_init_riscv(pa_cpu_riscv_flag_t *flags) {
pa_cpu_get_riscv_flags(flags);
#if HAVE_RVV
if (*flags & PA_CPU_RISCV_V) {
pa_convert_func_init_rvv(*flags);
}
return true;
#else
return false;
#endif
}

41
src/pulsecore/cpu-riscv.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef foocpuriscvhfoo
#define foocpuriscvhfoo
/***
This file is part of PulseAudio.
Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS).
PulseAudio 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.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/
#include <stdint.h>
#include <pulsecore/macro.h>
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
typedef enum pa_cpu_riscv_flag {
PA_CPU_RISCV_V = (1 << 0),
} pa_cpu_riscv_flag_t;
void pa_cpu_get_riscv_flags(pa_cpu_riscv_flag_t *flags);
bool pa_cpu_init_riscv (pa_cpu_riscv_flag_t *flags);
#ifdef HAVE_RVV
void pa_convert_func_init_rvv(pa_cpu_riscv_flag_t flags);
#endif
#endif /* foocpuxriscvhfoo */

View file

@ -30,6 +30,8 @@ void pa_cpu_init(pa_cpu_info *cpu_info) {
cpu_info->cpu_type = PA_CPU_X86;
else if (pa_cpu_init_arm(&cpu_info->flags.arm))
cpu_info->cpu_type = PA_CPU_ARM;
else if (pa_cpu_init_riscv(&cpu_info->flags.riscv))
cpu_info->cpu_type = PA_CPU_RISCV;
pa_cpu_init_orc(*cpu_info);
}

View file

@ -22,11 +22,13 @@
#include <pulsecore/cpu-x86.h>
#include <pulsecore/cpu-arm.h>
#include <pulsecore/cpu-riscv.h>
typedef enum {
PA_CPU_UNDEFINED = 0,
PA_CPU_X86,
PA_CPU_ARM,
PA_CPU_RISCV,
} pa_cpu_type_t;
typedef struct pa_cpu_info pa_cpu_info;
@ -37,6 +39,7 @@ struct pa_cpu_info {
union {
pa_cpu_x86_flag_t x86;
pa_cpu_arm_flag_t arm;
pa_cpu_riscv_flag_t riscv;
} flags;
bool force_generic_code;
};

View file

@ -13,6 +13,7 @@ libpulsecore_sources = [
'cpu-arm.c',
'cpu-orc.c',
'cpu-x86.c',
'cpu-riscv.c',
'device-port.c',
'database.c',
'ffmpeg/resample2.c',
@ -40,6 +41,7 @@ libpulsecore_sources = [
'sconv-s16be.c',
'sconv-s16le.c',
'sconv.c',
'sconv_rvv.c',
'shared.c',
'sink.c',
'sink-input.c',

58
src/pulsecore/sconv_rvv.c Normal file
View file

@ -0,0 +1,58 @@
/***
This file is part of PulseAudio.
Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS).
PulseAudio 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.
PulseAudio 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
General Public License for more details.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulsecore/macro.h>
#include <pulsecore/endianmacros.h>
#include "cpu-riscv.h"
#include "sconv.h"
#if HAVE_RVV
static void pa_sconv_s16le_from_f32ne_rvv(unsigned n, const float *src, int16_t *dst) {
__asm__ __volatile__ (
".option arch, +v \n\t"
"li t0, 1191182336 \n\t"
"fmv.w.x fa5, t0 \n\t"
"1: \n\t"
"vsetvli t0, a0, e32, m8, ta, ma \n\t"
"vle32.v v8, (a1) \n\t"
"sub a0, a0, t0 \n\t"
"vfmul.vf v8, v8, fa5 \n\t"
"vsetvli zero, zero, e16, m4, ta, ma \n\t"
"vfncvt.x.f.w v8, v8 \n\t"
"slli t0, t0, 1 \n\t"
"vse16.v v8, (a2) \n\t"
"add a1, a1, t0 \n\t"
"add a1, a1, t0 \n\t"
"add a2, a2, t0 \n\t"
"bnez a0, 1b \n\t"
:
:
: "cc", "memory"
);
}
void pa_convert_func_init_rvv(pa_cpu_riscv_flag_t flags) {
pa_log_info("Initialising RVV optimized conversions.");
pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_rvv);
}
#endif

View file

@ -23,6 +23,7 @@
#include <pulsecore/cpu-arm.h>
#include <pulsecore/cpu-x86.h>
#include <pulsecore/cpu-riscv.h>
#include <pulsecore/random.h>
#include <pulsecore/macro.h>
#include <pulsecore/sconv.h>
@ -190,6 +191,35 @@ START_TEST (sconv_sse_test) {
END_TEST
#endif /* (defined (__i386__) || defined (__amd64__)) && defined (HAVE_SSE) */
#if HAVE_RVV
START_TEST (sconv_rvv_test) {
pa_cpu_riscv_flag_t flags = 0;
pa_convert_func_t orig_func, rvv_func;
pa_cpu_get_riscv_flags(&flags);
if (!(flags & PA_CPU_RISCV_V)) {
pa_log_info("RVV not supported. Skipping");
return;
}
orig_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
pa_convert_func_init_rvv(PA_CPU_RISCV_V);
rvv_func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
pa_log_debug("Checking RVV sconv (float -> s16)");
run_conv_test_float_to_s16(rvv_func, orig_func, 0, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 1, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 2, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 3, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 4, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 5, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 6, true, false);
run_conv_test_float_to_s16(rvv_func, orig_func, 7, true, true);
}
END_TEST
#endif /* (defined () */
#if defined (__arm__) && defined (__linux__) && defined (HAVE_NEON)
START_TEST (sconv_neon_test) {
pa_cpu_arm_flag_t flags = 0;
@ -250,6 +280,10 @@ int main(int argc, char *argv[]) {
#endif
#if defined (__arm__) && defined (__linux__) && defined (HAVE_NEON)
tcase_add_test(tc, sconv_neon_test);
#endif
#if HAVE_RVV
tcase_set_timeout(tc, 0);
tcase_add_test(tc, sconv_rvv_test);
#endif
suite_add_tcase(s, tc);