xref: /aosp_15_r20/external/libdav1d/src/arm/32/cdef_tmpl.S (revision c09093415860a1c2373dacd84c4fde00c507cdfd)
1/*
2 * Copyright © 2018, VideoLAN and dav1d authors
3 * Copyright © 2020, Martin Storsjo
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this
10 *    list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 *    this list of conditions and the following disclaimer in the documentation
14 *    and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "src/arm/asm.S"
29#include "util.S"
30
31.macro dir_table w, stride
32const directions\w
33        .byte           -1 * \stride + 1, -2 * \stride + 2
34        .byte            0 * \stride + 1, -1 * \stride + 2
35        .byte            0 * \stride + 1,  0 * \stride + 2
36        .byte            0 * \stride + 1,  1 * \stride + 2
37        .byte            1 * \stride + 1,  2 * \stride + 2
38        .byte            1 * \stride + 0,  2 * \stride + 1
39        .byte            1 * \stride + 0,  2 * \stride + 0
40        .byte            1 * \stride + 0,  2 * \stride - 1
41// Repeated, to avoid & 7
42        .byte           -1 * \stride + 1, -2 * \stride + 2
43        .byte            0 * \stride + 1, -1 * \stride + 2
44        .byte            0 * \stride + 1,  0 * \stride + 2
45        .byte            0 * \stride + 1,  1 * \stride + 2
46        .byte            1 * \stride + 1,  2 * \stride + 2
47        .byte            1 * \stride + 0,  2 * \stride + 1
48endconst
49.endm
50
51.macro tables
52dir_table 8, 16
53dir_table 4, 8
54
55const pri_taps
56        .byte           4, 2, 3, 3
57endconst
58.endm
59
60.macro load_px d11, d12, d21, d22, w
61.if \w == 8
62        add             r6,  r2,  r9, lsl #1 // x + off
63        sub             r9,  r2,  r9, lsl #1 // x - off
64        vld1.16         {\d11,\d12}, [r6]    // p0
65        vld1.16         {\d21,\d22}, [r9]    // p1
66.else
67        add             r6,  r2,  r9, lsl #1 // x + off
68        sub             r9,  r2,  r9, lsl #1 // x - off
69        vld1.16         {\d11}, [r6]         // p0
70        add             r6,  r6,  #2*8       // += stride
71        vld1.16         {\d21}, [r9]         // p1
72        add             r9,  r9,  #2*8       // += stride
73        vld1.16         {\d12}, [r6]         // p0
74        vld1.16         {\d22}, [r9]         // p1
75.endif
76.endm
77.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
78.if \min
79        vmin.u16        q2,  q2,  \s1
80        vmax.s16        q3,  q3,  \s1
81        vmin.u16        q2,  q2,  \s2
82        vmax.s16        q3,  q3,  \s2
83.endif
84        vabd.u16        q8,  q0,  \s1        // abs(diff)
85        vabd.u16        q11, q0,  \s2        // abs(diff)
86        vshl.u16        q9,  q8,  \shift     // abs(diff) >> shift
87        vshl.u16        q12, q11, \shift     // abs(diff) >> shift
88        vqsub.u16       q9,  \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
89        vqsub.u16       q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
90        vsub.i16        q10, \s1, q0         // diff = p0 - px
91        vsub.i16        q13, \s2, q0         // diff = p1 - px
92        vneg.s16        q8,  q9              // -clip
93        vneg.s16        q11, q12             // -clip
94        vmin.s16        q10, q10, q9         // imin(diff, clip)
95        vmin.s16        q13, q13, q12        // imin(diff, clip)
96        vdup.16         q9,  \tap            // taps[k]
97        vmax.s16        q10, q10, q8         // constrain() = imax(imin(diff, clip), -clip)
98        vmax.s16        q13, q13, q11        // constrain() = imax(imin(diff, clip), -clip)
99        vmla.i16        q1,  q10, q9         // sum += taps[k] * constrain()
100        vmla.i16        q1,  q13, q9         // sum += taps[k] * constrain()
101.endm
102
103// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
104//                                   const uint16_t *tmp, int pri_strength,
105//                                   int sec_strength, int dir, int damping,
106//                                   int h, size_t edges);
107.macro filter_func w, bpc, pri, sec, min, suffix
108function cdef_filter\w\suffix\()_\bpc\()bpc_neon
109.if \bpc == 8
110        cmp             r8,  #0xf
111        beq             cdef_filter\w\suffix\()_edged_neon
112.endif
113.if \pri
114.if \bpc == 16
115        clz             r9,  r9
116        sub             r9,  r9,  #24        // -bitdepth_min_8
117        neg             r9,  r9              // bitdepth_min_8
118.endif
119        movrel_local    r8,  pri_taps
120.if \bpc == 16
121        lsr             r9,  r3,  r9         // pri_strength >> bitdepth_min_8
122        and             r9,  r9,  #1         // (pri_strength >> bitdepth_min_8) & 1
123.else
124        and             r9,  r3,  #1
125.endif
126        add             r8,  r8,  r9, lsl #1
127.endif
128        movrel_local    r9,  directions\w
129        add             r5,  r9,  r5, lsl #1
130        vmov.u16        d17, #15
131        vdup.16         d16, r6              // damping
132
133.if \pri
134        vdup.16         q5,  r3              // threshold
135.endif
136.if \sec
137        vdup.16         q7,  r4              // threshold
138.endif
139        vmov.16         d8[0], r3
140        vmov.16         d8[1], r4
141        vclz.i16        d8,  d8              // clz(threshold)
142        vsub.i16        d8,  d17, d8         // ulog2(threshold)
143        vqsub.u16       d8,  d16, d8         // shift = imax(0, damping - ulog2(threshold))
144        vneg.s16        d8,  d8              // -shift
145.if \sec
146        vdup.16         q6,  d8[1]
147.endif
148.if \pri
149        vdup.16         q4,  d8[0]
150.endif
151
1521:
153.if \w == 8
154        vld1.16         {q0},  [r2, :128]    // px
155.else
156        add             r12, r2,  #2*8
157        vld1.16         {d0},  [r2,  :64]    // px
158        vld1.16         {d1},  [r12, :64]    // px
159.endif
160
161        vmov.u16        q1,  #0              // sum
162.if \min
163        vmov.u16        q2,  q0              // min
164        vmov.u16        q3,  q0              // max
165.endif
166
167        // Instead of loading sec_taps 2, 1 from memory, just set it
168        // to 2 initially and decrease for the second round.
169        // This is also used as loop counter.
170        mov             lr,  #2              // sec_taps[0]
171
1722:
173.if \pri
174        ldrsb           r9,  [r5]            // off1
175
176        load_px         d28, d29, d30, d31, \w
177.endif
178
179.if \sec
180        add             r5,  r5,  #4         // +2*2
181        ldrsb           r9,  [r5]            // off2
182.endif
183
184.if \pri
185        ldrb            r12, [r8]            // *pri_taps
186
187        handle_pixel    q14, q15, q5,  q4,  r12, \min
188.endif
189
190.if \sec
191        load_px         d28, d29, d30, d31, \w
192
193        add             r5,  r5,  #8         // +2*4
194        ldrsb           r9,  [r5]            // off3
195
196        handle_pixel    q14, q15, q7,  q6,  lr, \min
197
198        load_px         d28, d29, d30, d31, \w
199
200        handle_pixel    q14, q15, q7,  q6,  lr, \min
201
202        sub             r5,  r5,  #11        // r5 -= 2*(2+4); r5 += 1;
203.else
204        add             r5,  r5,  #1         // r5 += 1
205.endif
206        subs            lr,  lr,  #1         // sec_tap-- (value)
207.if \pri
208        add             r8,  r8,  #1         // pri_taps++ (pointer)
209.endif
210        bne             2b
211
212        vshr.s16        q14, q1,  #15        // -(sum < 0)
213        vadd.i16        q1,  q1,  q14        // sum - (sum < 0)
214        vrshr.s16       q1,  q1,  #4         // (8 + sum - (sum < 0)) >> 4
215        vadd.i16        q0,  q0,  q1         // px + (8 + sum ...) >> 4
216.if \min
217        vmin.s16        q0,  q0,  q3
218        vmax.s16        q0,  q0,  q2         // iclip(px + .., min, max)
219.endif
220.if \bpc == 8
221        vmovn.u16       d0,  q0
222.endif
223.if \w == 8
224        add             r2,  r2,  #2*16      // tmp += tmp_stride
225        subs            r7,  r7,  #1         // h--
226.if \bpc == 8
227        vst1.8          {d0}, [r0, :64], r1
228.else
229        vst1.16         {q0}, [r0, :128], r1
230.endif
231.else
232.if \bpc == 8
233        vst1.32         {d0[0]}, [r0, :32], r1
234.else
235        vst1.16         {d0},    [r0, :64], r1
236.endif
237        add             r2,  r2,  #2*16      // tmp += 2*tmp_stride
238        subs            r7,  r7,  #2         // h -= 2
239.if \bpc == 8
240        vst1.32         {d0[1]}, [r0, :32], r1
241.else
242        vst1.16         {d1},    [r0, :64], r1
243.endif
244.endif
245
246        // Reset pri_taps and directions back to the original point
247        sub             r5,  r5,  #2
248.if \pri
249        sub             r8,  r8,  #2
250.endif
251
252        bgt             1b
253        vpop            {q4-q7}
254        pop             {r4-r9,pc}
255endfunc
256.endm
257
258.macro filter w, bpc
259filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
260filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
261filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
262
263function cdef_filter\w\()_\bpc\()bpc_neon, export=1
264        push            {r4-r9,lr}
265        vpush           {q4-q7}
266        ldrd            r4,  r5,  [sp, #92]
267        ldrd            r6,  r7,  [sp, #100]
268.if \bpc == 16
269        ldrd            r8,  r9,  [sp, #108]
270.else
271        ldr             r8,  [sp, #108]
272.endif
273        cmp             r3,  #0 // pri_strength
274        bne             1f
275        b               cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
2761:
277        cmp             r4,  #0 // sec_strength
278        bne             1f
279        b               cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
2801:
281        b               cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
282endfunc
283.endm
284
285const div_table, align=4
286        .short         840, 420, 280, 210, 168, 140, 120, 105
287endconst
288
289const alt_fact, align=4
290        .short         420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
291endconst
292
293.macro cost_alt dest, s1, s2, s3, s4, s5, s6
294        vmull.s16       q1,  \s1, \s1          // sum_alt[n]*sum_alt[n]
295        vmull.s16       q2,  \s2, \s2
296        vmull.s16       q3,  \s3, \s3
297        vmull.s16       q5,  \s4, \s4          // sum_alt[n]*sum_alt[n]
298        vmull.s16       q12, \s5, \s5
299        vmull.s16       q6,  \s6, \s6          // q6 overlaps the first \s1-\s2 here
300        vmul.i32        q1,  q1,  q13          // sum_alt[n]^2*fact
301        vmla.i32        q1,  q2,  q14
302        vmla.i32        q1,  q3,  q15
303        vmul.i32        q5,  q5,  q13          // sum_alt[n]^2*fact
304        vmla.i32        q5,  q12, q14
305        vmla.i32        q5,  q6,  q15
306        vadd.i32        d2,  d2,  d3
307        vadd.i32        d3,  d10, d11
308        vpadd.i32       \dest, d2, d3          // *cost_ptr
309.endm
310
311.macro find_best s1, s2, s3
312.ifnb \s2
313        vmov.32         lr,  \s2
314.endif
315        cmp             r12, r1                // cost[n] > best_cost
316        itt             gt
317        movgt           r0,  r3                // best_dir = n
318        movgt           r1,  r12               // best_cost = cost[n]
319.ifnb \s2
320        add             r3,  r3,  #1           // n++
321        cmp             lr,  r1                // cost[n] > best_cost
322        vmov.32         r12, \s3
323        itt             gt
324        movgt           r0,  r3                // best_dir = n
325        movgt           r1,  lr                // best_cost = cost[n]
326        add             r3,  r3,  #1           // n++
327.endif
328.endm
329
330// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
331//                                   unsigned *const var)
332.macro find_dir bpc
333function cdef_find_dir_\bpc\()bpc_neon, export=1
334        push            {lr}
335        vpush           {q4-q7}
336.if \bpc == 16
337        clz             r3,  r3                // clz(bitdepth_max)
338        sub             lr,  r3,  #24          // -bitdepth_min_8
339.endif
340        sub             sp,  sp,  #32          // cost
341        mov             r3,  #8
342        vmov.u16        q1,  #0                // q0-q1   sum_diag[0]
343        vmov.u16        q3,  #0                // q2-q3   sum_diag[1]
344        vmov.u16        q5,  #0                // q4-q5   sum_hv[0-1]
345        vmov.u16        q8,  #0                // q6,d16  sum_alt[0]
346                                               // q7,d17  sum_alt[1]
347        vmov.u16        q9,  #0                // q9,d22  sum_alt[2]
348        vmov.u16        q11, #0
349        vmov.u16        q10, #0                // q10,d23 sum_alt[3]
350
351
352.irpc i, 01234567
353.if \bpc == 8
354        vld1.8          {d30}, [r0, :64], r1
355        vmov.u8         d31, #128
356        vsubl.u8        q15, d30, d31          // img[x] - 128
357.else
358        vld1.16         {q15}, [r0, :128], r1
359        vdup.16         q14, lr                // -bitdepth_min_8
360        vshl.u16        q15, q15, q14
361        vmov.u16        q14, #128
362        vsub.i16        q15, q15, q14          // img[x] - 128
363.endif
364        vmov.u16        q14, #0
365
366.if \i == 0
367        vmov            q0,  q15               // sum_diag[0]
368.else
369        vext.8          q12, q14, q15, #(16-2*\i)
370        vext.8          q13, q15, q14, #(16-2*\i)
371        vadd.i16        q0,  q0,  q12          // sum_diag[0]
372        vadd.i16        q1,  q1,  q13          // sum_diag[0]
373.endif
374        vrev64.16       q13, q15
375        vswp            d26, d27               // [-x]
376.if \i == 0
377        vmov            q2,  q13               // sum_diag[1]
378.else
379        vext.8          q12, q14, q13, #(16-2*\i)
380        vext.8          q13, q13, q14, #(16-2*\i)
381        vadd.i16        q2,  q2,  q12          // sum_diag[1]
382        vadd.i16        q3,  q3,  q13          // sum_diag[1]
383.endif
384
385        vpadd.u16       d26, d30, d31          // [(x >> 1)]
386        vmov.u16        d27, #0
387        vpadd.u16       d24, d26, d28
388        vpadd.u16       d24, d24, d28          // [y]
389        vmov.u16        r12, d24[0]
390        vadd.i16        q5,  q5,  q15          // sum_hv[1]
391.if \i < 4
392        vmov.16         d8[\i],   r12          // sum_hv[0]
393.else
394        vmov.16         d9[\i-4], r12          // sum_hv[0]
395.endif
396
397.if \i == 0
398        vmov.u16        q6,  q13               // sum_alt[0]
399.else
400        vext.8          q12, q14, q13, #(16-2*\i)
401        vext.8          q14, q13, q14, #(16-2*\i)
402        vadd.i16        q6,  q6,  q12          // sum_alt[0]
403        vadd.i16        d16, d16, d28          // sum_alt[0]
404.endif
405        vrev64.16       d26, d26               // [-(x >> 1)]
406        vmov.u16        q14, #0
407.if \i == 0
408        vmov            q7,  q13               // sum_alt[1]
409.else
410        vext.8          q12, q14, q13, #(16-2*\i)
411        vext.8          q13, q13, q14, #(16-2*\i)
412        vadd.i16        q7,  q7,  q12          // sum_alt[1]
413        vadd.i16        d17, d17, d26          // sum_alt[1]
414.endif
415
416.if \i < 6
417        vext.8          q12, q14, q15, #(16-2*(3-(\i/2)))
418        vext.8          q13, q15, q14, #(16-2*(3-(\i/2)))
419        vadd.i16        q9,  q9,  q12          // sum_alt[2]
420        vadd.i16        d22, d22, d26          // sum_alt[2]
421.else
422        vadd.i16        q9,  q9,  q15          // sum_alt[2]
423.endif
424.if \i == 0
425        vmov            q10, q15               // sum_alt[3]
426.elseif \i == 1
427        vadd.i16        q10, q10, q15          // sum_alt[3]
428.else
429        vext.8          q12, q14, q15, #(16-2*(\i/2))
430        vext.8          q13, q15, q14, #(16-2*(\i/2))
431        vadd.i16        q10, q10, q12          // sum_alt[3]
432        vadd.i16        d23, d23, d26          // sum_alt[3]
433.endif
434.endr
435
436        vmov.u32        q15, #105
437
438        vmull.s16       q12, d8,  d8           // sum_hv[0]*sum_hv[0]
439        vmlal.s16       q12, d9,  d9
440        vmull.s16       q13, d10, d10          // sum_hv[1]*sum_hv[1]
441        vmlal.s16       q13, d11, d11
442        vadd.s32        d8,  d24, d25
443        vadd.s32        d9,  d26, d27
444        vpadd.s32       d8,  d8,  d9           // cost[2,6] (s16, s17)
445        vmul.i32        d8,  d8,  d30          // cost[2,6] *= 105
446
447        vrev64.16       q1,  q1
448        vrev64.16       q3,  q3
449        vext.8          q1,  q1,  q1,  #10     // sum_diag[0][14-n]
450        vext.8          q3,  q3,  q3,  #10     // sum_diag[1][14-n]
451
452        vstr            s16, [sp, #2*4]        // cost[2]
453        vstr            s17, [sp, #6*4]        // cost[6]
454
455        movrel_local    r12, div_table
456        vld1.16         {q14}, [r12, :128]
457
458        vmull.s16       q5,  d0,  d0           // sum_diag[0]*sum_diag[0]
459        vmull.s16       q12, d1,  d1
460        vmlal.s16       q5,  d2,  d2
461        vmlal.s16       q12, d3,  d3
462        vmull.s16       q0,  d4,  d4           // sum_diag[1]*sum_diag[1]
463        vmull.s16       q1,  d5,  d5
464        vmlal.s16       q0,  d6,  d6
465        vmlal.s16       q1,  d7,  d7
466        vmovl.u16       q13, d28               // div_table
467        vmovl.u16       q14, d29
468        vmul.i32        q5,  q5,  q13          // cost[0]
469        vmla.i32        q5,  q12, q14
470        vmul.i32        q0,  q0,  q13          // cost[4]
471        vmla.i32        q0,  q1,  q14
472        vadd.i32        d10, d10, d11
473        vadd.i32        d0,  d0,  d1
474        vpadd.i32       d0,  d10, d0           // cost[0,4] = s0,s1
475
476        movrel_local    r12, alt_fact
477        vld1.16         {d29, d30, d31}, [r12, :64] // div_table[2*m+1] + 105
478
479        vstr            s0,  [sp, #0*4]        // cost[0]
480        vstr            s1,  [sp, #4*4]        // cost[4]
481
482        vmovl.u16       q13, d29               // div_table[2*m+1] + 105
483        vmovl.u16       q14, d30
484        vmovl.u16       q15, d31
485
486        cost_alt        d14, d12, d13, d16, d14, d15, d17 // cost[1], cost[3]
487        cost_alt        d15, d18, d19, d22, d20, d21, d23 // cost[5], cost[7]
488        vstr            s28, [sp, #1*4]        // cost[1]
489        vstr            s29, [sp, #3*4]        // cost[3]
490
491        mov             r0,  #0                // best_dir
492        vmov.32         r1,  d0[0]             // best_cost
493        mov             r3,  #1                // n
494
495        vstr            s30, [sp, #5*4]        // cost[5]
496        vstr            s31, [sp, #7*4]        // cost[7]
497
498        vmov.32         r12, d14[0]
499
500        find_best       d14[0], d8[0], d14[1]
501        find_best       d14[1], d0[1], d15[0]
502        find_best       d15[0], d8[1], d15[1]
503        find_best       d15[1]
504
505        eor             r3,  r0,  #4           // best_dir ^4
506        ldr             r12, [sp, r3, lsl #2]
507        sub             r1,  r1,  r12          // best_cost - cost[best_dir ^ 4]
508        lsr             r1,  r1,  #10
509        str             r1,  [r2]              // *var
510
511        add             sp,  sp,  #32
512        vpop            {q4-q7}
513        pop             {pc}
514endfunc
515.endm
516