gfx/skia/trunk/src/core/SkUtilsArm.cpp

changeset 0
6474c204b198
     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

mercurial