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