diff --git a/configure b/configure index c791679794..5127fa0d8c 100755 --- a/configure +++ b/configure @@ -2209,6 +2209,7 @@ HAVE_LIST_PUB=" HEADERS_LIST=" arpa_inet_h + asm_hwcap_h asm_types_h cdio_paranoia_h cdio_paranoia_paranoia_h @@ -6432,6 +6433,7 @@ check_headers io.h enabled libdrm && check_headers linux/dma-buf.h +check_headers asm/hwcap.h check_headers linux/perf_event.h check_headers libcrystalhd/libcrystalhd_if.h check_headers malloc.h diff --git a/libavutil/aarch64/cpu.c b/libavutil/aarch64/cpu.c index 0c76f5ad15..025bf30828 100644 --- a/libavutil/aarch64/cpu.c +++ b/libavutil/aarch64/cpu.c @@ -20,6 +20,56 @@ #include "libavutil/cpu_internal.h" #include "config.h" +#if (defined(__linux__) || defined(__ANDROID__)) && HAVE_GETAUXVAL && HAVE_ASM_HWCAP_H +#include +#include +#include + +#define get_cpu_feature_reg(reg, val) \ + __asm__("mrs %0, " #reg : "=r" (val)) + +static int detect_flags(void) +{ + int flags = 0; + unsigned long hwcap; + + hwcap = getauxval(AT_HWCAP); + +#if defined(HWCAP_CPUID) + // We can check for DOTPROD and I8MM using HWCAP_ASIMDDP and + // HWCAP2_I8MM too, avoiding to read the CPUID registers (which triggers + // a trap, handled by the kernel). However the HWCAP_* defines for these + // extensions are added much later than HWCAP_CPUID, so the userland + // headers might lack support for them even if the binary later is run + // on hardware that does support it (and where the kernel might support + // HWCAP_CPUID). + // See https://www.kernel.org/doc/html/latest/arm64/cpu-feature-registers.html + if (hwcap & HWCAP_CPUID) { + uint64_t tmp; + + get_cpu_feature_reg(ID_AA64ISAR0_EL1, tmp); + if (((tmp >> 44) & 0xf) == 0x1) + flags |= AV_CPU_FLAG_DOTPROD; + get_cpu_feature_reg(ID_AA64ISAR1_EL1, tmp); + if (((tmp >> 52) & 0xf) == 0x1) + flags |= AV_CPU_FLAG_I8MM; + } +#else + (void)hwcap; +#endif + + return flags; +} + +#else + +static int detect_flags(void) +{ + return 0; +} + +#endif + int ff_get_cpu_flags_aarch64(void) { int flags = AV_CPU_FLAG_ARMV8 * HAVE_ARMV8 | @@ -33,6 +83,8 @@ int ff_get_cpu_flags_aarch64(void) flags |= AV_CPU_FLAG_I8MM; #endif + flags |= detect_flags(); + return flags; }