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