041afc985ad5e480f00e4e8b67fe3b842b7feb04
[ffmpeg.git] / libavutil / arm / cpu.c
1 /*
2  * This file is part of Libav.
3  *
4  * Libav is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * Libav is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with Libav; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include "libavutil/cpu.h"
20 #include "config.h"
21
22 #define CORE_FLAG(f) \
23     (AV_CPU_FLAG_ ## f * (HAVE_ ## f ## _EXTERNAL || HAVE_ ## f ## _INLINE))
24
25 #define CORE_CPU_FLAGS                          \
26     (CORE_FLAG(ARMV5TE) |                       \
27      CORE_FLAG(ARMV6)   |                       \
28      CORE_FLAG(ARMV6T2) |                       \
29      CORE_FLAG(VFP)     |                       \
30      CORE_FLAG(VFPV3)   |                       \
31      CORE_FLAG(NEON))
32
33 #if defined __linux__ || defined __ANDROID__
34
35 #include <stdint.h>
36 #include <stdio.h>
37
38 #define AT_HWCAP        16
39
40 /* Relevant HWCAP values from kernel headers */
41 #define HWCAP_VFP       (1 << 6)
42 #define HWCAP_EDSP      (1 << 7)
43 #define HWCAP_THUMBEE   (1 << 11)
44 #define HWCAP_NEON      (1 << 12)
45 #define HWCAP_VFPv3     (1 << 13)
46 #define HWCAP_TLS       (1 << 15)
47
48 static int get_hwcap(uint32_t *hwcap)
49 {
50     struct { uint32_t a_type; uint32_t a_val; } auxv;
51     FILE *f = fopen("/proc/self/auxv", "r");
52     int err = -1;
53
54     if (!f)
55         return -1;
56
57     while (fread(&auxv, sizeof(auxv), 1, f) > 0) {
58         if (auxv.a_type == AT_HWCAP) {
59             *hwcap = auxv.a_val;
60             err = 0;
61             break;
62         }
63     }
64
65     fclose(f);
66     return err;
67 }
68
69 int ff_get_cpu_flags_arm(void)
70 {
71     int flags = CORE_CPU_FLAGS;
72     uint32_t hwcap;
73
74     if (get_hwcap(&hwcap) < 0)
75         return flags;
76
77 #define check_cap(cap, flag) do {               \
78         if (hwcap & HWCAP_ ## cap)              \
79             flags |= AV_CPU_FLAG_ ## flag;      \
80     } while (0)
81
82     /* No flags explicitly indicate v6 or v6T2 so check others which
83        imply support. */
84     check_cap(EDSP,    ARMV5TE);
85     check_cap(TLS,     ARMV6);
86     check_cap(THUMBEE, ARMV6T2);
87     check_cap(VFP,     VFP);
88     check_cap(VFPv3,   VFPV3);
89     check_cap(NEON,    NEON);
90
91     /* The v6 checks above are not reliable so let higher flags
92        trickle down. */
93     if (flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON))
94         flags |= AV_CPU_FLAG_ARMV6T2;
95     if (flags & AV_CPU_FLAG_ARMV6T2)
96         flags |= AV_CPU_FLAG_ARMV6;
97
98     return flags;
99 }
100
101 #else
102
103 int ff_get_cpu_flags_arm(void)
104 {
105     return AV_CPU_FLAG_ARMV5TE * HAVE_ARMV5TE |
106            AV_CPU_FLAG_ARMV6   * HAVE_ARMV6   |
107            AV_CPU_FLAG_ARMV6T2 * HAVE_ARMV6T2 |
108            AV_CPU_FLAG_VFP     * HAVE_VFP     |
109            AV_CPU_FLAG_VFPV3   * HAVE_VFPV3   |
110            AV_CPU_FLAG_NEON    * HAVE_NEON;
111 }
112
113 #endif