OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2012 The Android Open Source Project | 3 * Copyright 2012 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkUtilsArm.h" | 9 #include "SkUtilsArm.h" |
10 | 10 |
11 #if SK_ARM_NEON_IS_DYNAMIC | 11 #if SK_ARM_NEON_IS_DYNAMIC |
12 | 12 |
13 #include <unistd.h> | 13 #include <unistd.h> |
14 #include <fcntl.h> | 14 #include <fcntl.h> |
15 #include <errno.h> | 15 #include <errno.h> |
16 #include <string.h> | 16 #include <string.h> |
17 #include <pthread.h> | 17 #include <pthread.h> |
18 | 18 |
19 // Set USE_ANDROID_NDK_CPU_FEATURES to use the Android NDK's | 19 #if SK_BUILD_FOR_ANDROID |
20 // cpu-features helper library to detect NEON at runtime. See | |
21 // http://crbug.com/164154 to see why this is needed in Chromium | |
22 // for Android. | |
23 #if !defined(USE_ANDROID_NDK_CPU_FEATURES) | |
24 # if defined(SK_BUILD_FOR_ANDROID) | |
25 # define USE_ANDROID_NDK_CPU_FEATURES 1 | |
26 # else | |
27 # define USE_ANDROID_NDK_CPU_FEATURES 0 | |
28 # endif | |
29 #endif | |
30 | |
31 #if USE_ANDROID_NDK_CPU_FEATURES | |
32 # include <cpu-features.h> | 20 # include <cpu-features.h> |
33 #endif | 21 #endif |
34 | 22 |
35 // Set NEON_DEBUG to 1 to allow debugging of the CPU features probing. | |
36 // For now, we always set it for SK_DEBUG builds. | |
37 #ifdef SK_DEBUG | |
38 # define NEON_DEBUG 1 | |
39 #else | |
40 # define NEON_DEBUG 0 | |
41 #endif | |
42 | |
43 #if NEON_DEBUG | |
44 # ifdef SK_BUILD_FOR_ANDROID | |
45 // used to declare PROP_VALUE_MAX and __system_property_get() | |
46 # include <sys/system_properties.h> | |
47 # endif | |
48 #endif | |
49 | |
50 // A function used to determine at runtime if the target CPU supports | 23 // A function used to determine at runtime if the target CPU supports |
51 // the ARM NEON instruction set. This implementation is Linux-specific. | 24 // the ARM NEON instruction set. This implementation is Linux-specific. |
52 static bool sk_cpu_arm_check_neon(void) { | 25 static bool sk_cpu_arm_check_neon(void) { |
| 26 // If we fail any of the following, assume we don't have NEON instructions |
| 27 // This allows us to return immediately in case of error. |
53 bool result = false; | 28 bool result = false; |
54 | 29 |
55 #if NEON_DEBUG | 30 // Use the Android NDK's cpu-features helper library to detect NEON at runtime. |
56 // Allow forcing the mode through the environment during debugging. | 31 // See http://crbug.com/164154 to see why this is needed in Chromium for Android
. |
57 # ifdef SK_BUILD_FOR_ANDROID | 32 #ifdef SK_BUILD_FOR_ANDROID |
58 // On Android, we use a system property | |
59 # define PROP_NAME "debug.skia.arm_neon_mode" | |
60 char prop[PROP_VALUE_MAX]; | |
61 if (__system_property_get(PROP_NAME, prop) > 0) { | |
62 # else | |
63 # define PROP_NAME "SKIA_ARM_NEON_MODE" | |
64 // On ARM Linux, we use an environment variable | |
65 const char* prop = getenv(PROP_NAME); | |
66 if (prop != NULL) { | |
67 # endif | |
68 SkDebugf("%s: %s", PROP_NAME, prop); | |
69 if (!strcmp(prop, "1")) { | |
70 SkDebugf("Forcing ARM Neon mode to full!\n"); | |
71 return true; | |
72 } | |
73 if (!strcmp(prop, "0")) { | |
74 SkDebugf("Disabling ARM NEON mode\n"); | |
75 return false; | |
76 } | |
77 } | |
78 SkDebugf("Running dynamic CPU feature detection\n"); | |
79 #endif | |
80 | |
81 #if USE_ANDROID_NDK_CPU_FEATURES | |
82 | 33 |
83 result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; | 34 result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
84 | 35 |
85 #else // USE_ANDROID_NDK_CPU_FEATURES | 36 #else // SK_BUILD_FOR_ANDROID |
86 | 37 |
87 // There is no user-accessible CPUID instruction on ARM that we can use. | 38 // There is no user-accessible CPUID instruction on ARM that we can use. |
88 // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. | 39 // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. |
89 // For example, here's a typical output (Nexus S running ICS 4.0.3): | 40 // For example, here's a typical output (Nexus S running ICS 4.0.3): |
90 /* | 41 /* |
91 Processor : ARMv7 Processor rev 2 (v7l) | 42 Processor : ARMv7 Processor rev 2 (v7l) |
92 BogoMIPS : 994.65 | 43 BogoMIPS : 994.65 |
93 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 | 44 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 |
94 CPU implementer : 0x41 | 45 CPU implementer : 0x41 |
95 CPU architecture: 7 | 46 CPU architecture: 7 |
96 CPU variant : 0x2 | 47 CPU variant : 0x2 |
97 CPU part : 0xc08 | 48 CPU part : 0xc08 |
98 CPU revision : 2 | 49 CPU revision : 2 |
99 | 50 |
100 Hardware : herring | 51 Hardware : herring |
101 Revision : 000b | 52 Revision : 000b |
102 Serial : 3833c77d6dc000ec | 53 Serial : 3833c77d6dc000ec |
103 */ | 54 */ |
104 char buffer[4096]; | 55 char buffer[4096]; |
105 | 56 |
106 // If we fail any of the following, assume we don't have NEON instructions | |
107 // This allows us to return immediately in case of error. | |
108 result = false; | |
109 | |
110 do { | 57 do { |
111 // open /proc/cpuinfo | 58 // open /proc/cpuinfo |
112 int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); | 59 int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); |
113 if (fd < 0) { | 60 if (fd < 0) { |
114 SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno)); | 61 SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno)); |
115 break; | 62 break; |
116 } | 63 } |
117 | 64 |
118 // Read the file. To simplify our search, we're going to place two | 65 // Read the file. To simplify our search, we're going to place two |
119 // sentinel '\n' characters: one at the start of the buffer, and one at | 66 // sentinel '\n' characters: one at the start of the buffer, and one at |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 | 113 |
167 // Ensure it is followed by a space or a newline. | 114 // Ensure it is followed by a space or a newline. |
168 if (flag[neon_len] != ' ' && flag[neon_len] != '\n') | 115 if (flag[neon_len] != ' ' && flag[neon_len] != '\n') |
169 break; | 116 break; |
170 | 117 |
171 // Fine, we support Arm NEON ! | 118 // Fine, we support Arm NEON ! |
172 result = true; | 119 result = true; |
173 | 120 |
174 } while (0); | 121 } while (0); |
175 | 122 |
176 #endif // USE_ANDROID_NDK_CPU_FEATURES | 123 #endif // SK_BUILD_FOR_ANDROID |
177 | 124 |
178 if (result) { | 125 if (result) { |
179 SkDebugf("Device supports ARM NEON instructions!\n"); | 126 SkDEBUGF(("Device supports ARM NEON instructions!\n")); |
180 } else { | 127 } else { |
181 SkDebugf("Device does NOT support ARM NEON instructions!\n"); | 128 SkDEBUGF(("Device does NOT support ARM NEON instructions!\n")); |
182 } | 129 } |
183 return result; | 130 return result; |
184 } | 131 } |
185 | 132 |
186 static pthread_once_t sOnce; | 133 static pthread_once_t sOnce; |
187 static bool sHasArmNeon; | 134 static bool sHasArmNeon; |
188 | 135 |
189 // called through pthread_once() | 136 // called through pthread_once() |
190 void sk_cpu_arm_probe_features(void) { | 137 void sk_cpu_arm_probe_features(void) { |
191 sHasArmNeon = sk_cpu_arm_check_neon(); | 138 sHasArmNeon = sk_cpu_arm_check_neon(); |
192 } | 139 } |
193 | 140 |
194 bool sk_cpu_arm_has_neon(void) { | 141 bool sk_cpu_arm_has_neon(void) { |
195 pthread_once(&sOnce, sk_cpu_arm_probe_features); | 142 pthread_once(&sOnce, sk_cpu_arm_probe_features); |
196 return sHasArmNeon; | 143 return sHasArmNeon; |
197 } | 144 } |
198 | 145 |
199 #endif // SK_ARM_NEON_IS_DYNAMIC | 146 #endif // SK_ARM_NEON_IS_DYNAMIC |
OLD | NEW |