diff --git a/libavutil/cpu.c b/libavutil/cpu.c index 6548cc3042..52f6b9a3bf 100644 --- a/libavutil/cpu.c +++ b/libavutil/cpu.c @@ -51,6 +51,8 @@ static atomic_int cpu_flags = ATOMIC_VAR_INIT(-1); static int get_cpu_flags(void) { + if (ARCH_MIPS) + return ff_get_cpu_flags_mips(); if (ARCH_AARCH64) return ff_get_cpu_flags_aarch64(); if (ARCH_ARM) @@ -169,6 +171,9 @@ int av_parse_cpu_flags(const char *s) { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, +#elif ARCH_MIPS + { "mmi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMI }, .unit = "flags" }, + { "msa", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MSA }, .unit = "flags" }, #endif { NULL }, }; @@ -250,6 +255,9 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, +#elif ARCH_MIPS + { "mmi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMI }, .unit = "flags" }, + { "msa", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MSA }, .unit = "flags" }, #endif { NULL }, }; @@ -308,6 +316,8 @@ int av_cpu_count(void) size_t av_cpu_max_align(void) { + if (ARCH_MIPS) + return ff_get_cpu_max_align_mips(); if (ARCH_AARCH64) return ff_get_cpu_max_align_aarch64(); if (ARCH_ARM) diff --git a/libavutil/cpu.h b/libavutil/cpu.h index 8bb9eb606b..83099dd969 100644 --- a/libavutil/cpu.h +++ b/libavutil/cpu.h @@ -71,6 +71,9 @@ #define AV_CPU_FLAG_VFP_VM (1 << 7) ///< VFPv2 vector mode, deprecated in ARMv7-A and unavailable in various CPUs implementations #define AV_CPU_FLAG_SETEND (1 <<16) +#define AV_CPU_FLAG_MMI (1 << 0) +#define AV_CPU_FLAG_MSA (1 << 1) + /** * Return the flags which specify extensions supported by the CPU. * The returned value is affected by av_force_cpu_flags() if that was used diff --git a/libavutil/cpu_internal.h b/libavutil/cpu_internal.h index 37122d1c5f..889764320b 100644 --- a/libavutil/cpu_internal.h +++ b/libavutil/cpu_internal.h @@ -41,11 +41,13 @@ #define CPUEXT_FAST(flags, cpuext) CPUEXT_SUFFIX_FAST(flags, , cpuext) #define CPUEXT_SLOW(flags, cpuext) CPUEXT_SUFFIX_SLOW(flags, , cpuext) +int ff_get_cpu_flags_mips(void); int ff_get_cpu_flags_aarch64(void); int ff_get_cpu_flags_arm(void); int ff_get_cpu_flags_ppc(void); int ff_get_cpu_flags_x86(void); +size_t ff_get_cpu_max_align_mips(void); size_t ff_get_cpu_max_align_aarch64(void); size_t ff_get_cpu_max_align_arm(void); size_t ff_get_cpu_max_align_ppc(void); diff --git a/libavutil/mips/Makefile b/libavutil/mips/Makefile index dbfa5aa341..5f8c9b64e9 100644 --- a/libavutil/mips/Makefile +++ b/libavutil/mips/Makefile @@ -1 +1 @@ -OBJS += mips/float_dsp_mips.o +OBJS += mips/float_dsp_mips.o mips/cpu.o diff --git a/libavutil/mips/cpu.c b/libavutil/mips/cpu.c new file mode 100644 index 0000000000..59619d54de --- /dev/null +++ b/libavutil/mips/cpu.c @@ -0,0 +1,134 @@ +/* + * 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/cpu.h" +#include "libavutil/cpu_internal.h" +#include "config.h" +#if defined __linux__ || defined __ANDROID__ +#include +#include +#include +#include +#include "asmdefs.h" +#include "libavutil/avstring.h" +#endif + +#if defined __linux__ || defined __ANDROID__ + +#define HWCAP_LOONGSON_CPUCFG (1 << 14) + +static int cpucfg_available(void) +{ + return getauxval(AT_HWCAP) & HWCAP_LOONGSON_CPUCFG; +} + +/* Most toolchains have no CPUCFG support yet */ +static uint32_t read_cpucfg(uint32_t reg) +{ + uint32_t __res; + + __asm__ __volatile__( + "parse_r __res,%0\n\t" + "parse_r reg,%1\n\t" + ".insn \n\t" + ".word (0xc8080118 | (reg << 21) | (__res << 11))\n\t" + :"=r"(__res) + :"r"(reg) + : + ); + return __res; +} + +#define LOONGSON_CFG1 0x1 + +#define LOONGSON_CFG1_MMI (1 << 4) +#define LOONGSON_CFG1_MSA1 (1 << 5) + +static int cpu_flags_cpucfg(void) +{ + int flags = 0; + uint32_t cfg1 = read_cpucfg(LOONGSON_CFG1); + + if (cfg1 & LOONGSON_CFG1_MMI) + flags |= AV_CPU_FLAG_MMI; + + if (cfg1 & LOONGSON_CFG1_MSA1) + flags |= AV_CPU_FLAG_MSA; + + return flags; +} + +static int cpu_flags_cpuinfo(void) +{ + FILE *f = fopen("/proc/cpuinfo", "r"); + char buf[200]; + int flags = 0; + + if (!f) + return -1; + + while (fgets(buf, sizeof(buf), f)) { + /* Legacy kernel may not export MMI in ASEs implemented */ + if (av_strstart(buf, "cpu model", NULL)) { + if (strstr(buf, "Loongson-3 ")) + flags |= AV_CPU_FLAG_MMI; + } + + if (av_strstart(buf, "ASEs implemented", NULL)) { + if (strstr(buf, " loongson-mmi")) + flags |= AV_CPU_FLAG_MMI; + if (strstr(buf, " msa")) + flags |= AV_CPU_FLAG_MSA; + + break; + } + } + fclose(f); + return flags; +} +#endif + +int ff_get_cpu_flags_mips(void) +{ +#if defined __linux__ || defined __ANDROID__ + if (cpucfg_available()) + return cpu_flags_cpucfg(); + else + return cpu_flags_cpuinfo(); +#else + /* Assume no SIMD ASE supported */ + return 0; +#endif +} + +size_t ff_get_cpu_max_align_mips(void) +{ + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_MSA) + return 16; + + /* + * MMI itself is 64-bit but quad word load & store + * needs 128-bit align. + */ + if (flags & AV_CPU_FLAG_MMI) + return 16; + + return 8; +} diff --git a/libavutil/mips/cpu.h b/libavutil/mips/cpu.h new file mode 100644 index 0000000000..615dc49759 --- /dev/null +++ b/libavutil/mips/cpu.h @@ -0,0 +1,28 @@ +/* + * 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 AVUTIL_MIPS_CPU_H +#define AVUTIL_MIPS_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_mmi(flags) CPUEXT(flags, MMI) +#define have_msa(flags) CPUEXT(flags, MSA) + +#endif /* AVUTIL_MIPS_CPU_H */ diff --git a/libavutil/tests/cpu.c b/libavutil/tests/cpu.c index ce45b715a0..c853371fb3 100644 --- a/libavutil/tests/cpu.c +++ b/libavutil/tests/cpu.c @@ -49,6 +49,9 @@ static const struct { { AV_CPU_FLAG_SETEND, "setend" }, #elif ARCH_PPC { AV_CPU_FLAG_ALTIVEC, "altivec" }, +#elif ARCH_MIPS + { AV_CPU_FLAG_MMI, "mmi" }, + { AV_CPU_FLAG_MSA, "msa" }, #elif ARCH_X86 { AV_CPU_FLAG_MMX, "mmx" }, { AV_CPU_FLAG_MMXEXT, "mmxext" }, diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index 899f68bb32..b3ac76c325 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -213,6 +213,9 @@ static const struct { { "ALTIVEC", "altivec", AV_CPU_FLAG_ALTIVEC }, { "VSX", "vsx", AV_CPU_FLAG_VSX }, { "POWER8", "power8", AV_CPU_FLAG_POWER8 }, +#elif ARCH_MIPS + { "MMI", "mmi", AV_CPU_FLAG_MMI }, + { "MSA", "msa", AV_CPU_FLAG_MSA }, #elif ARCH_X86 { "MMX", "mmx", AV_CPU_FLAG_MMX|AV_CPU_FLAG_CMOV }, { "MMXEXT", "mmxext", AV_CPU_FLAG_MMXEXT },