11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* 21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 SuSE, Inc. 31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2007 Red Hat, Inc. 41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission to use, copy, modify, distribute, and sell this software and its 61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation for any purpose is hereby granted without fee, provided that 71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the above copyright notice appear in all copies and that both that 81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copyright notice and this permission notice appear in supporting 91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation, and that the name of SuSE not be used in advertising or 101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * publicity pertaining to distribution of the software without specific, 111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * written prior permission. SuSE makes no representations about the 121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * suitability of this software for any purpose. It is provided "as is" 131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * without express or implied warranty. 141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H 231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h> 241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h" 271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 281176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef enum 291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ARM_V7 = (1 << 0), 311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ARM_V6 = (1 << 1), 321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ARM_VFP = (1 << 2), 331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ARM_NEON = (1 << 3), 341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ARM_IWMMXT = (1 << 4) 351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} arm_cpu_features_t; 361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT) 381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if defined(_MSC_VER) 401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */ 421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <windows.h> 431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 441176bdada62cabc6ec4b0308a930e83b679d5d36John Reckextern int pixman_msvc_try_arm_neon_op (); 451176bdada62cabc6ec4b0308a930e83b679d5d36John Reckextern int pixman_msvc_try_arm_simd_op (); 461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 471176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic arm_cpu_features_t 481176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void) 491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck arm_cpu_features_t features = 0; 511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck __try 531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_msvc_try_arm_simd_op (); 551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_V6; 561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) 581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck __try 621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_msvc_try_arm_neon_op (); 641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_NEON; 651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) 671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return features; 711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) /* iOS */ 741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "TargetConditionals.h" 761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 771176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic arm_cpu_features_t 781176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void) 791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck arm_cpu_features_t features = 0; 811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_V6; 831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* Detection of ARM NEON on iOS is fairly simple because iOS binaries 851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * contain separate executable images for each processor architecture. 861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * So all we have to do is detect the armv7 architecture build. The 871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * operating system automatically runs the armv7 binary for armv7 devices 881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and the armv6 binary for armv6 devices. 891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if defined(__ARM_NEON__) 911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_NEON; 921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return features; 951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#elif defined(__ANDROID__) || defined(ANDROID) /* Android */ 981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <cpu-features.h> 1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic arm_cpu_features_t 1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void) 1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck arm_cpu_features_t features = 0; 1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck AndroidCpuFamily cpu_family; 1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck uint64_t cpu_features; 1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cpu_family = android_getCpuFamily(); 1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cpu_features = android_getCpuFeatures(); 1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (cpu_family == ANDROID_CPU_FAMILY_ARM) 1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (cpu_features & ANDROID_CPU_ARM_FEATURE_ARMv7) 1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_V7; 1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFPv3) 1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_VFP; 1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) 1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_NEON; 1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return features; 1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#elif defined (__linux__) /* linux ELF */ 1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <unistd.h> 1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <sys/types.h> 1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <sys/stat.h> 1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <sys/mman.h> 1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <fcntl.h> 1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <string.h> 1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <elf.h> 1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic arm_cpu_features_t 1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void) 1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck arm_cpu_features_t features = 0; 1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck Elf32_auxv_t aux; 1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int fd; 1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck fd = open ("/proc/self/auxv", O_RDONLY); 1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (fd >= 0) 1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) 1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (aux.a_type == AT_HWCAP) 1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck uint32_t hwcap = aux.a_un.a_val; 1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* hardcode these values to avoid depending on specific 1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * versions of the hwcap header, e.g. HWCAP_NEON 1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if ((hwcap & 64) != 0) 1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_VFP; 1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if ((hwcap & 512) != 0) 1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_IWMMXT; 1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* this flag is only present on kernel 2.6.29 */ 1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if ((hwcap & 4096) != 0) 1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_NEON; 1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (aux.a_type == AT_PLATFORM) 1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck const char *plat = (const char*) aux.a_un.a_val; 1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (strncmp (plat, "v7l", 3) == 0) 1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= (ARM_V7 | ARM_V6); 1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (strncmp (plat, "v6l", 3) == 0) 1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features |= ARM_V6; 1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck close (fd); 1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return features; 1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#else /* Unknown */ 1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic arm_cpu_features_t 1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void) 1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 0; 1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif /* Linux elf */ 1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_bool_t 1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reckhave_feature (arm_cpu_features_t feature) 1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck static pixman_bool_t initialized; 1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck static arm_cpu_features_t features; 1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!initialized) 1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck features = detect_cpu_features(); 1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck initialized = TRUE; 1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return (features & feature) == feature; 2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */ 2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_implementation_t * 2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_arm_get_implementations (pixman_implementation_t *imp) 2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef USE_ARM_SIMD 2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!_pixman_disabled ("arm-simd") && have_feature (ARM_V6)) 2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck imp = _pixman_implementation_create_arm_simd (imp); 2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 2131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef USE_ARM_IWMMXT 2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!_pixman_disabled ("arm-iwmmxt") && have_feature (ARM_IWMMXT)) 2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck imp = _pixman_implementation_create_mmx (imp); 2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef USE_ARM_NEON 2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!_pixman_disabled ("arm-neon") && have_feature (ARM_NEON)) 2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck imp = _pixman_implementation_create_arm_neon (imp); 2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return imp; 2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 226