[FFmpeg-cvslog] arm: detect cpu features at runtime on Linux

Mans Rullgard git at videolan.org
Sat Dec 8 15:07:09 CET 2012


ffmpeg | branch: master | Mans Rullgard <mans at mansr.com> | Wed Dec  5 02:11:22 2012 +0000| [b57c1da81e4f9d46af6ad9f69e6e2255d5b8aaff] | committer: Mans Rullgard

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 at mansr.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=b57c1da81e4f9d46af6ad9f69e6e2255d5b8aaff
---

 configure           |    4 ++-
 libavutil/arm/cpu.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index 62f3f0b..bf809c6 100755
--- a/configure
+++ b/configure
@@ -3161,7 +3161,9 @@ EOF
     enabled vfp     && check_insn vfp     'fadds s0, s0, s0'
     enabled vfpv3   && check_insn vfpv3   'vmov.f32 s0, #1.0'
 
-    map 'enabled_any ${v}_external ${v}_inline || disable $v' $ARCH_EXT_LIST_ARM
+    [ $target_os = linux ] ||
+        map 'enabled_any ${v}_external ${v}_inline || disable $v' \
+            $ARCH_EXT_LIST_ARM
 
     check_inline_asm asm_mod_q '"add r0, %Q0, %R0" :: "r"((long long)0)'
     check_inline_asm asm_mod_y '"vmul.i32 d0, d0, %y0" :: "x"(0)'
diff --git a/libavutil/arm/cpu.c b/libavutil/arm/cpu.c
index 7058aeb..041afc9 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



More information about the ffmpeg-cvslog mailing list