summaryrefslogtreecommitdiff
path: root/libavutil/arm
diff options
context:
space:
mode:
authorMans Rullgard <mans@mansr.com>2012-12-05 02:11:22 +0000
committerMans Rullgard <mans@mansr.com>2012-12-07 16:54:04 +0000
commitb57c1da81e4f9d46af6ad9f69e6e2255d5b8aaff (patch)
treef5f6804392c42566ca2210de5b8d08355177f0dc /libavutil/arm
parentb326755989b346d0d935e0628e8865f9b2951c30 (diff)
arm: detect cpu features at runtime on Linux
This allows compiling optimised functions for features not enabled in the core build and selecting these at runtime if the system has the necessary support. Signed-off-by: Mans Rullgard <mans@mansr.com>
Diffstat (limited to 'libavutil/arm')
-rw-r--r--libavutil/arm/cpu.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/libavutil/arm/cpu.c b/libavutil/arm/cpu.c
index 7058aeb1f1..041afc985a 100644
--- a/libavutil/arm/cpu.c
+++ b/libavutil/arm/cpu.c
@@ -19,6 +19,87 @@
#include "libavutil/cpu.h"
#include "config.h"
+#define CORE_FLAG(f) \
+ (AV_CPU_FLAG_ ## f * (HAVE_ ## f ## _EXTERNAL || HAVE_ ## f ## _INLINE))
+
+#define CORE_CPU_FLAGS \
+ (CORE_FLAG(ARMV5TE) | \
+ CORE_FLAG(ARMV6) | \
+ CORE_FLAG(ARMV6T2) | \
+ CORE_FLAG(VFP) | \
+ CORE_FLAG(VFPV3) | \
+ CORE_FLAG(NEON))
+
+#if defined __linux__ || defined __ANDROID__
+
+#include <stdint.h>
+#include <stdio.h>
+
+#define AT_HWCAP 16
+
+/* Relevant HWCAP values from kernel headers */
+#define HWCAP_VFP (1 << 6)
+#define HWCAP_EDSP (1 << 7)
+#define HWCAP_THUMBEE (1 << 11)
+#define HWCAP_NEON (1 << 12)
+#define HWCAP_VFPv3 (1 << 13)
+#define HWCAP_TLS (1 << 15)
+
+static int get_hwcap(uint32_t *hwcap)
+{
+ struct { uint32_t a_type; uint32_t a_val; } auxv;
+ FILE *f = fopen("/proc/self/auxv", "r");
+ int err = -1;
+
+ if (!f)
+ return -1;
+
+ while (fread(&auxv, sizeof(auxv), 1, f) > 0) {
+ if (auxv.a_type == AT_HWCAP) {
+ *hwcap = auxv.a_val;
+ err = 0;
+ break;
+ }
+ }
+
+ fclose(f);
+ return err;
+}
+
+int ff_get_cpu_flags_arm(void)
+{
+ int flags = CORE_CPU_FLAGS;
+ uint32_t hwcap;
+
+ if (get_hwcap(&hwcap) < 0)
+ return flags;
+
+#define check_cap(cap, flag) do { \
+ if (hwcap & HWCAP_ ## cap) \
+ flags |= AV_CPU_FLAG_ ## flag; \
+ } while (0)
+
+ /* No flags explicitly indicate v6 or v6T2 so check others which
+ imply support. */
+ check_cap(EDSP, ARMV5TE);
+ check_cap(TLS, ARMV6);
+ check_cap(THUMBEE, ARMV6T2);
+ check_cap(VFP, VFP);
+ check_cap(VFPv3, VFPV3);
+ check_cap(NEON, NEON);
+
+ /* The v6 checks above are not reliable so let higher flags
+ trickle down. */
+ if (flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON))
+ flags |= AV_CPU_FLAG_ARMV6T2;
+ if (flags & AV_CPU_FLAG_ARMV6T2)
+ flags |= AV_CPU_FLAG_ARMV6;
+
+ return flags;
+}
+
+#else
+
int ff_get_cpu_flags_arm(void)
{
return AV_CPU_FLAG_ARMV5TE * HAVE_ARMV5TE |
@@ -28,3 +109,5 @@ int ff_get_cpu_flags_arm(void)
AV_CPU_FLAG_VFPV3 * HAVE_VFPV3 |
AV_CPU_FLAG_NEON * HAVE_NEON;
}
+
+#endif