/*
* Copyright © 2018 , VideoLAN and dav1d authors
* Copyright © 2020 , Martin Storsjo
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1 . Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2 . Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
#include "src/arm/asm.S"
#include "util.S"
.macro dir_table w, stride
const directions\w
.byte -1 * \stride + 1 , -2 * \stride + 2
.byte 0 * \stride + 1 , -1 * \stride + 2
.byte 0 * \stride + 1 , 0 * \stride + 2
.byte 0 * \stride + 1 , 1 * \stride + 2
.byte 1 * \stride + 1 , 2 * \stride + 2
.byte 1 * \stride + 0 , 2 * \stride + 1
.byte 1 * \stride + 0 , 2 * \stride + 0
.byte 1 * \stride + 0 , 2 * \stride - 1
// Repeated, to avoid & 7
.byte -1 * \stride + 1 , -2 * \stride + 2
.byte 0 * \stride + 1 , -1 * \stride + 2
.byte 0 * \stride + 1 , 0 * \stride + 2
.byte 0 * \stride + 1 , 1 * \stride + 2
.byte 1 * \stride + 1 , 2 * \stride + 2
.byte 1 * \stride + 0 , 2 * \stride + 1
endconst
.endm
.macro tables
dir_table 8 , 16
dir_table 4 , 8
const pri_taps
.byte 4 , 2 , 3 , 3
endconst
.endm
.macro load_px d11, d12, d21, d22, w
.if \w == 8
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11,\d12}, [r6] // p0
vld1.16 {\d21,\d22}, [r9] // p1
.else
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11}, [r6] // p0
add r6, r6, #2 *8 // += stride
vld1.16 {\d21}, [r9] // p1
add r9, r9, #2 *8 // += stride
vld1.16 {\d12}, [r6] // p0
vld1.16 {\d22}, [r9] // p1
.endif
.endm
.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
.if \min
vmin.u16 q2, q2, \s1
vmax.s16 q3, q3, \s1
vmin.u16 q2, q2, \s2
vmax.s16 q3, q3, \s2
.endif
vabd.u16 q8, q0, \s1 // abs(diff)
vabd.u16 q11, q0, \s2 // abs(diff)
vshl.u16 q9, q8, \shift // abs(diff) >> shift
vshl.u16 q12, q11, \shift // abs(diff) >> shift
vqsub.u16 q9, \thresh_vec, q9 // clip = imax(0 , threshold - (abs(diff) >> shift))
vqsub.u16 q12, \thresh_vec, q12// clip = imax(0 , threshold - (abs(diff) >> shift))
vsub.i16 q10, \s1, q0 // diff = p0 - px
vsub.i16 q13, \s2, q0 // diff = p1 - px
vneg.s16 q8, q9 // -clip
vneg.s16 q11, q12 // -clip
vmin.s16 q10, q10, q9 // imin(diff, clip)
vmin.s16 q13, q13, q12 // imin(diff, clip)
vdup.16 q9, \tap // taps[k]
vmax.s16 q10, q10, q8 // constrain() = imax(imin(diff, clip), -clip)
vmax.s16 q13, q13, q11 // constrain() = imax(imin(diff, clip), -clip)
vmla.i16 q1, q10, q9 // sum += taps[k] * constrain()
vmla.i16 q1, q13, q9 // sum += taps[k] * constrain()
.endm
// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func w, bpc, pri, sec, min, suffix
function cdef_filter\w\suffix\()_\bpc\()bpc_neon
.if \bpc == 8
cmp r8, #0 xf
beq cdef_filter\w\suffix\()_edged_neon
.endif
.if \pri
.if \bpc == 16
clz r9, r9
sub r9, r9, #24 // -bitdepth_min_8
neg r9, r9 // bitdepth_min_8
.endif
movrel_local r8, pri_taps
.if \bpc == 16
lsr r9, r3, r9 // pri_strength >> bitdepth_min_8
and r9, r9, #1 // (pri_strength >> bitdepth_min_8) & 1
.else
and r9, r3, #1
.endif
add r8, r8, r9, lsl #1
.endif
movrel_local r9, directions\w
add r5, r9, r5, lsl #1
vmov.u16 d17, #15
vdup.16 d16, r6 // damping
.if \pri
vdup.16 q5, r3 // threshold
.endif
.if \sec
vdup.16 q7, r4 // threshold
.endif
vmov.16 d8[0 ], r3
vmov.16 d8[1 ], r4
vclz.i16 d8, d8 // clz(threshold)
vsub.i16 d8, d17, d8 // ulog2(threshold)
vqsub.u16 d8, d16, d8 // shift = imax(0 , damping - ulog2(threshold))
vneg.s16 d8, d8 // -shift
.if \sec
vdup.16 q6, d8[1 ]
.endif
.if \pri
vdup.16 q4, d8[0 ]
.endif
1 :
.if \w == 8
vld1.16 {q0}, [r2, :128 ] // px
.else
add r12, r2, #2 *8
vld1.16 {d0}, [r2, :64 ] // px
vld1.16 {d1}, [r12, :64 ] // px
.endif
vmov.u16 q1, #0 // sum
.if \min
vmov.u16 q2, q0 // min
vmov.u16 q3, q0 // max
.endif
// Instead of loading sec_taps 2 , 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov lr, #2 // sec_taps[0 ]
2 :
.if \pri
ldrsb r9, [r5] // off1
load_px d28, d29, d30, d31, \w
.endif
.if \sec
add r5, r5, #4 // +2 *2
ldrsb r9, [r5] // off2
.endif
.if \pri
ldrb r12, [r8] // *pri_taps
handle_pixel q14, q15, q5, q4, r12, \min
.endif
.if \sec
load_px d28, d29, d30, d31, \w
add r5, r5, #8 // +2 *4
ldrsb r9, [r5] // off3
handle_pixel q14, q15, q7, q6, lr, \min
load_px d28, d29, d30, d31, \w
handle_pixel q14, q15, q7, q6, lr, \min
sub r5, r5, #11 // r5 -= 2 *(2 +4 ); r5 += 1 ;
.else
add r5, r5, #1 // r5 += 1
.endif
subs lr, lr, #1 // sec_tap-- (value)
.if \pri
add r8, r8, #1 // pri_taps++ (pointer)
.endif
bne 2 b
vshr.s16 q14, q1, #15 // -(sum < 0 )
vadd.i16 q1, q1, q14 // sum - (sum < 0 )
vrshr.s16 q1, q1, #4 // (8 + sum - (sum < 0 )) >> 4
vadd.i16 q0, q0, q1 // px + (8 + sum ...) >> 4
.if \min
vmin.s16 q0, q0, q3
vmax.s16 q0, q0, q2 // iclip(px + .., min, max)
.endif
.if \bpc == 8
vmovn.u16 d0, q0
.endif
.if \w == 8
add r2, r2, #2 *16 // tmp += tmp_stride
subs r7, r7, #1 // h--
.if \bpc == 8
vst1.8 {d0}, [r0, :64 ], r1
.else
vst1.16 {q0}, [r0, :128 ], r1
.endif
.else
.if \bpc == 8
vst1.32 {d0[0 ]}, [r0, :32 ], r1
.else
vst1.16 {d0}, [r0, :64 ], r1
.endif
add r2, r2, #2 *16 // tmp += 2 *tmp_stride
subs r7, r7, #2 // h -= 2
.if \bpc == 8
vst1.32 {d0[1 ]}, [r0, :32 ], r1
.else
vst1.16 {d1}, [r0, :64 ], r1
.endif
.endif
// Reset pri_taps and directions back to the original point
sub r5, r5, #2
.if \pri
sub r8, r8, #2
.endif
bgt 1 b
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
.endm
.macro filter w, bpc
filter_func \w, \bpc, pri=1 , sec=0 , min=0 , suffix=_pri
filter_func \w, \bpc, pri=0 , sec=1 , min=0 , suffix=_sec
filter_func \w, \bpc, pri=1 , sec=1 , min=1 , suffix=_pri_sec
function cdef_filter\w\()_\bpc\()bpc_neon, export=1
push {r4-r9,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #92 ]
ldrd r6, r7, [sp, #100 ]
.if \bpc == 16
ldrd r8, r9, [sp, #108 ]
.else
ldr r8, [sp, #108 ]
.endif
cmp r3, #0 // pri_strength
bne 1 f
b cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
1 :
cmp r4, #0 // sec_strength
bne 1 f
b cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
1 :
b cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
endfunc
.endm
const div_table, align =4
.short 840 , 420 , 280 , 210 , 168 , 140 , 120 , 105
endconst
const alt_fact, align =4
.short 420 , 210 , 140 , 105 , 105 , 105 , 105 , 105 , 140 , 210 , 420 , 0
endconst
.macro cost_alt dest, s1, s2, s3, s4, s5, s6
vmull.s16 q1, \s1, \s1 // sum_alt[n]*sum_alt[n]
vmull.s16 q2, \s2, \s2
vmull.s16 q3, \s3, \s3
vmull.s16 q5, \s4, \s4 // sum_alt[n]*sum_alt[n]
vmull.s16 q12, \s5, \s5
vmull.s16 q6, \s6, \s6 // q6 overlaps the first \s1-\s2 here
vmul.i32 q1, q1, q13 // sum_alt[n]^2 *fact
vmla.i32 q1, q2, q14
vmla.i32 q1, q3, q15
vmul.i32 q5, q5, q13 // sum_alt[n]^2 *fact
vmla.i32 q5, q12, q14
vmla.i32 q5, q6, q15
vadd.i32 d2, d2, d3
vadd.i32 d3, d10, d11
vpadd.i32 \dest, d2, d3 // *cost_ptr
.endm
.macro find_best s1, s2, s3
.ifnb \s2
vmov.32 lr, \s2
.endif
cmp r12, r1 // cost[n] > best_cost
itt gt
movgt r0, r3 // best_dir = n
movgt r1, r12 // best_cost = cost[n]
.ifnb \s2
add r3, r3, #1 // n++
cmp lr, r1 // cost[n] > best_cost
vmov.32 r12, \s3
itt gt
movgt r0, r3 // best_dir = n
movgt r1, lr // best_cost = cost[n]
add r3, r3, #1 // n++
.endif
.endm
// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
// unsigned *const var)
.macro find_dir bpc
function cdef_find_dir_\bpc\()bpc_neon, export=1
push {lr}
vpush {q4-q7}
.if \bpc == 16
clz r3, r3 // clz(bitdepth_max)
sub lr, r3, #24 // -bitdepth_min_8
.endif
sub sp, sp, #32 // cost
mov r3, #8
vmov.u16 q1, #0 // q0-q1 sum_diag[0 ]
vmov.u16 q3, #0 // q2-q3 sum_diag[1 ]
vmov.u16 q5, #0 // q4-q5 sum_hv[0 -1 ]
vmov.u16 q8, #0 // q6,d16 sum_alt[0 ]
// q7,d17 sum_alt[1 ]
vmov.u16 q9, #0 // q9,d22 sum_alt[2 ]
vmov.u16 q11, #0
vmov.u16 q10, #0 // q10,d23 sum_alt[3 ]
.irpc i, 01234567
.if \bpc == 8
vld1.8 {d30}, [r0, :64 ], r1
vmov.u8 d31, #128
vsubl.u8 q15, d30, d31 // img[x] - 128
.else
vld1.16 {q15}, [r0, :128 ], r1
vdup.16 q14, lr // -bitdepth_min_8
vshl.u16 q15, q15, q14
vmov.u16 q14, #128
vsub.i16 q15, q15, q14 // img[x] - 128
.endif
vmov.u16 q14, #0
.if \i == 0
vmov q0, q15 // sum_diag[0 ]
.else
vext.8 q12, q14, q15, #(16 -2 *\i)
vext.8 q13, q15, q14, #(16 -2 *\i)
vadd.i16 q0, q0, q12 // sum_diag[0 ]
vadd.i16 q1, q1, q13 // sum_diag[0 ]
.endif
vrev64.16 q13, q15
vswp d26, d27 // [-x]
.if \i == 0
vmov q2, q13 // sum_diag[1 ]
.else
vext.8 q12, q14, q13, #(16 -2 *\i)
vext.8 q13, q13, q14, #(16 -2 *\i)
vadd.i16 q2, q2, q12 // sum_diag[1 ]
vadd.i16 q3, q3, q13 // sum_diag[1 ]
.endif
vpadd.u16 d26, d30, d31 // [(x >> 1 )]
vmov.u16 d27, #0
vpadd.u16 d24, d26, d28
vpadd.u16 d24, d24, d28 // [y]
vmov.u16 r12, d24[0 ]
vadd.i16 q5, q5, q15 // sum_hv[1 ]
.if \i < 4
vmov.16 d8[\i], r12 // sum_hv[0 ]
.else
vmov.16 d9[\i-4 ], r12 // sum_hv[0 ]
.endif
.if \i == 0
vmov.u16 q6, q13 // sum_alt[0 ]
.else
vext.8 q12, q14, q13, #(16 -2 *\i)
vext.8 q14, q13, q14, #(16 -2 *\i)
vadd.i16 q6, q6, q12 // sum_alt[0 ]
vadd.i16 d16, d16, d28 // sum_alt[0 ]
.endif
vrev64.16 d26, d26 // [-(x >> 1 )]
vmov.u16 q14, #0
.if \i == 0
vmov q7, q13 // sum_alt[1 ]
.else
vext.8 q12, q14, q13, #(16 -2 *\i)
vext.8 q13, q13, q14, #(16 -2 *\i)
vadd.i16 q7, q7, q12 // sum_alt[1 ]
vadd.i16 d17, d17, d26 // sum_alt[1 ]
.endif
.if \i < 6
vext.8 q12, q14, q15, #(16 -2 *(3 -(\i/2 )))
vext.8 q13, q15, q14, #(16 -2 *(3 -(\i/2 )))
vadd.i16 q9, q9, q12 // sum_alt[2 ]
vadd.i16 d22, d22, d26 // sum_alt[2 ]
.else
vadd.i16 q9, q9, q15 // sum_alt[2 ]
.endif
.if \i == 0
vmov q10, q15 // sum_alt[3 ]
.elseif \i == 1
vadd.i16 q10, q10, q15 // sum_alt[3 ]
.else
vext.8 q12, q14, q15, #(16 -2 *(\i/2 ))
vext.8 q13, q15, q14, #(16 -2 *(\i/2 ))
vadd.i16 q10, q10, q12 // sum_alt[3 ]
vadd.i16 d23, d23, d26 // sum_alt[3 ]
.endif
.endr
vmov.u32 q15, #105
vmull.s16 q12, d8, d8 // sum_hv[0 ]*sum_hv[0 ]
vmlal.s16 q12, d9, d9
vmull.s16 q13, d10, d10 // sum_hv[1 ]*sum_hv[1 ]
vmlal.s16 q13, d11, d11
vadd.s32 d8, d24, d25
vadd.s32 d9, d26, d27
vpadd.s32 d8, d8, d9 // cost[2 ,6 ] (s16, s17)
vmul.i32 d8, d8, d30 // cost[2 ,6 ] *= 105
vrev64.16 q1, q1
vrev64.16 q3, q3
vext.8 q1, q1, q1, #10 // sum_diag[0 ][14 -n]
vext.8 q3, q3, q3, #10 // sum_diag[1 ][14 -n]
vstr s16, [sp, #2 *4 ] // cost[2 ]
vstr s17, [sp, #6 *4 ] // cost[6 ]
movrel_local r12, div_table
vld1.16 {q14}, [r12, :128 ]
vmull.s16 q5, d0, d0 // sum_diag[0 ]*sum_diag[0 ]
vmull.s16 q12, d1, d1
vmlal.s16 q5, d2, d2
vmlal.s16 q12, d3, d3
vmull.s16 q0, d4, d4 // sum_diag[1 ]*sum_diag[1 ]
vmull.s16 q1, d5, d5
vmlal.s16 q0, d6, d6
vmlal.s16 q1, d7, d7
vmovl.u16 q13, d28 // div_table
vmovl.u16 q14, d29
vmul.i32 q5, q5, q13 // cost[0 ]
vmla.i32 q5, q12, q14
vmul.i32 q0, q0, q13 // cost[4 ]
vmla.i32 q0, q1, q14
vadd.i32 d10, d10, d11
vadd.i32 d0, d0, d1
vpadd.i32 d0, d10, d0 // cost[0 ,4 ] = s0,s1
movrel_local r12, alt_fact
vld1.16 {d29, d30, d31}, [r12, :64 ] // div_table[2 *m+1 ] + 105
vstr s0, [sp, #0 *4 ] // cost[0 ]
vstr s1, [sp, #4 *4 ] // cost[4 ]
vmovl.u16 q13, d29 // div_table[2 *m+1 ] + 105
vmovl.u16 q14, d30
vmovl.u16 q15, d31
cost_alt d14, d12, d13, d16, d14, d15, d17 // cost[1 ], cost[3 ]
cost_alt d15, d18, d19, d22, d20, d21, d23 // cost[5 ], cost[7 ]
vstr s28, [sp, #1 *4 ] // cost[1 ]
vstr s29, [sp, #3 *4 ] // cost[3 ]
mov r0, #0 // best_dir
vmov.32 r1, d0[0 ] // best_cost
mov r3, #1 // n
vstr s30, [sp, #5 *4 ] // cost[5 ]
vstr s31, [sp, #7 *4 ] // cost[7 ]
vmov.32 r12, d14[0 ]
find_best d14[0 ], d8[0 ], d14[1 ]
find_best d14[1 ], d0[1 ], d15[0 ]
find_best d15[0 ], d8[1 ], d15[1 ]
find_best d15[1 ]
eor r3, r0, #4 // best_dir ^4
ldr r12, [sp, r3, lsl #2 ]
sub r1, r1, r12 // best_cost - cost[best_dir ^ 4 ]
lsr r1, r1, #10
str r1, [r2] // *var
add sp, sp, #32
vpop {q4-q7}
pop {pc}
endfunc
.endm
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland