1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkUtilsArm.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,199 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkUtilsArm.h" 1.13 + 1.14 +#if SK_ARM_NEON_IS_DYNAMIC 1.15 + 1.16 +#include <unistd.h> 1.17 +#include <fcntl.h> 1.18 +#include <errno.h> 1.19 +#include <string.h> 1.20 +#include <pthread.h> 1.21 + 1.22 +// Set USE_ANDROID_NDK_CPU_FEATURES to use the Android NDK's 1.23 +// cpu-features helper library to detect NEON at runtime. See 1.24 +// http://crbug.com/164154 to see why this is needed in Chromium 1.25 +// for Android. 1.26 +#if !defined(USE_ANDROID_NDK_CPU_FEATURES) 1.27 +# if defined(SK_BUILD_FOR_ANDROID) 1.28 +# define USE_ANDROID_NDK_CPU_FEATURES 1 1.29 +# else 1.30 +# define USE_ANDROID_NDK_CPU_FEATURES 0 1.31 +# endif 1.32 +#endif 1.33 + 1.34 +#if USE_ANDROID_NDK_CPU_FEATURES 1.35 +# include <cpu-features.h> 1.36 +#endif 1.37 + 1.38 +// Set NEON_DEBUG to 1 to allow debugging of the CPU features probing. 1.39 +// For now, we always set it for SK_DEBUG builds. 1.40 +#ifdef SK_DEBUG 1.41 +# define NEON_DEBUG 1 1.42 +#else 1.43 +# define NEON_DEBUG 0 1.44 +#endif 1.45 + 1.46 +#if NEON_DEBUG 1.47 +# ifdef SK_BUILD_FOR_ANDROID 1.48 + // used to declare PROP_VALUE_MAX and __system_property_get() 1.49 +# include <sys/system_properties.h> 1.50 +# endif 1.51 +#endif 1.52 + 1.53 +// A function used to determine at runtime if the target CPU supports 1.54 +// the ARM NEON instruction set. This implementation is Linux-specific. 1.55 +static bool sk_cpu_arm_check_neon(void) { 1.56 + bool result = false; 1.57 + 1.58 +#if NEON_DEBUG 1.59 + // Allow forcing the mode through the environment during debugging. 1.60 +# ifdef SK_BUILD_FOR_ANDROID 1.61 + // On Android, we use a system property 1.62 +# define PROP_NAME "debug.skia.arm_neon_mode" 1.63 + char prop[PROP_VALUE_MAX]; 1.64 + if (__system_property_get(PROP_NAME, prop) > 0) { 1.65 +# else 1.66 +# define PROP_NAME "SKIA_ARM_NEON_MODE" 1.67 + // On ARM Linux, we use an environment variable 1.68 + const char* prop = getenv(PROP_NAME); 1.69 + if (prop != NULL) { 1.70 +# endif 1.71 + SkDebugf("%s: %s", PROP_NAME, prop); 1.72 + if (!strcmp(prop, "1")) { 1.73 + SkDebugf("Forcing ARM Neon mode to full!\n"); 1.74 + return true; 1.75 + } 1.76 + if (!strcmp(prop, "0")) { 1.77 + SkDebugf("Disabling ARM NEON mode\n"); 1.78 + return false; 1.79 + } 1.80 + } 1.81 + SkDebugf("Running dynamic CPU feature detection\n"); 1.82 +#endif 1.83 + 1.84 +#if USE_ANDROID_NDK_CPU_FEATURES 1.85 + 1.86 + result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; 1.87 + 1.88 +#else // USE_ANDROID_NDK_CPU_FEATURES 1.89 + 1.90 + // There is no user-accessible CPUID instruction on ARM that we can use. 1.91 + // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature. 1.92 + // For example, here's a typical output (Nexus S running ICS 4.0.3): 1.93 + /* 1.94 + Processor : ARMv7 Processor rev 2 (v7l) 1.95 + BogoMIPS : 994.65 1.96 + Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 1.97 + CPU implementer : 0x41 1.98 + CPU architecture: 7 1.99 + CPU variant : 0x2 1.100 + CPU part : 0xc08 1.101 + CPU revision : 2 1.102 + 1.103 + Hardware : herring 1.104 + Revision : 000b 1.105 + Serial : 3833c77d6dc000ec 1.106 + */ 1.107 + char buffer[4096]; 1.108 + 1.109 + // If we fail any of the following, assume we don't have NEON instructions 1.110 + // This allows us to return immediately in case of error. 1.111 + result = false; 1.112 + 1.113 + do { 1.114 + // open /proc/cpuinfo 1.115 + int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY)); 1.116 + if (fd < 0) { 1.117 + SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno)); 1.118 + break; 1.119 + } 1.120 + 1.121 + // Read the file. To simplify our search, we're going to place two 1.122 + // sentinel '\n' characters: one at the start of the buffer, and one at 1.123 + // the end. This means we reserve the first and last buffer bytes. 1.124 + buffer[0] = '\n'; 1.125 + int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2)); 1.126 + close(fd); 1.127 + 1.128 + if (size < 0) { // should not happen 1.129 + SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno)); 1.130 + break; 1.131 + } 1.132 + 1.133 + SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n", 1.134 + size, buffer+1); 1.135 + 1.136 + // Compute buffer limit, and place final sentinel 1.137 + char* buffer_end = buffer + 1 + size; 1.138 + buffer_end[0] = '\n'; 1.139 + 1.140 + // Now, find a line that starts with "Features", i.e. look for 1.141 + // '\nFeatures ' in our buffer. 1.142 + const char features[] = "\nFeatures\t"; 1.143 + const size_t features_len = sizeof(features)-1; 1.144 + 1.145 + char* line = (char*) memmem(buffer, buffer_end - buffer, 1.146 + features, features_len); 1.147 + if (line == NULL) { // Weird, no Features line, bad kernel? 1.148 + SkDebugf("Could not find a line starting with 'Features'" 1.149 + "in /proc/cpuinfo ?\n"); 1.150 + break; 1.151 + } 1.152 + 1.153 + line += features_len; // Skip the "\nFeatures\t" prefix 1.154 + 1.155 + // Find the end of the current line 1.156 + char* line_end = (char*) memchr(line, '\n', buffer_end - line); 1.157 + if (line_end == NULL) 1.158 + line_end = buffer_end; 1.159 + 1.160 + // Now find an instance of 'neon' in the flags list. We want to 1.161 + // ensure it's only 'neon' and not something fancy like 'noneon' 1.162 + // so check that it follows a space. 1.163 + const char neon[] = " neon"; 1.164 + const size_t neon_len = sizeof(neon)-1; 1.165 + const char* flag = (const char*) memmem(line, line_end - line, 1.166 + neon, neon_len); 1.167 + if (flag == NULL) 1.168 + break; 1.169 + 1.170 + // Ensure it is followed by a space or a newline. 1.171 + if (flag[neon_len] != ' ' && flag[neon_len] != '\n') 1.172 + break; 1.173 + 1.174 + // Fine, we support Arm NEON ! 1.175 + result = true; 1.176 + 1.177 + } while (0); 1.178 + 1.179 +#endif // USE_ANDROID_NDK_CPU_FEATURES 1.180 + 1.181 + if (result) { 1.182 + SkDebugf("Device supports ARM NEON instructions!\n"); 1.183 + } else { 1.184 + SkDebugf("Device does NOT support ARM NEON instructions!\n"); 1.185 + } 1.186 + return result; 1.187 +} 1.188 + 1.189 +static pthread_once_t sOnce; 1.190 +static bool sHasArmNeon; 1.191 + 1.192 +// called through pthread_once() 1.193 +void sk_cpu_arm_probe_features(void) { 1.194 + sHasArmNeon = sk_cpu_arm_check_neon(); 1.195 +} 1.196 + 1.197 +bool sk_cpu_arm_has_neon(void) { 1.198 + pthread_once(&sOnce, sk_cpu_arm_probe_features); 1.199 + return sHasArmNeon; 1.200 +} 1.201 + 1.202 +#endif // SK_ARM_NEON_IS_DYNAMIC