mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
[libpng16] Moved OS dependent code from arm/arm_init.c, to allow the included
implementation of the ARM NEON discovery function to be set at build-time and provide sample implementations from the current code in the contrib/arm-neon subdirectory. The __linux__ code has also been changed to compile and link on Android by using /proc/cpuinfo, and the old linux code is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux dependencies apart from opening /proc/cpuinfo and is C90 compliant.
This commit is contained in:
parent
38ef9c9779
commit
dba54b8888
7
ANNOUNCE
7
ANNOUNCE
@ -59,6 +59,13 @@ Version 1.6.10beta02 [February 16, 2014]
|
|||||||
Moved redefines of png_error(), png_warning(), png_chunk_error(),
|
Moved redefines of png_error(), png_warning(), png_chunk_error(),
|
||||||
and png_chunk_warning() from pngpriv.h to png.h to make them visible
|
and png_chunk_warning() from pngpriv.h to png.h to make them visible
|
||||||
to libpng-calling applications.
|
to libpng-calling applications.
|
||||||
|
Moved OS dependent code from arm/arm_init.c, to allow the included
|
||||||
|
implementation of the ARM NEON discovery function to be set at
|
||||||
|
build-time and provide sample implementations from the current code in the
|
||||||
|
contrib/arm-neon subdirectory. The __linux__ code has also been changed to
|
||||||
|
compile and link on Android by using /proc/cpuinfo, and the old linux code
|
||||||
|
is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux
|
||||||
|
dependencies apart from opening /proc/cpuinfo and is C90 compliant.
|
||||||
|
|
||||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
||||||
(subscription required; visit
|
(subscription required; visit
|
||||||
|
7
CHANGES
7
CHANGES
@ -4833,6 +4833,13 @@ Version 1.6.10beta02 [February 16, 2014]
|
|||||||
Moved redefines of png_error(), png_warning(), png_chunk_error(),
|
Moved redefines of png_error(), png_warning(), png_chunk_error(),
|
||||||
and png_chunk_warning() from pngpriv.h to png.h to make them visible
|
and png_chunk_warning() from pngpriv.h to png.h to make them visible
|
||||||
to libpng-calling applications.
|
to libpng-calling applications.
|
||||||
|
Moved OS dependent code from arm/arm_init.c, to allow the included
|
||||||
|
implementation of the ARM NEON discovery function to be set at
|
||||||
|
build-time and provide sample implementations from the current code in the
|
||||||
|
contrib/arm-neon subdirectory. The __linux__ code has also been changed to
|
||||||
|
compile and link on Android by using /proc/cpuinfo, and the old linux code
|
||||||
|
is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux
|
||||||
|
dependencies apart from opening /proc/cpuinfo and is C90 compliant.
|
||||||
|
|
||||||
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
|
||||||
(subscription required; visit
|
(subscription required; visit
|
||||||
|
143
arm/arm_init.c
143
arm/arm_init.c
@ -19,132 +19,33 @@
|
|||||||
#ifdef PNG_READ_SUPPORTED
|
#ifdef PNG_READ_SUPPORTED
|
||||||
#if PNG_ARM_NEON_OPT > 0
|
#if PNG_ARM_NEON_OPT > 0
|
||||||
#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */
|
#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */
|
||||||
#include <signal.h> /* for sig_atomic_t */
|
/* WARNING: it is strongly recommended that you do not build libpng with
|
||||||
|
* run-time checks for CPU features if at all possible. In the case of the ARM
|
||||||
#ifdef __ANDROID__
|
* NEON instructions there is no processor-specific way of detecting the
|
||||||
/* Linux provides access to information about CPU capabilites via
|
* presense of the required support, therefore run-time detectioon is extremely
|
||||||
* /proc/self/auxv, however Android blocks this while still claiming to be
|
* OS specific.
|
||||||
* Linux. The Andoid NDK, however, provides appropriate support.
|
|
||||||
*
|
*
|
||||||
* Documentation: http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html
|
* You may set the macro PNG_ARM_NEON_FILE to the file name of file containing
|
||||||
|
* a fragment of C source code which defines the png_have_neon function. There
|
||||||
|
* are a number of implementations in contrib/arm-neon, but the only one that
|
||||||
|
* has partial support is contrib/arm-neon/linux.c - a generic Linux
|
||||||
|
* implementation which reads /proc/cpufino.
|
||||||
*/
|
*/
|
||||||
#include <cpu-features.h>
|
#ifndef PNG_ARM_NEON_FILE
|
||||||
|
# ifdef __linux__
|
||||||
|
# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
#ifdef PNG_ARM_NEON_FILE
|
||||||
png_have_neon(png_structp png_ptr)
|
|
||||||
{
|
|
||||||
/* This is a whole lot easier than the mess below, however it is probably
|
|
||||||
* implemented as below, therefore it is better to cache the result (these
|
|
||||||
* function calls may be slow!)
|
|
||||||
*/
|
|
||||||
PNG_UNUSED(png_ptr)
|
|
||||||
return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&
|
|
||||||
(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
|
|
||||||
}
|
|
||||||
#elif defined(__linux__)
|
|
||||||
/* The generic __linux__ implementation requires reading /proc/self/auxv and
|
|
||||||
* looking at each element for one that records NEON capabilities.
|
|
||||||
*/
|
|
||||||
#include <unistd.h> /* for POSIX 1003.1 */
|
|
||||||
#include <errno.h> /* for EINTR */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <signal.h> /* for sig_atomic_t */
|
||||||
#include <sys/stat.h>
|
static int png_have_neon(png_structp png_ptr);
|
||||||
#include <fcntl.h>
|
#include PNG_ARM_NEON_FILE
|
||||||
#include <elf.h>
|
|
||||||
#include <asm/hwcap.h>
|
|
||||||
|
|
||||||
/* A read call may be interrupted, in which case it returns -1 and sets errno to
|
#else /* PNG_ARM_NEON_FILE */
|
||||||
* EINTR if nothing was done, otherwise (if something was done) a partial read
|
# error "PNG_ARM_NEON_FILE undefined: no support for run-time ARM NEON checks"
|
||||||
* may result.
|
#endif /* PNG_ARM_NEON_FILE */
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
|
|
||||||
{
|
|
||||||
size_t ntotal = 0;
|
|
||||||
char *buffer = png_voidcast(char*, buffer_in);
|
|
||||||
|
|
||||||
while (nbytes > 0)
|
|
||||||
{
|
|
||||||
unsigned int nread;
|
|
||||||
int iread;
|
|
||||||
|
|
||||||
/* Passing nread > INT_MAX to read is implementation defined in POSIX
|
|
||||||
* 1003.1, therefore despite the unsigned argument portable code must
|
|
||||||
* limit the value to INT_MAX!
|
|
||||||
*/
|
|
||||||
if (nbytes > INT_MAX)
|
|
||||||
nread = INT_MAX;
|
|
||||||
|
|
||||||
else
|
|
||||||
nread = (unsigned int)/*SAFE*/nbytes;
|
|
||||||
|
|
||||||
iread = read(fd, buffer, nread);
|
|
||||||
|
|
||||||
if (iread == -1)
|
|
||||||
{
|
|
||||||
/* This is the devil in the details, a read can terminate early with 0
|
|
||||||
* bytes read because of EINTR, yet it still returns -1 otherwise end
|
|
||||||
* of file cannot be distinguished.
|
|
||||||
*/
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
png_warning(png_ptr, "/proc read failed");
|
|
||||||
return 0; /* I.e., a permanent failure */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (iread < 0)
|
|
||||||
{
|
|
||||||
/* Not a valid 'read' result: */
|
|
||||||
png_warning(png_ptr, "OS /proc read bug");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (iread > 0)
|
|
||||||
{
|
|
||||||
/* Continue reading until a permanent failure, or EOF */
|
|
||||||
buffer += iread;
|
|
||||||
nbytes -= (unsigned int)/*SAFE*/iread;
|
|
||||||
ntotal += (unsigned int)/*SAFE*/iread;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
return ntotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ntotal; /* nbytes == 0 */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
png_have_neon(png_structp png_ptr)
|
|
||||||
{
|
|
||||||
int fd = open("/proc/self/auxv", O_RDONLY);
|
|
||||||
Elf32_auxv_t aux;
|
|
||||||
|
|
||||||
/* Failsafe: failure to open means no NEON */
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
png_warning(png_ptr, "/proc/self/auxv open failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
|
|
||||||
{
|
|
||||||
if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* We don't know how to do a run-time check on this system */
|
|
||||||
# error "no support for run-time ARM NEON checks"
|
|
||||||
#endif /* OS checks */
|
|
||||||
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
|
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
|
||||||
|
|
||||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
||||||
|
83
contrib/arm-neon/README
Normal file
83
contrib/arm-neon/README
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
OPERATING SYSTEM SPECIFIC ARM NEON DETECTION
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
Detection of the ability to exexcute ARM NEON on an ARM processor requires
|
||||||
|
operating system support. (The information is not available in user mode.)
|
||||||
|
|
||||||
|
HOW TO USE THIS
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This directory contains C code fragments which can be included in arm/arm_init.c
|
||||||
|
by setting the macro PNG_ARM_NEON_FILE to the file name in "" or <> at build
|
||||||
|
time. This setting is not recorded in pnglibconf.h and can be changed simply by
|
||||||
|
rebuilding arm/arm_init.o with the required macro definition.
|
||||||
|
|
||||||
|
For any of this code to be used the ARM NEON code must be enabled and run time
|
||||||
|
checks must be supported. I.e.:
|
||||||
|
|
||||||
|
#if PNG_ARM_NEON_OPT > 0
|
||||||
|
#ifdef PNG_ARM_NEON_CHECK_SUPPORTED
|
||||||
|
|
||||||
|
This is done in a 'configure' build by passing configure the argument:
|
||||||
|
|
||||||
|
--enable-arm-neon=check
|
||||||
|
|
||||||
|
Apart from the basic Linux implementation in contrib/arm-neon/linux.c this code
|
||||||
|
is unsupported. That means that it is not even compiled on a regular basis and
|
||||||
|
may be broken in any given minor release.
|
||||||
|
|
||||||
|
FILE FORMAT
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Each file documents its testing status as of the last time it was tested (which
|
||||||
|
may have been a long time ago):
|
||||||
|
|
||||||
|
STATUS: one of:
|
||||||
|
SUPPORTED: This indicates that the file is included in the regularly
|
||||||
|
performed test builds and bugs are fixed when discovered.
|
||||||
|
COMPILED: This indicates that the code did compile at least once. See the
|
||||||
|
more detailed description for the extent to which the result was
|
||||||
|
successful.
|
||||||
|
TESTED: This means the code was fully compiled into the libpng test programs
|
||||||
|
and these were run at least once.
|
||||||
|
|
||||||
|
BUG REPORTS: an email address to which to send reports of problems
|
||||||
|
|
||||||
|
The file is a fragment of C code. It should not define any 'extern' symbols;
|
||||||
|
everything should be static. It must define the function:
|
||||||
|
|
||||||
|
static int png_have_neon(png_structp png_ptr);
|
||||||
|
|
||||||
|
That function must return 1 if ARM NEON instructions are supported, 0 if not.
|
||||||
|
It must not execute png_error unless it detects a bug. A png_error will prevent
|
||||||
|
the reading of the PNG and in the future, writing too.
|
||||||
|
|
||||||
|
BUG REPORTS
|
||||||
|
-----------
|
||||||
|
|
||||||
|
If you mail a bug report for any file that is not SUPPORTED there may only be
|
||||||
|
limited response. Consider fixing it and sending a patch to fix the problem -
|
||||||
|
this is more likely to result in action.
|
||||||
|
|
||||||
|
CONTRIBUTIONS
|
||||||
|
-------------
|
||||||
|
|
||||||
|
You may send contributions of new implementations to
|
||||||
|
png-mng-implement@sourceforge.net. Please write code in strict C90 C where
|
||||||
|
possible. Obviously OS dependencies are to be expected. If you submit code you
|
||||||
|
must have the authors permission and it must have a license that is acceptable
|
||||||
|
to the current maintainer; in particular that license must permit
|
||||||
|
redistribution.
|
||||||
|
|
||||||
|
Please try to make the contribution a single file and give the file a clear and
|
||||||
|
unambiguous name that identifies the target OS. If multiple files really are
|
||||||
|
required put them all in a sub-directory.
|
||||||
|
|
||||||
|
You must also be prepared to handle bug reports from users of the code, either
|
||||||
|
by joining the png-mng-implement mailing list or by providing an email for the
|
||||||
|
"BUG REPORTS" entry or both. Please make sure that the header of the file
|
||||||
|
contains the STATUS and BUG REPORTS fields as above.
|
||||||
|
|
||||||
|
Please list the OS requirements as precisely as possible. Ideally you should
|
||||||
|
also list the environment in which the code has been tested and certainly list
|
||||||
|
any environments where you suspect it might not work.
|
39
contrib/arm-neon/android-ndk.c
Normal file
39
contrib/arm-neon/android-ndk.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/* contrib/arm-neon/android-ndk.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Glenn Randers-Pehrson
|
||||||
|
* Written by John Bowler, 2014.
|
||||||
|
* Last changed in libpng 1.6.10 [(PENDING RELEASE)]
|
||||||
|
*
|
||||||
|
* This code is released under the libpng license.
|
||||||
|
* For conditions of distribution and use, see the disclaimer
|
||||||
|
* and license in png.h
|
||||||
|
*
|
||||||
|
* SEE contrib/arm-neon/README before reporting bugs
|
||||||
|
*
|
||||||
|
* STATUS: COMPILED, UNTESTED
|
||||||
|
* BUG REPORTS: png-mng-implement@sourceforge.net
|
||||||
|
*
|
||||||
|
* png_have_neon implemented for the Android NDK, see:
|
||||||
|
*
|
||||||
|
* Documentation:
|
||||||
|
* http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html
|
||||||
|
* http://code.google.com/p/android/issues/detail?id=49065
|
||||||
|
*
|
||||||
|
* NOTE: this requires that libpng is built against the Android NDK and linked
|
||||||
|
* with an implementation of the Android ARM 'cpu-features' library. The code
|
||||||
|
* has been compiled only, not linked: no version of the library has been found,
|
||||||
|
* only the header files exist in the NDK.
|
||||||
|
*/
|
||||||
|
#include <cpu-features.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
png_have_neon(png_structp png_ptr)
|
||||||
|
{
|
||||||
|
/* This is a whole lot easier than the linux code, however it is probably
|
||||||
|
* implemented as below, therefore it is better to cache the result (these
|
||||||
|
* function calls may be slow!)
|
||||||
|
*/
|
||||||
|
PNG_UNUSED(png_ptr)
|
||||||
|
return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&
|
||||||
|
(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
|
||||||
|
}
|
120
contrib/arm-neon/linux-auxv.c
Normal file
120
contrib/arm-neon/linux-auxv.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/* contrib/arm-neon/linux-auxv.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Glenn Randers-Pehrson
|
||||||
|
* Written by Mans Rullgard, 2011.
|
||||||
|
* Last changed in libpng 1.6.10 [(PENDING RELEASE)]
|
||||||
|
*
|
||||||
|
* This code is released under the libpng license.
|
||||||
|
* For conditions of distribution and use, see the disclaimer
|
||||||
|
* and license in png.h
|
||||||
|
*
|
||||||
|
* SEE contrib/arm-neon/README before reporting bugs
|
||||||
|
*
|
||||||
|
* STATUS: COMPILED, TESTED
|
||||||
|
* BUG REPORTS: png-mng-implement@sourceforge.net
|
||||||
|
*
|
||||||
|
* png_have_neon implemented for Linux versions which allow access to
|
||||||
|
* /proc/self/auxv. This is probably faster, cleaner and safer than the code to
|
||||||
|
* read /proc/cpuinfo in contrib/arm-neon/linux, however it is yet another piece
|
||||||
|
* of potentially untested code and has more complex dependencies than the code
|
||||||
|
* to read cpuinfo.
|
||||||
|
*
|
||||||
|
* This generic __linux__ implementation requires reading /proc/self/auxv and
|
||||||
|
* looking at each element for one that records NEON capabilities.
|
||||||
|
*/
|
||||||
|
#include <unistd.h> /* for POSIX 1003.1 */
|
||||||
|
#include <errno.h> /* for EINTR */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
|
||||||
|
/* A read call may be interrupted, in which case it returns -1 and sets errno to
|
||||||
|
* EINTR if nothing was done, otherwise (if something was done) a partial read
|
||||||
|
* may result.
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
|
||||||
|
{
|
||||||
|
size_t ntotal = 0;
|
||||||
|
char *buffer = png_voidcast(char*, buffer_in);
|
||||||
|
|
||||||
|
while (nbytes > 0)
|
||||||
|
{
|
||||||
|
unsigned int nread;
|
||||||
|
int iread;
|
||||||
|
|
||||||
|
/* Passing nread > INT_MAX to read is implementation defined in POSIX
|
||||||
|
* 1003.1, therefore despite the unsigned argument portable code must
|
||||||
|
* limit the value to INT_MAX!
|
||||||
|
*/
|
||||||
|
if (nbytes > INT_MAX)
|
||||||
|
nread = INT_MAX;
|
||||||
|
|
||||||
|
else
|
||||||
|
nread = (unsigned int)/*SAFE*/nbytes;
|
||||||
|
|
||||||
|
iread = read(fd, buffer, nread);
|
||||||
|
|
||||||
|
if (iread == -1)
|
||||||
|
{
|
||||||
|
/* This is the devil in the details, a read can terminate early with 0
|
||||||
|
* bytes read because of EINTR, yet it still returns -1 otherwise end
|
||||||
|
* of file cannot be distinguished.
|
||||||
|
*/
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
png_warning(png_ptr, "/proc read failed");
|
||||||
|
return 0; /* I.e., a permanent failure */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (iread < 0)
|
||||||
|
{
|
||||||
|
/* Not a valid 'read' result: */
|
||||||
|
png_warning(png_ptr, "OS /proc read bug");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (iread > 0)
|
||||||
|
{
|
||||||
|
/* Continue reading until a permanent failure, or EOF */
|
||||||
|
buffer += iread;
|
||||||
|
nbytes -= (unsigned int)/*SAFE*/iread;
|
||||||
|
ntotal += (unsigned int)/*SAFE*/iread;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
return ntotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ntotal; /* nbytes == 0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
png_have_neon(png_structp png_ptr)
|
||||||
|
{
|
||||||
|
int fd = open("/proc/self/auxv", O_RDONLY);
|
||||||
|
Elf32_auxv_t aux;
|
||||||
|
|
||||||
|
/* Failsafe: failure to open means no NEON */
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
png_warning(png_ptr, "/proc/self/auxv open failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
|
||||||
|
{
|
||||||
|
if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
159
contrib/arm-neon/linux.c
Normal file
159
contrib/arm-neon/linux.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/* contrib/arm-neon/linux.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Glenn Randers-Pehrson
|
||||||
|
* Written by John Bowler, 2014.
|
||||||
|
* Last changed in libpng 1.6.10 [(PENDING RELEASE)]
|
||||||
|
*
|
||||||
|
* This code is released under the libpng license.
|
||||||
|
* For conditions of distribution and use, see the disclaimer
|
||||||
|
* and license in png.h
|
||||||
|
*
|
||||||
|
* SEE contrib/arm-neon/README before reporting bugs
|
||||||
|
*
|
||||||
|
* STATUS: SUPPORTED
|
||||||
|
* BUG REPORTS: png-mng-implement@sourceforge.net
|
||||||
|
*
|
||||||
|
* png_have_neon implemented for Linux by reading the widely available
|
||||||
|
* pseudo-file /proc/cpuinfo.
|
||||||
|
*
|
||||||
|
* This code is strict ANSI-C and is probably moderately portable, it does
|
||||||
|
* however use <stdio.h> and assumes that /proc/cpuinfo is never localized.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
png_have_neon(png_structp png_ptr)
|
||||||
|
{
|
||||||
|
FILE *f = fopen("/proc/cpuinfo", "rb");
|
||||||
|
|
||||||
|
if (f != NULL)
|
||||||
|
{
|
||||||
|
/* This is a simple state machine which reads the input byte-by-byte until
|
||||||
|
* it gets a match on the 'neon' feature or reaches the end of the stream.
|
||||||
|
*/
|
||||||
|
static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69 };
|
||||||
|
static const char ch_neon[] = { 78, 69, 79, 78 };
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine
|
||||||
|
} state;
|
||||||
|
int counter;
|
||||||
|
|
||||||
|
for (state=StartLine, counter=0;;)
|
||||||
|
{
|
||||||
|
int ch = fgetc(f);
|
||||||
|
|
||||||
|
if (ch == EOF)
|
||||||
|
{
|
||||||
|
/* EOF means error or end-of-file, return false; neon at EOF is
|
||||||
|
* assumed to be a mistake.
|
||||||
|
*/
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case StartLine:
|
||||||
|
/* Match spaces at the start of line */
|
||||||
|
if (ch <= 32) /* skip control characters and space */
|
||||||
|
break;
|
||||||
|
|
||||||
|
counter=0;
|
||||||
|
state = Feature;
|
||||||
|
/* FALL THROUGH */
|
||||||
|
|
||||||
|
case Feature:
|
||||||
|
/* Match 'FEATURE', ASCII case insensitive. */
|
||||||
|
if ((ch & ~0x40) == ch_feature[counter])
|
||||||
|
{
|
||||||
|
if (++counter == (sizeof ch_feature))
|
||||||
|
state = Colon;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* did not match 'feature' */
|
||||||
|
state = SkipLine;
|
||||||
|
/* FALL THROUGH */
|
||||||
|
|
||||||
|
case SkipLine:
|
||||||
|
skipLine:
|
||||||
|
/* Skip everything until we see linefeed or carriage return */
|
||||||
|
if (ch != 10 && ch != 13)
|
||||||
|
break;
|
||||||
|
|
||||||
|
state = StartLine;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Colon:
|
||||||
|
/* Match any number of space or tab followed by ':' */
|
||||||
|
if (ch == 32 || ch == 9)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ch == 58) /* i.e. ':' */
|
||||||
|
{
|
||||||
|
state = StartTag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either a bad line format or a 'feature' prefix followed by
|
||||||
|
* other characters.
|
||||||
|
*/
|
||||||
|
state = SkipLine;
|
||||||
|
goto skipLine;
|
||||||
|
|
||||||
|
case StartTag:
|
||||||
|
/* Skip space characters before a tag */
|
||||||
|
if (ch == 32 || ch == 9)
|
||||||
|
break;
|
||||||
|
|
||||||
|
state = Neon;
|
||||||
|
counter = 0;
|
||||||
|
/* FALL THROUGH */
|
||||||
|
|
||||||
|
case Neon:
|
||||||
|
/* Look for 'neon' tag */
|
||||||
|
if ((ch & ~0x40) == ch_neon[counter])
|
||||||
|
{
|
||||||
|
if (++counter == (sizeof ch_neon))
|
||||||
|
state = HaveNeon;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = SkipTag;
|
||||||
|
/* FALL THROUGH */
|
||||||
|
|
||||||
|
case SkipTag:
|
||||||
|
/* Skip non-space characters */
|
||||||
|
if (ch == 10 || ch == 13)
|
||||||
|
state = StartLine;
|
||||||
|
|
||||||
|
else if (ch == 32 || ch == 9)
|
||||||
|
state = StartTag;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HaveNeon:
|
||||||
|
/* Have seen a 'neon' prefix, but there must be a space or new
|
||||||
|
* line character to terminate it.
|
||||||
|
*/
|
||||||
|
if (ch == 10 || ch == 13 || ch == 32 || ch == 9)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = SkipTag;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
png_error(png_ptr, "png_have_neon: internal error (bug)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
png_warning(png_ptr, "/proc/cpuinfo open failed");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user