mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00

Allow run-time ARM NEON checking to be disabled. A new configure option: --enable-arm-neon=always will stop the run-time checks. New checks within arm/arm_init.c will cause the code not to be compiled unless __ARM_NEON__ is set. This should make it fail safe (if someone asks for it on then the build will fail if it can't be done.)
236 lines
7.5 KiB
ArmAsm
236 lines
7.5 KiB
ArmAsm
|
|
/* filter_neon.S - NEON optimised filter functions
|
|
*
|
|
* Copyright (c) 2011 Glenn Randers-Pehrson
|
|
* Written by Mans Rullgard, 2011.
|
|
* Last changed in libpng 1.5.7 [December 15, 2011]
|
|
*
|
|
* This code is released under the libpng license.
|
|
* For conditions of distribution and use, see the disclaimer
|
|
* and license in png.h
|
|
*/
|
|
|
|
/* This is required to get the symbol renames, which are #defines, and also
|
|
* includes the value of PNG_FILTER_OPTIMIZATIONS.
|
|
*/
|
|
#define PNG_VERSION_INFO_ONLY
|
|
#include "../pngpriv.h"
|
|
|
|
#if defined(PNG_FILTER_OPTIMIZATIONS) && defined(__arm__) && \
|
|
defined(__ARM_NEON__)
|
|
#if defined(__linux__) && defined(__ELF__)
|
|
.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
|
|
#endif
|
|
|
|
#ifdef __ELF__
|
|
# define ELF
|
|
#else
|
|
# define ELF @
|
|
#endif
|
|
|
|
.arch armv7-a
|
|
.fpu neon
|
|
|
|
.macro func name, export=0
|
|
.macro endfunc
|
|
ELF .size \name, . - \name
|
|
.endfunc
|
|
.purgem endfunc
|
|
.endm
|
|
.text
|
|
.if \export
|
|
.global \name
|
|
.endif
|
|
ELF .type \name, STT_FUNC
|
|
.func \name
|
|
\name:
|
|
.endm
|
|
|
|
func png_read_filter_row_sub4_neon, export=1
|
|
ldr r3, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
1:
|
|
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
|
|
vadd.u8 d0, d3, d4
|
|
vadd.u8 d1, d0, d5
|
|
vadd.u8 d2, d1, d6
|
|
vadd.u8 d3, d2, d7
|
|
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
|
|
subs r3, r3, #16
|
|
bgt 1b
|
|
|
|
bx lr
|
|
endfunc
|
|
|
|
func png_read_filter_row_sub3_neon, export=1
|
|
ldr r3, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
mov r0, r1
|
|
mov r2, #3
|
|
mov r12, #12
|
|
vld1.8 {q11}, [r0], r12
|
|
1:
|
|
vext.8 d5, d22, d23, #3
|
|
vadd.u8 d0, d3, d22
|
|
vext.8 d6, d22, d23, #6
|
|
vadd.u8 d1, d0, d5
|
|
vext.8 d7, d23, d23, #1
|
|
vld1.8 {q11}, [r0], r12
|
|
vst1.32 {d0[0]}, [r1,:32], r2
|
|
vadd.u8 d2, d1, d6
|
|
vst1.32 {d1[0]}, [r1], r2
|
|
vadd.u8 d3, d2, d7
|
|
vst1.32 {d2[0]}, [r1], r2
|
|
vst1.32 {d3[0]}, [r1], r2
|
|
subs r3, r3, #12
|
|
bgt 1b
|
|
|
|
bx lr
|
|
endfunc
|
|
|
|
func png_read_filter_row_up_neon, export=1
|
|
ldr r3, [r0, #4] @ rowbytes
|
|
1:
|
|
vld1.8 {q0}, [r1,:128]
|
|
vld1.8 {q1}, [r2,:128]!
|
|
vadd.u8 q0, q0, q1
|
|
vst1.8 {q0}, [r1,:128]!
|
|
subs r3, r3, #16
|
|
bgt 1b
|
|
|
|
bx lr
|
|
endfunc
|
|
|
|
func png_read_filter_row_avg4_neon, export=1
|
|
ldr r12, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
1:
|
|
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
|
|
vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
|
|
vhadd.u8 d0, d3, d16
|
|
vadd.u8 d0, d0, d4
|
|
vhadd.u8 d1, d0, d17
|
|
vadd.u8 d1, d1, d5
|
|
vhadd.u8 d2, d1, d18
|
|
vadd.u8 d2, d2, d6
|
|
vhadd.u8 d3, d2, d19
|
|
vadd.u8 d3, d3, d7
|
|
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
|
|
subs r12, r12, #16
|
|
bgt 1b
|
|
|
|
bx lr
|
|
endfunc
|
|
|
|
func png_read_filter_row_avg3_neon, export=1
|
|
push {r4,lr}
|
|
ldr r12, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
mov r0, r1
|
|
mov r4, #3
|
|
mov lr, #12
|
|
vld1.8 {q11}, [r0], lr
|
|
1:
|
|
vld1.8 {q10}, [r2], lr
|
|
vext.8 d5, d22, d23, #3
|
|
vhadd.u8 d0, d3, d20
|
|
vext.8 d17, d20, d21, #3
|
|
vadd.u8 d0, d0, d22
|
|
vext.8 d6, d22, d23, #6
|
|
vhadd.u8 d1, d0, d17
|
|
vext.8 d18, d20, d21, #6
|
|
vadd.u8 d1, d1, d5
|
|
vext.8 d7, d23, d23, #1
|
|
vld1.8 {q11}, [r0], lr
|
|
vst1.32 {d0[0]}, [r1,:32], r4
|
|
vhadd.u8 d2, d1, d18
|
|
vst1.32 {d1[0]}, [r1], r4
|
|
vext.8 d19, d21, d21, #1
|
|
vadd.u8 d2, d2, d6
|
|
vhadd.u8 d3, d2, d19
|
|
vst1.32 {d2[0]}, [r1], r4
|
|
vadd.u8 d3, d3, d7
|
|
vst1.32 {d3[0]}, [r1], r4
|
|
subs r12, r12, #12
|
|
bgt 1b
|
|
|
|
pop {r4,pc}
|
|
endfunc
|
|
|
|
.macro paeth rx, ra, rb, rc
|
|
vaddl.u8 q12, \ra, \rb @ a + b
|
|
vaddl.u8 q15, \rc, \rc @ 2*c
|
|
vabdl.u8 q13, \rb, \rc @ pa
|
|
vabdl.u8 q14, \ra, \rc @ pb
|
|
vabd.u16 q15, q12, q15 @ pc
|
|
vcle.u16 q12, q13, q14 @ pa <= pb
|
|
vcle.u16 q13, q13, q15 @ pa <= pc
|
|
vcle.u16 q14, q14, q15 @ pb <= pc
|
|
vand q12, q12, q13 @ pa <= pb && pa <= pc
|
|
vmovn.u16 d28, q14
|
|
vmovn.u16 \rx, q12
|
|
vbsl d28, \rb, \rc
|
|
vbsl \rx, \ra, d28
|
|
.endm
|
|
|
|
func png_read_filter_row_paeth4_neon, export=1
|
|
ldr r12, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
vmov.i8 d20, #0
|
|
1:
|
|
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
|
|
vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
|
|
paeth d0, d3, d16, d20
|
|
vadd.u8 d0, d0, d4
|
|
paeth d1, d0, d17, d16
|
|
vadd.u8 d1, d1, d5
|
|
paeth d2, d1, d18, d17
|
|
vadd.u8 d2, d2, d6
|
|
paeth d3, d2, d19, d18
|
|
vmov d20, d19
|
|
vadd.u8 d3, d3, d7
|
|
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
|
|
subs r12, r12, #16
|
|
bgt 1b
|
|
|
|
bx lr
|
|
endfunc
|
|
|
|
func png_read_filter_row_paeth3_neon, export=1
|
|
push {r4,lr}
|
|
ldr r12, [r0, #4] @ rowbytes
|
|
vmov.i8 d3, #0
|
|
vmov.i8 d4, #0
|
|
mov r0, r1
|
|
mov r4, #3
|
|
mov lr, #12
|
|
vld1.8 {q11}, [r0], lr
|
|
1:
|
|
vld1.8 {q10}, [r2], lr
|
|
paeth d0, d3, d20, d4
|
|
vext.8 d5, d22, d23, #3
|
|
vadd.u8 d0, d0, d22
|
|
vext.8 d17, d20, d21, #3
|
|
paeth d1, d0, d17, d20
|
|
vst1.32 {d0[0]}, [r1,:32], r4
|
|
vext.8 d6, d22, d23, #6
|
|
vadd.u8 d1, d1, d5
|
|
vext.8 d18, d20, d21, #6
|
|
paeth d2, d1, d18, d17
|
|
vext.8 d7, d23, d23, #1
|
|
vld1.8 {q11}, [r0], lr
|
|
vst1.32 {d1[0]}, [r1], r4
|
|
vadd.u8 d2, d2, d6
|
|
vext.8 d19, d21, d21, #1
|
|
paeth d3, d2, d19, d18
|
|
vst1.32 {d2[0]}, [r1], r4
|
|
vmov d4, d19
|
|
vadd.u8 d3, d3, d7
|
|
vst1.32 {d3[0]}, [r1], r4
|
|
subs r12, r12, #12
|
|
bgt 1b
|
|
|
|
pop {r4,pc}
|
|
endfunc
|
|
#endif /* FILTER_OPTIMIZATIONS && __arm__ && __ARM_NEON__ */
|