OLD | NEW |
(Empty) | |
| 1 |
| 2 /* arm_init.c - NEON optimised filter functions |
| 3 * |
| 4 * Copyright (c) 2013 Glenn Randers-Pehrson |
| 5 * Written by Mans Rullgard, 2011. |
| 6 * Last changed in libpng 1.5.17 [July 18, 2013] |
| 7 * |
| 8 * This code is released under the libpng license. |
| 9 * For conditions of distribution and use, see the disclaimer |
| 10 * and license in png.h |
| 11 */ |
| 12 /* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are |
| 13 * called. |
| 14 */ |
| 15 #define _POSIX_SOURCE 1 |
| 16 |
| 17 #include "../pngpriv.h" |
| 18 |
| 19 #ifdef PNG_READ_SUPPORTED |
| 20 #if PNG_ARM_NEON_OPT > 0 |
| 21 #ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */ |
| 22 #include <signal.h> /* for sig_atomic_t */ |
| 23 |
| 24 #ifdef __ANDROID__ |
| 25 /* Linux provides access to information about CPU capabilites via |
| 26 * /proc/self/auxv, however Android blocks this while still claiming to be |
| 27 * Linux. The Andoid NDK, however, provides appropriate support. |
| 28 * |
| 29 * Documentation: http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html |
| 30 */ |
| 31 #include <cpu-features.h> |
| 32 |
| 33 static int |
| 34 png_have_neon(png_structp png_ptr) |
| 35 { |
| 36 /* This is a whole lot easier than the mess below, however it is probably |
| 37 * implemented as below, therefore it is better to cache the result (these |
| 38 * function calls may be slow!) |
| 39 */ |
| 40 PNG_UNUSED(png_ptr) |
| 41 return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM && |
| 42 (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
| 43 } |
| 44 #elif defined(__linux__) |
| 45 /* The generic __linux__ implementation requires reading /proc/self/auxv and |
| 46 * looking at each element for one that records NEON capabilities. |
| 47 */ |
| 48 #include <unistd.h> /* for POSIX 1003.1 */ |
| 49 #include <errno.h> /* for EINTR */ |
| 50 |
| 51 #include <sys/types.h> |
| 52 #include <sys/stat.h> |
| 53 #include <fcntl.h> |
| 54 #include <elf.h> |
| 55 #include <asm/hwcap.h> |
| 56 |
| 57 /* A read call may be interrupted, in which case it returns -1 and sets errno to |
| 58 * EINTR if nothing was done, otherwise (if something was done) a partial read |
| 59 * may result. |
| 60 */ |
| 61 static size_t |
| 62 safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes) |
| 63 { |
| 64 size_t ntotal = 0; |
| 65 char *buffer = png_voidcast(char*, buffer_in); |
| 66 |
| 67 while (nbytes > 0) |
| 68 { |
| 69 unsigned int nread; |
| 70 int iread; |
| 71 |
| 72 /* Passing nread > INT_MAX to read is implementation defined in POSIX |
| 73 * 1003.1, therefore despite the unsigned argument portable code must |
| 74 * limit the value to INT_MAX! |
| 75 */ |
| 76 if (nbytes > INT_MAX) |
| 77 nread = INT_MAX; |
| 78 |
| 79 else |
| 80 nread = (unsigned int)/*SAFE*/nbytes; |
| 81 |
| 82 iread = read(fd, buffer, nread); |
| 83 |
| 84 if (iread == -1) |
| 85 { |
| 86 /* This is the devil in the details, a read can terminate early with 0 |
| 87 * bytes read because of EINTR, yet it still returns -1 otherwise end |
| 88 * of file cannot be distinguished. |
| 89 */ |
| 90 if (errno != EINTR) |
| 91 { |
| 92 png_warning(png_ptr, "/proc read failed"); |
| 93 return 0; /* I.e. a permanent failure */ |
| 94 } |
| 95 } |
| 96 |
| 97 else if (iread < 0) |
| 98 { |
| 99 /* Not a valid 'read' result: */ |
| 100 png_warning(png_ptr, "OS /proc read bug"); |
| 101 return 0; |
| 102 } |
| 103 |
| 104 else if (iread > 0) |
| 105 { |
| 106 /* Continue reading until a permanent failure, or EOF */ |
| 107 buffer += iread; |
| 108 nbytes -= (unsigned int)/*SAFE*/iread; |
| 109 ntotal += (unsigned int)/*SAFE*/iread; |
| 110 } |
| 111 |
| 112 else |
| 113 return ntotal; |
| 114 } |
| 115 |
| 116 return ntotal; /* nbytes == 0 */ |
| 117 } |
| 118 |
| 119 static int |
| 120 png_have_neon(png_structp png_ptr) |
| 121 { |
| 122 int fd = open("/proc/self/auxv", O_RDONLY); |
| 123 Elf32_auxv_t aux; |
| 124 |
| 125 /* Failsafe: failure to open means no NEON */ |
| 126 if (fd == -1) |
| 127 { |
| 128 png_warning(png_ptr, "/proc/self/auxv open failed"); |
| 129 return 0; |
| 130 } |
| 131 |
| 132 while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux) |
| 133 { |
| 134 if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0) |
| 135 { |
| 136 close(fd); |
| 137 return 1; |
| 138 } |
| 139 } |
| 140 |
| 141 close(fd); |
| 142 return 0; |
| 143 } |
| 144 #else |
| 145 /* We don't know how to do a run-time check on this system */ |
| 146 # error "no support for run-time ARM NEON checks" |
| 147 #endif /* OS checks */ |
| 148 #endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ |
| 149 |
| 150 #ifndef PNG_ALIGNED_MEMORY_SUPPORTED |
| 151 # error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED" |
| 152 #endif |
| 153 |
| 154 void |
| 155 png_init_filter_functions_neon(png_structp pp, unsigned int bpp) |
| 156 { |
| 157 #ifdef PNG_ARM_NEON_API_SUPPORTED |
| 158 switch ((pp->options >> PNG_ARM_NEON) & 3) |
| 159 { |
| 160 case PNG_OPTION_UNSET: |
| 161 /* Allow the run-time check to execute if it has been enabled - |
| 162 * thus both API and CHECK can be turned on. If it isn't supported |
| 163 * this case will fall through to the 'default' below, which just |
| 164 * returns. |
| 165 */ |
| 166 #endif /* PNG_ARM_NEON_API_SUPPORTED */ |
| 167 #ifdef PNG_ARM_NEON_CHECK_SUPPORTED |
| 168 { |
| 169 static volatile sig_atomic_t no_neon = -1; /* not checked */ |
| 170 |
| 171 if (no_neon < 0) |
| 172 no_neon = !png_have_neon(pp); |
| 173 |
| 174 if (no_neon) |
| 175 return; |
| 176 } |
| 177 #ifdef PNG_ARM_NEON_API_SUPPORTED |
| 178 break; |
| 179 #endif |
| 180 #endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ |
| 181 #ifdef PNG_ARM_NEON_API_SUPPORTED |
| 182 case PNG_OPTION_ON: |
| 183 /* Option turned on */ |
| 184 break; |
| 185 |
| 186 default: /* OFF or INVALID */ |
| 187 return; |
| 188 } |
| 189 #endif |
| 190 |
| 191 /* IMPORTANT: any new external functions used here must be declared using |
| 192 * PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the |
| 193 * 'prefix' option to configure works: |
| 194 * |
| 195 * ./configure --with-libpng-prefix=foobar_ |
| 196 * |
| 197 * Verify you have got this right by running the above command, doing a build |
| 198 * and examining pngprefix.h; it must contain a #define for every external |
| 199 * function you add. (Notice that this happens automatically for the |
| 200 * initialization function.) |
| 201 */ |
| 202 pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon; |
| 203 |
| 204 if (bpp == 3) |
| 205 { |
| 206 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon; |
| 207 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon; |
| 208 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = |
| 209 png_read_filter_row_paeth3_neon; |
| 210 } |
| 211 |
| 212 else if (bpp == 4) |
| 213 { |
| 214 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon; |
| 215 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon; |
| 216 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = |
| 217 png_read_filter_row_paeth4_neon; |
| 218 } |
| 219 } |
| 220 #endif /* PNG_ARM_NEON_OPT > 0 */ |
| 221 #endif /* PNG_READ_SUPPORTED */ |
OLD | NEW |