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 // This file no longer needs to exist, but it's still referenced by Chrome's GYP
/ GN builds. | 8 #include "SkUtilsArm.h" |
| 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 |