michael@0: /* michael@0: * Copyright © 2000 SuSE, Inc. michael@0: * Copyright © 2007 Red Hat, Inc. michael@0: * michael@0: * Permission to use, copy, modify, distribute, and sell this software and its michael@0: * documentation for any purpose is hereby granted without fee, provided that michael@0: * the above copyright notice appear in all copies and that both that michael@0: * copyright notice and this permission notice appear in supporting michael@0: * documentation, and that the name of SuSE not be used in advertising or michael@0: * publicity pertaining to distribution of the software without specific, michael@0: * written prior permission. SuSE makes no representations about the michael@0: * suitability of this software for any purpose. It is provided "as is" michael@0: * without express or implied warranty. michael@0: * michael@0: * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE michael@0: * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION michael@0: * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN michael@0: * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: */ michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: michael@0: #include "pixman-private.h" michael@0: michael@0: typedef enum michael@0: { michael@0: ARM_V7 = (1 << 0), michael@0: ARM_V6 = (1 << 1), michael@0: ARM_VFP = (1 << 2), michael@0: ARM_NEON = (1 << 3), michael@0: ARM_IWMMXT = (1 << 4) michael@0: } arm_cpu_features_t; michael@0: michael@0: #if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT) michael@0: michael@0: #if defined(_MSC_VER) michael@0: michael@0: /* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */ michael@0: #include michael@0: michael@0: extern int pixman_msvc_try_arm_neon_op (); michael@0: extern int pixman_msvc_try_arm_simd_op (); michael@0: michael@0: static arm_cpu_features_t michael@0: detect_cpu_features (void) michael@0: { michael@0: arm_cpu_features_t features = 0; michael@0: michael@0: __try michael@0: { michael@0: pixman_msvc_try_arm_simd_op (); michael@0: features |= ARM_V6; michael@0: } michael@0: __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: } michael@0: michael@0: __try michael@0: { michael@0: pixman_msvc_try_arm_neon_op (); michael@0: features |= ARM_NEON; michael@0: } michael@0: __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) michael@0: { michael@0: } michael@0: michael@0: return features; michael@0: } michael@0: michael@0: #elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) /* iOS */ michael@0: michael@0: #include "TargetConditionals.h" michael@0: michael@0: static arm_cpu_features_t michael@0: detect_cpu_features (void) michael@0: { michael@0: arm_cpu_features_t features = 0; michael@0: michael@0: features |= ARM_V6; michael@0: michael@0: /* Detection of ARM NEON on iOS is fairly simple because iOS binaries michael@0: * contain separate executable images for each processor architecture. michael@0: * So all we have to do is detect the armv7 architecture build. The michael@0: * operating system automatically runs the armv7 binary for armv7 devices michael@0: * and the armv6 binary for armv6 devices. michael@0: */ michael@0: #if defined(__ARM_NEON__) michael@0: features |= ARM_NEON; michael@0: #endif michael@0: michael@0: return features; michael@0: } michael@0: michael@0: #elif defined(__ANDROID__) || defined(ANDROID) /* Android */ michael@0: michael@0: static arm_cpu_features_t michael@0: detect_cpu_features (void) michael@0: { michael@0: arm_cpu_features_t features = 0; michael@0: char buf[1024]; michael@0: char* pos; michael@0: const char* ver_token = "CPU architecture: "; michael@0: FILE* f = fopen("/proc/cpuinfo", "r"); michael@0: if (!f) { michael@0: return features; michael@0: } michael@0: michael@0: fread(buf, sizeof(char), sizeof(buf), f); michael@0: fclose(f); michael@0: pos = strstr(buf, ver_token); michael@0: if (pos) { michael@0: char vchar = *(pos + strlen(ver_token)); michael@0: if (vchar >= '0' && vchar <= '9') { michael@0: int ver = vchar - '0'; michael@0: if (ver >= 7) michael@0: features |= ARM_V7; michael@0: } michael@0: } michael@0: if (strstr(buf, "neon") != NULL) michael@0: features |= ARM_NEON; michael@0: if (strstr(buf, "vfp") != NULL) michael@0: features |= ARM_VFP; michael@0: michael@0: return features; michael@0: } michael@0: michael@0: #elif defined (__linux__) /* linux ELF */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: static arm_cpu_features_t michael@0: detect_cpu_features (void) michael@0: { michael@0: arm_cpu_features_t features = 0; michael@0: Elf32_auxv_t aux; michael@0: int fd; michael@0: michael@0: fd = open ("/proc/self/auxv", O_RDONLY); michael@0: if (fd >= 0) michael@0: { michael@0: while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) michael@0: { michael@0: if (aux.a_type == AT_HWCAP) michael@0: { michael@0: uint32_t hwcap = aux.a_un.a_val; michael@0: michael@0: /* hardcode these values to avoid depending on specific michael@0: * versions of the hwcap header, e.g. HWCAP_NEON michael@0: */ michael@0: if ((hwcap & 64) != 0) michael@0: features |= ARM_VFP; michael@0: if ((hwcap & 512) != 0) michael@0: features |= ARM_IWMMXT; michael@0: /* this flag is only present on kernel 2.6.29 */ michael@0: if ((hwcap & 4096) != 0) michael@0: features |= ARM_NEON; michael@0: } michael@0: else if (aux.a_type == AT_PLATFORM) michael@0: { michael@0: const char *plat = (const char*) aux.a_un.a_val; michael@0: michael@0: if (strncmp (plat, "v7l", 3) == 0) michael@0: features |= (ARM_V7 | ARM_V6); michael@0: else if (strncmp (plat, "v6l", 3) == 0) michael@0: features |= ARM_V6; michael@0: } michael@0: } michael@0: close (fd); michael@0: } michael@0: michael@0: return features; michael@0: } michael@0: michael@0: #else /* Unknown */ michael@0: michael@0: static arm_cpu_features_t michael@0: detect_cpu_features (void) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: #endif /* Linux elf */ michael@0: michael@0: static pixman_bool_t michael@0: have_feature (arm_cpu_features_t feature) michael@0: { michael@0: static pixman_bool_t initialized; michael@0: static arm_cpu_features_t features; michael@0: michael@0: if (!initialized) michael@0: { michael@0: features = detect_cpu_features(); michael@0: initialized = TRUE; michael@0: } michael@0: michael@0: return (features & feature) == feature; michael@0: } michael@0: michael@0: #endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */ michael@0: michael@0: pixman_implementation_t * michael@0: _pixman_arm_get_implementations (pixman_implementation_t *imp) michael@0: { michael@0: #ifdef USE_ARM_SIMD michael@0: if (!_pixman_disabled ("arm-simd") && have_feature (ARM_V6)) michael@0: imp = _pixman_implementation_create_arm_simd (imp); michael@0: #endif michael@0: michael@0: #ifdef USE_ARM_IWMMXT michael@0: if (!_pixman_disabled ("arm-iwmmxt") && have_feature (ARM_IWMMXT)) michael@0: imp = _pixman_implementation_create_mmx (imp); michael@0: #endif michael@0: michael@0: #ifdef USE_ARM_NEON michael@0: if (!_pixman_disabled ("arm-neon") && have_feature (ARM_NEON)) michael@0: imp = _pixman_implementation_create_arm_neon (imp); michael@0: #endif michael@0: michael@0: return imp; michael@0: }