OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkUtilsArm.h" | 8 // This file no longer needs to exist, but it's still referenced by Chrome's GYP
/ GN builds. |
9 | |
10 #if SK_ARM_NEON_IS_DYNAMIC | |
11 | |
12 #include <unistd.h> | |
13 #include <fcntl.h> | |
14 #include <errno.h> | |
15 #include <string.h> | |
16 #include <pthread.h> | |
17 | |
18 #if defined(SK_BUILD_FOR_ANDROID) | |
19 # include <cpu-features.h> | |
20 #endif | |
21 | |
22 // A function used to determine at runtime if the target CPU supports | |
23 // the ARM NEON instruction set. This implementation is Linux-specific. | |
24 static bool sk_cpu_arm_check_neon(void) { | |
25 // If we fail any of the following, assume we don't have NEON instructions | |
26 // This allows us to return immediately in case of error. | |
27 bool result = false; | |
28 | |
29 // Use the Android NDK's cpu-features helper library to detect NEON at runtime. | |
30 // See http://crbug.com/164154 to see why this is needed in Chromium for Android
. | |
31 #ifdef SK_BUILD_FOR_ANDROID | |
32 | |
33 result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; | |
34 | |
35 #else // SK_BUILD_FOR_ANDROID | |
36 | |
37 // There is no user-accessible CPUID instruction on ARM that we can use. | |
38 // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. | |
39 // For example, here's a typical output (Nexus S running ICS 4.0.3): | |
40 /* | |
41 Processor : ARMv7 Processor rev 2 (v7l) | |
42 BogoMIPS : 994.65 | |
43 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 | |
44 CPU implementer : 0x41 | |
45 CPU architecture: 7 | |
46 CPU variant : 0x2 | |
47 CPU part : 0xc08 | |
48 CPU revision : 2 | |
49 | |
50 Hardware : herring | |
51 Revision : 000b | |
52 Serial : 3833c77d6dc000ec | |
53 */ | |
54 char buffer[4096]; | |
55 | |
56 do { | |
57 // open /proc/cpuinfo | |
58 int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); | |
59 if (fd < 0) { | |
60 SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno)); | |
61 break; | |
62 } | |
63 | |
64 // Read the file. To simplify our search, we're going to place two | |
65 // sentinel '\n' characters: one at the start of the buffer, and one at | |
66 // the end. This means we reserve the first and last buffer bytes. | |
67 buffer[0] = '\n'; | |
68 int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2)); | |
69 close(fd); | |
70 | |
71 if (size < 0) { // should not happen | |
72 SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno)); | |
73 break; | |
74 } | |
75 | |
76 SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n", | |
77 size, buffer+1); | |
78 | |
79 // Compute buffer limit, and place final sentinel | |
80 char* buffer_end = buffer + 1 + size; | |
81 buffer_end[0] = '\n'; | |
82 | |
83 // Now, find a line that starts with "Features", i.e. look for | |
84 // '\nFeatures ' in our buffer. | |
85 const char features[] = "\nFeatures\t"; | |
86 const size_t features_len = sizeof(features)-1; | |
87 | |
88 char* line = (char*) memmem(buffer, buffer_end - buffer, | |
89 features, features_len); | |
90 if (line == nullptr) { // Weird, no Features line, bad kernel? | |
91 SkDebugf("Could not find a line starting with 'Features'" | |
92 "in /proc/cpuinfo ?\n"); | |
93 break; | |
94 } | |
95 | |
96 line += features_len; // Skip the "\nFeatures\t" prefix | |
97 | |
98 // Find the end of the current line | |
99 char* line_end = (char*) memchr(line, '\n', buffer_end - line); | |
100 if (line_end == nullptr) | |
101 line_end = buffer_end; | |
102 | |
103 // Now find an instance of 'neon' in the flags list. We want to | |
104 // ensure it's only 'neon' and not something fancy like 'noneon' | |
105 // so check that it follows a space. | |
106 const char neon[] = " neon"; | |
107 const size_t neon_len = sizeof(neon)-1; | |
108 const char* flag = (const char*) memmem(line, line_end - line, | |
109 neon, neon_len); | |
110 if (flag == nullptr) | |
111 break; | |
112 | |
113 // Ensure it is followed by a space or a newline. | |
114 if (flag[neon_len] != ' ' && flag[neon_len] != '\n') | |
115 break; | |
116 | |
117 // Fine, we support Arm NEON ! | |
118 result = true; | |
119 | |
120 } while (0); | |
121 | |
122 #endif // SK_BUILD_FOR_ANDROID | |
123 | |
124 if (result) { | |
125 SkDEBUGF(("Device supports ARM NEON instructions!\n")); | |
126 } else { | |
127 SkDEBUGF(("Device does NOT support ARM NEON instructions!\n")); | |
128 } | |
129 return result; | |
130 } | |
131 | |
132 static pthread_once_t sOnce; | |
133 static bool sHasArmNeon; | |
134 | |
135 // called through pthread_once() | |
136 void sk_cpu_arm_probe_features(void) { | |
137 sHasArmNeon = sk_cpu_arm_check_neon(); | |
138 } | |
139 | |
140 bool sk_cpu_arm_has_neon(void) { | |
141 pthread_once(&sOnce, sk_cpu_arm_probe_features); | |
142 return sHasArmNeon; | |
143 } | |
144 | |
145 #endif // SK_ARM_NEON_IS_DYNAMIC | |
OLD | NEW |