Line data Source code
1 : /*
2 : * Copyright © 2000 SuSE, Inc.
3 : * Copyright © 2007 Red Hat, Inc.
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and its
6 : * documentation for any purpose is hereby granted without fee, provided that
7 : * the above copyright notice appear in all copies and that both that
8 : * copyright notice and this permission notice appear in supporting
9 : * documentation, and that the name of SuSE not be used in advertising or
10 : * publicity pertaining to distribution of the software without specific,
11 : * written prior permission. SuSE makes no representations about the
12 : * suitability of this software for any purpose. It is provided "as is"
13 : * without express or implied warranty.
14 : *
15 : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17 : * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 : * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 : * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 : */
22 : #ifdef HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include "pixman-private.h"
27 :
28 : typedef enum
29 : {
30 : ARM_V7 = (1 << 0),
31 : ARM_V6 = (1 << 1),
32 : ARM_VFP = (1 << 2),
33 : ARM_NEON = (1 << 3),
34 : ARM_IWMMXT = (1 << 4)
35 : } arm_cpu_features_t;
36 :
37 : #if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT)
38 :
39 : #if defined(_MSC_VER)
40 :
41 : /* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
42 : #include <windows.h>
43 :
44 : extern int pixman_msvc_try_arm_neon_op ();
45 : extern int pixman_msvc_try_arm_simd_op ();
46 :
47 : static arm_cpu_features_t
48 : detect_cpu_features (void)
49 : {
50 : arm_cpu_features_t features = 0;
51 :
52 : __try
53 : {
54 : pixman_msvc_try_arm_simd_op ();
55 : features |= ARM_V6;
56 : }
57 : __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
58 : {
59 : }
60 :
61 : __try
62 : {
63 : pixman_msvc_try_arm_neon_op ();
64 : features |= ARM_NEON;
65 : }
66 : __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
67 : {
68 : }
69 :
70 : return features;
71 : }
72 :
73 : #elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) /* iOS */
74 :
75 : #include "TargetConditionals.h"
76 :
77 : static arm_cpu_features_t
78 : detect_cpu_features (void)
79 : {
80 : arm_cpu_features_t features = 0;
81 :
82 : features |= ARM_V6;
83 :
84 : /* Detection of ARM NEON on iOS is fairly simple because iOS binaries
85 : * contain separate executable images for each processor architecture.
86 : * So all we have to do is detect the armv7 architecture build. The
87 : * operating system automatically runs the armv7 binary for armv7 devices
88 : * and the armv6 binary for armv6 devices.
89 : */
90 : #if defined(__ARM_NEON__)
91 : features |= ARM_NEON;
92 : #endif
93 :
94 : return features;
95 : }
96 :
97 : #elif defined(__ANDROID__) || defined(ANDROID) /* Android */
98 :
99 : static arm_cpu_features_t
100 : detect_cpu_features (void)
101 : {
102 : arm_cpu_features_t features = 0;
103 : char buf[1024];
104 : char* pos;
105 : const char* ver_token = "CPU architecture: ";
106 : FILE* f = fopen("/proc/cpuinfo", "r");
107 : if (!f) {
108 : return features;
109 : }
110 :
111 : fread(buf, sizeof(char), sizeof(buf), f);
112 : fclose(f);
113 : pos = strstr(buf, ver_token);
114 : if (pos) {
115 : char vchar = *(pos + strlen(ver_token));
116 : if (vchar >= '0' && vchar <= '9') {
117 : int ver = vchar - '0';
118 : if (ver >= 7)
119 : features |= ARM_V7;
120 : }
121 : }
122 : if (strstr(buf, "neon") != NULL)
123 : features |= ARM_NEON;
124 : if (strstr(buf, "vfp") != NULL)
125 : features |= ARM_VFP;
126 :
127 : return features;
128 : }
129 :
130 : #elif defined (__linux__) /* linux ELF */
131 :
132 : #include <unistd.h>
133 : #include <sys/types.h>
134 : #include <sys/stat.h>
135 : #include <sys/mman.h>
136 : #include <fcntl.h>
137 : #include <string.h>
138 : #include <elf.h>
139 :
140 : static arm_cpu_features_t
141 : detect_cpu_features (void)
142 : {
143 : arm_cpu_features_t features = 0;
144 : Elf32_auxv_t aux;
145 : int fd;
146 :
147 : fd = open ("/proc/self/auxv", O_RDONLY);
148 : if (fd >= 0)
149 : {
150 : while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
151 : {
152 : if (aux.a_type == AT_HWCAP)
153 : {
154 : uint32_t hwcap = aux.a_un.a_val;
155 :
156 : /* hardcode these values to avoid depending on specific
157 : * versions of the hwcap header, e.g. HWCAP_NEON
158 : */
159 : if ((hwcap & 64) != 0)
160 : features |= ARM_VFP;
161 : if ((hwcap & 512) != 0)
162 : features |= ARM_IWMMXT;
163 : /* this flag is only present on kernel 2.6.29 */
164 : if ((hwcap & 4096) != 0)
165 : features |= ARM_NEON;
166 : }
167 : else if (aux.a_type == AT_PLATFORM)
168 : {
169 : const char *plat = (const char*) aux.a_un.a_val;
170 :
171 : if (strncmp (plat, "v7l", 3) == 0)
172 : features |= (ARM_V7 | ARM_V6);
173 : else if (strncmp (plat, "v6l", 3) == 0)
174 : features |= ARM_V6;
175 : }
176 : }
177 : close (fd);
178 : }
179 :
180 : return features;
181 : }
182 :
183 : #else /* Unknown */
184 :
185 : static arm_cpu_features_t
186 : detect_cpu_features (void)
187 : {
188 : return 0;
189 : }
190 :
191 : #endif /* Linux elf */
192 :
193 : static pixman_bool_t
194 : have_feature (arm_cpu_features_t feature)
195 : {
196 : static pixman_bool_t initialized;
197 : static arm_cpu_features_t features;
198 :
199 : if (!initialized)
200 : {
201 : features = detect_cpu_features();
202 : initialized = TRUE;
203 : }
204 :
205 : return (features & feature) == feature;
206 : }
207 :
208 : #endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */
209 :
210 : pixman_implementation_t *
211 1 : _pixman_arm_get_implementations (pixman_implementation_t *imp)
212 : {
213 : #ifdef USE_ARM_SIMD
214 : if (!_pixman_disabled ("arm-simd") && have_feature (ARM_V6))
215 : imp = _pixman_implementation_create_arm_simd (imp);
216 : #endif
217 :
218 : #ifdef USE_ARM_IWMMXT
219 : if (!_pixman_disabled ("arm-iwmmxt") && have_feature (ARM_IWMMXT))
220 : imp = _pixman_implementation_create_mmx (imp);
221 : #endif
222 :
223 : #ifdef USE_ARM_NEON
224 : if (!_pixman_disabled ("arm-neon") && have_feature (ARM_NEON))
225 : imp = _pixman_implementation_create_arm_neon (imp);
226 : #endif
227 :
228 1 : return imp;
229 : }
|