- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkUtilsArm.cpp
1
2 /*
3  * Copyright 2012 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "SkUtilsArm.h"
10
11 #if SK_ARM_NEON_IS_DYNAMIC
12
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <pthread.h>
18
19 // Set USE_ANDROID_NDK_CPU_FEATURES to use the Android NDK's
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(SK_BUILD_FOR_ANDROID)
24 #  define USE_ANDROID_NDK_CPU_FEATURES 1
25 #else
26 #  define USE_ANDROID_NDK_CPU_FEATURES 0
27 #endif
28
29 #if USE_ANDROID_NDK_CPU_FEATURES
30 #  include <cpu-features.h>
31 #endif
32
33 // Set NEON_DEBUG to 1 to allow debugging of the CPU features probing.
34 // For now, we always set it for SK_DEBUG builds.
35 #ifdef SK_DEBUG
36 #  define NEON_DEBUG  1
37 #else
38 #  define NEON_DEBUG 0
39 #endif
40
41 #if NEON_DEBUG
42 #  ifdef SK_BUILD_FOR_ANDROID
43      // used to declare PROP_VALUE_MAX and __system_property_get()
44 #    include <sys/system_properties.h>
45 #  endif
46 #endif
47
48 // A function used to determine at runtime if the target CPU supports
49 // the ARM NEON instruction set. This implementation is Linux-specific.
50 static bool sk_cpu_arm_check_neon(void) {
51     bool result = false;
52
53 #if NEON_DEBUG
54     // Allow forcing the mode through the environment during debugging.
55 #  ifdef SK_BUILD_FOR_ANDROID
56     // On Android, we use a system property
57 #   define PROP_NAME  "debug.skia.arm_neon_mode"
58     char prop[PROP_VALUE_MAX];
59     if (__system_property_get(PROP_NAME, prop) > 0) {
60 #  else
61 #   define PROP_NAME   "SKIA_ARM_NEON_MODE"
62     // On ARM Linux, we use an environment variable
63     const char* prop = getenv(PROP_NAME);
64     if (prop != NULL) {
65 #  endif
66         SkDebugf("%s: %s", PROP_NAME, prop);
67         if (!strcmp(prop, "1")) {
68             SkDebugf("Forcing ARM Neon mode to full!\n");
69             return true;
70         }
71         if (!strcmp(prop, "0")) {
72             SkDebugf("Disabling ARM NEON mode\n");
73             return false;
74         }
75     }
76     SkDebugf("Running dynamic CPU feature detection\n");
77 #endif
78
79 #if USE_ANDROID_NDK_CPU_FEATURES
80
81   result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
82
83 #else  // USE_ANDROID_NDK_CPU_FEATURES
84
85     // There is no user-accessible CPUID instruction on ARM that we can use.
86     // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature.
87     // For example, here's a typical output (Nexus S running ICS 4.0.3):
88     /*
89     Processor       : ARMv7 Processor rev 2 (v7l)
90     BogoMIPS        : 994.65
91     Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
92     CPU implementer : 0x41
93     CPU architecture: 7
94     CPU variant     : 0x2
95     CPU part        : 0xc08
96     CPU revision    : 2
97
98     Hardware        : herring
99     Revision        : 000b
100     Serial          : 3833c77d6dc000ec
101     */
102     char   buffer[4096];
103
104     // If we fail any of the following, assume we don't have NEON instructions
105     // This allows us to return immediately in case of error.
106     result = false;
107
108     do {
109         // open /proc/cpuinfo
110         int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY));
111         if (fd < 0) {
112             SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno));
113             break;
114         }
115
116         // Read the file. To simplify our search, we're going to place two
117         // sentinel '\n' characters: one at the start of the buffer, and one at
118         // the end. This means we reserve the first and last buffer bytes.
119         buffer[0] = '\n';
120         int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2));
121         close(fd);
122
123         if (size < 0) {  // should not happen
124             SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno));
125             break;
126         }
127
128         SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n",
129                  size, buffer+1);
130
131         // Compute buffer limit, and place final sentinel
132         char* buffer_end = buffer + 1 + size;
133         buffer_end[0] = '\n';
134
135         // Now, find a line that starts with "Features", i.e. look for
136         // '\nFeatures ' in our buffer.
137         const char features[] = "\nFeatures\t";
138         const size_t features_len = sizeof(features)-1;
139
140         char*  line = (char*) memmem(buffer, buffer_end - buffer,
141                                      features, features_len);
142         if (line == NULL) {  // Weird, no Features line, bad kernel?
143             SkDebugf("Could not find a line starting with 'Features'"
144               "in /proc/cpuinfo ?\n");
145             break;
146         }
147
148         line += features_len;  // Skip the "\nFeatures\t" prefix
149
150         // Find the end of the current line
151         char* line_end = (char*) memchr(line, '\n', buffer_end - line);
152         if (line_end == NULL)
153             line_end = buffer_end;
154
155         // Now find an instance of 'neon' in the flags list. We want to
156         // ensure it's only 'neon' and not something fancy like 'noneon'
157         // so check that it follows a space.
158         const char neon[] = " neon";
159         const size_t neon_len = sizeof(neon)-1;
160         const char* flag = (const char*) memmem(line, line_end - line,
161                                                 neon, neon_len);
162         if (flag == NULL)
163             break;
164
165         // Ensure it is followed by a space or a newline.
166         if (flag[neon_len] != ' ' && flag[neon_len] != '\n')
167             break;
168
169         // Fine, we support Arm NEON !
170         result = true;
171
172     } while (0);
173
174 #endif  // USE_ANDROID_NDK_CPU_FEATURES
175
176     if (result) {
177         SkDebugf("Device supports ARM NEON instructions!\n");
178     } else {
179         SkDebugf("Device does NOT support ARM NEON instructions!\n");
180     }
181     return result;
182 }
183
184 static pthread_once_t  sOnce;
185 static bool            sHasArmNeon;
186
187 // called through pthread_once()
188 void sk_cpu_arm_probe_features(void) {
189     sHasArmNeon = sk_cpu_arm_check_neon();
190 }
191
192 bool sk_cpu_arm_has_neon(void) {
193     pthread_once(&sOnce, sk_cpu_arm_probe_features);
194     return sHasArmNeon;
195 }
196
197 #endif // SK_ARM_NEON_IS_DYNAMIC