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