1 ; 2 ; Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 ; 4 ; Use of this source code is governed by a BSD-style license 5 ; that can be found in the LICENSE file in the root of the source 6 ; tree. An additional intellectual property rights grant can be found 7 ; in the file PATENTS. All contributing project authors may 8 ; be found in the AUTHORS file in the root of the source tree. 9 ; 10 11 12 EXPORT |vp8_sixtap_predict16x16_neon| 13 ARM 14 REQUIRE8 15 PRESERVE8 16 17 AREA ||.text||, CODE, READONLY, ALIGN=2 18 19 filter16_coeff 20 DCD 0, 0, 128, 0, 0, 0, 0, 0 21 DCD 0, -6, 123, 12, -1, 0, 0, 0 22 DCD 2, -11, 108, 36, -8, 1, 0, 0 23 DCD 0, -9, 93, 50, -6, 0, 0, 0 24 DCD 3, -16, 77, 77, -16, 3, 0, 0 25 DCD 0, -6, 50, 93, -9, 0, 0, 0 26 DCD 1, -8, 36, 108, -11, 2, 0, 0 27 DCD 0, -1, 12, 123, -6, 0, 0, 0 28 29 ;----------------- 30 ; r0 unsigned char *src_ptr, 31 ; r1 int src_pixels_per_line, 32 ; r2 int xoffset, 33 ; r3 int yoffset, 34 ; r4 unsigned char *dst_ptr, 35 ; stack(r5) int dst_pitch 36 37 ;Note: To take advantage of 8-bit mulplication instruction in NEON. First apply abs() to 38 ; filter coeffs to make them u8. Then, use vmlsl for negtive coeffs. After multiplication, 39 ; the result can be negtive. So, I treat the result as s16. But, since it is also possible 40 ; that the result can be a large positive number (> 2^15-1), which could be confused as a 41 ; negtive number. To avoid that error, apply filter coeffs in the order of 0, 1, 4 ,5 ,2, 42 ; which ensures that the result stays in s16 range. Finally, saturated add the result by 43 ; applying 3rd filter coeff. Same applys to other filter functions. 44 45 |vp8_sixtap_predict16x16_neon| PROC 46 push {r4-r5, lr} 47 48 adr r12, filter16_coeff 49 ldr r4, [sp, #12] ;load parameters from stack 50 ldr r5, [sp, #16] ;load parameters from stack 51 52 cmp r2, #0 ;skip first_pass filter if xoffset=0 53 beq secondpass_filter16x16_only 54 55 add r2, r12, r2, lsl #5 ;calculate filter location 56 57 cmp r3, #0 ;skip second_pass filter if yoffset=0 58 59 vld1.s32 {q14, q15}, [r2] ;load first_pass filter 60 61 beq firstpass_filter16x16_only 62 63 sub sp, sp, #336 ;reserve space on stack for temporary storage 64 mov lr, sp 65 66 vabs.s32 q12, q14 67 vabs.s32 q13, q15 68 69 mov r2, #7 ;loop counter 70 sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) 71 sub r0, r0, r1, lsl #1 72 73 vdup.8 d0, d24[0] ;first_pass filter (d0-d5) 74 vdup.8 d1, d24[4] 75 vdup.8 d2, d25[0] 76 vdup.8 d3, d25[4] 77 vdup.8 d4, d26[0] 78 vdup.8 d5, d26[4] 79 80 ;First Pass: output_height lines x output_width columns (21x16) 81 filt_blk2d_fp16x16_loop_neon 82 vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data 83 vld1.u8 {d9, d10, d11}, [r0], r1 84 vld1.u8 {d12, d13, d14}, [r0], r1 85 86 pld [r0] 87 pld [r0, r1] 88 pld [r0, r1, lsl #1] 89 90 vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) 91 vmull.u8 q9, d7, d0 92 vmull.u8 q10, d9, d0 93 vmull.u8 q11, d10, d0 94 vmull.u8 q12, d12, d0 95 vmull.u8 q13, d13, d0 96 97 vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] 98 vext.8 d29, d9, d10, #1 99 vext.8 d30, d12, d13, #1 100 101 vmlsl.u8 q8, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) 102 vmlsl.u8 q10, d29, d1 103 vmlsl.u8 q12, d30, d1 104 105 vext.8 d28, d7, d8, #1 106 vext.8 d29, d10, d11, #1 107 vext.8 d30, d13, d14, #1 108 109 vmlsl.u8 q9, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) 110 vmlsl.u8 q11, d29, d1 111 vmlsl.u8 q13, d30, d1 112 113 vext.8 d28, d6, d7, #4 ;construct src_ptr[2] 114 vext.8 d29, d9, d10, #4 115 vext.8 d30, d12, d13, #4 116 117 vmlsl.u8 q8, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) 118 vmlsl.u8 q10, d29, d4 119 vmlsl.u8 q12, d30, d4 120 121 vext.8 d28, d7, d8, #4 122 vext.8 d29, d10, d11, #4 123 vext.8 d30, d13, d14, #4 124 125 vmlsl.u8 q9, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) 126 vmlsl.u8 q11, d29, d4 127 vmlsl.u8 q13, d30, d4 128 129 vext.8 d28, d6, d7, #5 ;construct src_ptr[3] 130 vext.8 d29, d9, d10, #5 131 vext.8 d30, d12, d13, #5 132 133 vmlal.u8 q8, d28, d5 ;(src_ptr[3] * vp8_filter[5]) 134 vmlal.u8 q10, d29, d5 135 vmlal.u8 q12, d30, d5 136 137 vext.8 d28, d7, d8, #5 138 vext.8 d29, d10, d11, #5 139 vext.8 d30, d13, d14, #5 140 141 vmlal.u8 q9, d28, d5 ;(src_ptr[3] * vp8_filter[5]) 142 vmlal.u8 q11, d29, d5 143 vmlal.u8 q13, d30, d5 144 145 vext.8 d28, d6, d7, #2 ;construct src_ptr[0] 146 vext.8 d29, d9, d10, #2 147 vext.8 d30, d12, d13, #2 148 149 vmlal.u8 q8, d28, d2 ;(src_ptr[0] * vp8_filter[2]) 150 vmlal.u8 q10, d29, d2 151 vmlal.u8 q12, d30, d2 152 153 vext.8 d28, d7, d8, #2 154 vext.8 d29, d10, d11, #2 155 vext.8 d30, d13, d14, #2 156 157 vmlal.u8 q9, d28, d2 ;(src_ptr[0] * vp8_filter[2]) 158 vmlal.u8 q11, d29, d2 159 vmlal.u8 q13, d30, d2 160 161 vext.8 d28, d6, d7, #3 ;construct src_ptr[1] 162 vext.8 d29, d9, d10, #3 163 vext.8 d30, d12, d13, #3 164 165 vext.8 d15, d7, d8, #3 166 vext.8 d31, d10, d11, #3 167 vext.8 d6, d13, d14, #3 168 169 vmull.u8 q4, d28, d3 ;(src_ptr[1] * vp8_filter[3]) 170 vmull.u8 q5, d29, d3 171 vmull.u8 q6, d30, d3 172 173 vqadd.s16 q8, q4 ;sum of all (src_data*filter_parameters) 174 vqadd.s16 q10, q5 175 vqadd.s16 q12, q6 176 177 vmull.u8 q6, d15, d3 ;(src_ptr[1] * vp8_filter[3]) 178 vmull.u8 q7, d31, d3 179 vmull.u8 q3, d6, d3 180 181 subs r2, r2, #1 182 183 vqadd.s16 q9, q6 184 vqadd.s16 q11, q7 185 vqadd.s16 q13, q3 186 187 vqrshrun.s16 d6, q8, #7 ;shift/round/saturate to u8 188 vqrshrun.s16 d7, q9, #7 189 vqrshrun.s16 d8, q10, #7 190 vqrshrun.s16 d9, q11, #7 191 vqrshrun.s16 d10, q12, #7 192 vqrshrun.s16 d11, q13, #7 193 194 vst1.u8 {d6, d7, d8}, [lr]! ;store result 195 vst1.u8 {d9, d10, d11}, [lr]! 196 197 bne filt_blk2d_fp16x16_loop_neon 198 199 ;Second pass: 16x16 200 ;secondpass_filter - do first 8-columns and then second 8-columns 201 add r3, r12, r3, lsl #5 202 sub lr, lr, #336 203 204 vld1.s32 {q5, q6}, [r3] ;load second_pass filter 205 mov r3, #2 ;loop counter 206 207 vabs.s32 q7, q5 208 vabs.s32 q8, q6 209 210 mov r2, #16 211 212 vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) 213 vdup.8 d1, d14[4] 214 vdup.8 d2, d15[0] 215 vdup.8 d3, d15[4] 216 vdup.8 d4, d16[0] 217 vdup.8 d5, d16[4] 218 219 filt_blk2d_sp16x16_outloop_neon 220 vld1.u8 {d18}, [lr], r2 ;load src data 221 vld1.u8 {d19}, [lr], r2 222 vld1.u8 {d20}, [lr], r2 223 vld1.u8 {d21}, [lr], r2 224 mov r12, #4 ;loop counter 225 vld1.u8 {d22}, [lr], r2 226 227 secondpass_inner_loop_neon 228 vld1.u8 {d23}, [lr], r2 ;load src data 229 vld1.u8 {d24}, [lr], r2 230 vld1.u8 {d25}, [lr], r2 231 vld1.u8 {d26}, [lr], r2 232 233 vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) 234 vmull.u8 q4, d19, d0 235 vmull.u8 q5, d20, d0 236 vmull.u8 q6, d21, d0 237 238 vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) 239 vmlsl.u8 q4, d20, d1 240 vmlsl.u8 q5, d21, d1 241 vmlsl.u8 q6, d22, d1 242 243 vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) 244 vmlsl.u8 q4, d23, d4 245 vmlsl.u8 q5, d24, d4 246 vmlsl.u8 q6, d25, d4 247 248 vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) 249 vmlal.u8 q4, d21, d2 250 vmlal.u8 q5, d22, d2 251 vmlal.u8 q6, d23, d2 252 253 vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) 254 vmlal.u8 q4, d24, d5 255 vmlal.u8 q5, d25, d5 256 vmlal.u8 q6, d26, d5 257 258 vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) 259 vmull.u8 q8, d22, d3 260 vmull.u8 q9, d23, d3 261 vmull.u8 q10, d24, d3 262 263 subs r12, r12, #1 264 265 vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) 266 vqadd.s16 q8, q4 267 vqadd.s16 q9, q5 268 vqadd.s16 q10, q6 269 270 vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 271 vqrshrun.s16 d7, q8, #7 272 vqrshrun.s16 d8, q9, #7 273 vqrshrun.s16 d9, q10, #7 274 275 vst1.u8 {d6}, [r4], r5 ;store result 276 vmov q9, q11 277 vst1.u8 {d7}, [r4], r5 278 vmov q10, q12 279 vst1.u8 {d8}, [r4], r5 280 vmov d22, d26 281 vst1.u8 {d9}, [r4], r5 282 283 bne secondpass_inner_loop_neon 284 285 subs r3, r3, #1 286 sub lr, lr, #336 287 add lr, lr, #8 288 289 sub r4, r4, r5, lsl #4 290 add r4, r4, #8 291 292 bne filt_blk2d_sp16x16_outloop_neon 293 294 add sp, sp, #336 295 pop {r4-r5,pc} 296 297 ;-------------------- 298 firstpass_filter16x16_only 299 vabs.s32 q12, q14 300 vabs.s32 q13, q15 301 302 mov r2, #8 ;loop counter 303 sub r0, r0, #2 ;move srcptr back to (column-2) 304 305 vdup.8 d0, d24[0] ;first_pass filter (d0-d5) 306 vdup.8 d1, d24[4] 307 vdup.8 d2, d25[0] 308 vdup.8 d3, d25[4] 309 vdup.8 d4, d26[0] 310 vdup.8 d5, d26[4] 311 312 ;First Pass: output_height lines x output_width columns (16x16) 313 filt_blk2d_fpo16x16_loop_neon 314 vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data 315 vld1.u8 {d9, d10, d11}, [r0], r1 316 317 pld [r0] 318 pld [r0, r1] 319 320 vmull.u8 q6, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) 321 vmull.u8 q7, d7, d0 322 vmull.u8 q8, d9, d0 323 vmull.u8 q9, d10, d0 324 325 vext.8 d20, d6, d7, #1 ;construct src_ptr[-1] 326 vext.8 d21, d9, d10, #1 327 vext.8 d22, d7, d8, #1 328 vext.8 d23, d10, d11, #1 329 vext.8 d24, d6, d7, #4 ;construct src_ptr[2] 330 vext.8 d25, d9, d10, #4 331 vext.8 d26, d7, d8, #4 332 vext.8 d27, d10, d11, #4 333 vext.8 d28, d6, d7, #5 ;construct src_ptr[3] 334 vext.8 d29, d9, d10, #5 335 336 vmlsl.u8 q6, d20, d1 ;-(src_ptr[-1] * vp8_filter[1]) 337 vmlsl.u8 q8, d21, d1 338 vmlsl.u8 q7, d22, d1 ;-(src_ptr[-1] * vp8_filter[1]) 339 vmlsl.u8 q9, d23, d1 340 vmlsl.u8 q6, d24, d4 ;-(src_ptr[2] * vp8_filter[4]) 341 vmlsl.u8 q8, d25, d4 342 vmlsl.u8 q7, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) 343 vmlsl.u8 q9, d27, d4 344 vmlal.u8 q6, d28, d5 ;(src_ptr[3] * vp8_filter[5]) 345 vmlal.u8 q8, d29, d5 346 347 vext.8 d20, d7, d8, #5 348 vext.8 d21, d10, d11, #5 349 vext.8 d22, d6, d7, #2 ;construct src_ptr[0] 350 vext.8 d23, d9, d10, #2 351 vext.8 d24, d7, d8, #2 352 vext.8 d25, d10, d11, #2 353 354 vext.8 d26, d6, d7, #3 ;construct src_ptr[1] 355 vext.8 d27, d9, d10, #3 356 vext.8 d28, d7, d8, #3 357 vext.8 d29, d10, d11, #3 358 359 vmlal.u8 q7, d20, d5 ;(src_ptr[3] * vp8_filter[5]) 360 vmlal.u8 q9, d21, d5 361 vmlal.u8 q6, d22, d2 ;(src_ptr[0] * vp8_filter[2]) 362 vmlal.u8 q8, d23, d2 363 vmlal.u8 q7, d24, d2 ;(src_ptr[0] * vp8_filter[2]) 364 vmlal.u8 q9, d25, d2 365 366 vmull.u8 q10, d26, d3 ;(src_ptr[1] * vp8_filter[3]) 367 vmull.u8 q11, d27, d3 368 vmull.u8 q12, d28, d3 ;(src_ptr[1] * vp8_filter[3]) 369 vmull.u8 q15, d29, d3 370 371 vqadd.s16 q6, q10 ;sum of all (src_data*filter_parameters) 372 vqadd.s16 q8, q11 373 vqadd.s16 q7, q12 374 vqadd.s16 q9, q15 375 376 subs r2, r2, #1 377 378 vqrshrun.s16 d6, q6, #7 ;shift/round/saturate to u8 379 vqrshrun.s16 d7, q7, #7 380 vqrshrun.s16 d8, q8, #7 381 vqrshrun.s16 d9, q9, #7 382 383 vst1.u8 {q3}, [r4], r5 ;store result 384 vst1.u8 {q4}, [r4], r5 385 386 bne filt_blk2d_fpo16x16_loop_neon 387 388 pop {r4-r5,pc} 389 390 ;-------------------- 391 secondpass_filter16x16_only 392 ;Second pass: 16x16 393 add r3, r12, r3, lsl #5 394 sub r0, r0, r1, lsl #1 395 396 vld1.s32 {q5, q6}, [r3] ;load second_pass filter 397 mov r3, #2 ;loop counter 398 399 vabs.s32 q7, q5 400 vabs.s32 q8, q6 401 402 vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) 403 vdup.8 d1, d14[4] 404 vdup.8 d2, d15[0] 405 vdup.8 d3, d15[4] 406 vdup.8 d4, d16[0] 407 vdup.8 d5, d16[4] 408 409 filt_blk2d_spo16x16_outloop_neon 410 vld1.u8 {d18}, [r0], r1 ;load src data 411 vld1.u8 {d19}, [r0], r1 412 vld1.u8 {d20}, [r0], r1 413 vld1.u8 {d21}, [r0], r1 414 mov r12, #4 ;loop counter 415 vld1.u8 {d22}, [r0], r1 416 417 secondpass_only_inner_loop_neon 418 vld1.u8 {d23}, [r0], r1 ;load src data 419 vld1.u8 {d24}, [r0], r1 420 vld1.u8 {d25}, [r0], r1 421 vld1.u8 {d26}, [r0], r1 422 423 vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) 424 vmull.u8 q4, d19, d0 425 vmull.u8 q5, d20, d0 426 vmull.u8 q6, d21, d0 427 428 vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) 429 vmlsl.u8 q4, d20, d1 430 vmlsl.u8 q5, d21, d1 431 vmlsl.u8 q6, d22, d1 432 433 vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) 434 vmlsl.u8 q4, d23, d4 435 vmlsl.u8 q5, d24, d4 436 vmlsl.u8 q6, d25, d4 437 438 vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) 439 vmlal.u8 q4, d21, d2 440 vmlal.u8 q5, d22, d2 441 vmlal.u8 q6, d23, d2 442 443 vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) 444 vmlal.u8 q4, d24, d5 445 vmlal.u8 q5, d25, d5 446 vmlal.u8 q6, d26, d5 447 448 vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) 449 vmull.u8 q8, d22, d3 450 vmull.u8 q9, d23, d3 451 vmull.u8 q10, d24, d3 452 453 subs r12, r12, #1 454 455 vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) 456 vqadd.s16 q8, q4 457 vqadd.s16 q9, q5 458 vqadd.s16 q10, q6 459 460 vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 461 vqrshrun.s16 d7, q8, #7 462 vqrshrun.s16 d8, q9, #7 463 vqrshrun.s16 d9, q10, #7 464 465 vst1.u8 {d6}, [r4], r5 ;store result 466 vmov q9, q11 467 vst1.u8 {d7}, [r4], r5 468 vmov q10, q12 469 vst1.u8 {d8}, [r4], r5 470 vmov d22, d26 471 vst1.u8 {d9}, [r4], r5 472 473 bne secondpass_only_inner_loop_neon 474 475 subs r3, r3, #1 476 sub r0, r0, r1, lsl #4 477 sub r0, r0, r1, lsl #2 478 sub r0, r0, r1 479 add r0, r0, #8 480 481 sub r4, r4, r5, lsl #4 482 add r4, r4, #8 483 484 bne filt_blk2d_spo16x16_outloop_neon 485 486 pop {r4-r5,pc} 487 488 ENDP 489 490 END 491