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