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_loop_filter_horizontal_edge_y_neon| 13 EXPORT |vp8_loop_filter_horizontal_edge_uv_neon| 14 EXPORT |vp8_loop_filter_vertical_edge_y_neon| 15 EXPORT |vp8_loop_filter_vertical_edge_uv_neon| 16 ARM 17 REQUIRE8 18 PRESERVE8 19 20 AREA ||.text||, CODE, READONLY, ALIGN=2 21 22 ; flimit, limit, and thresh should be positive numbers. 23 ; All 16 elements in these variables are equal. 24 25 ; void vp8_loop_filter_horizontal_edge_y_neon(unsigned char *src, int pitch, 26 ; const signed char *flimit, 27 ; const signed char *limit, 28 ; const signed char *thresh, 29 ; int count) 30 ; r0 unsigned char *src 31 ; r1 int pitch 32 ; r2 const signed char *flimit 33 ; r3 const signed char *limit 34 ; sp const signed char *thresh, 35 ; sp+4 int count (unused) 36 |vp8_loop_filter_horizontal_edge_y_neon| PROC 37 stmdb sp!, {lr} 38 vld1.s8 {d0[], d1[]}, [r2] ; flimit 39 vld1.s8 {d2[], d3[]}, [r3] ; limit 40 sub r2, r0, r1, lsl #2 ; move src pointer down by 4 lines 41 ldr r12, [sp, #4] ; load thresh pointer 42 43 vld1.u8 {q3}, [r2], r1 ; p3 44 vld1.u8 {q4}, [r2], r1 ; p2 45 vld1.u8 {q5}, [r2], r1 ; p1 46 vld1.u8 {q6}, [r2], r1 ; p0 47 vld1.u8 {q7}, [r2], r1 ; q0 48 vld1.u8 {q8}, [r2], r1 ; q1 49 vld1.u8 {q9}, [r2], r1 ; q2 50 vld1.u8 {q10}, [r2] ; q3 51 vld1.s8 {d4[], d5[]}, [r12] ; thresh 52 sub r0, r0, r1, lsl #1 53 54 bl vp8_loop_filter_neon 55 56 vst1.u8 {q5}, [r0], r1 ; store op1 57 vst1.u8 {q6}, [r0], r1 ; store op0 58 vst1.u8 {q7}, [r0], r1 ; store oq0 59 vst1.u8 {q8}, [r0], r1 ; store oq1 60 61 ldmia sp!, {pc} 62 ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| 63 64 ; void vp8_loop_filter_horizontal_edge_uv_neon(unsigned char *u, int pitch 65 ; const signed char *flimit, 66 ; const signed char *limit, 67 ; const signed char *thresh, 68 ; unsigned char *v) 69 ; r0 unsigned char *u, 70 ; r1 int pitch, 71 ; r2 const signed char *flimit, 72 ; r3 const signed char *limit, 73 ; sp const signed char *thresh, 74 ; sp+4 unsigned char *v 75 |vp8_loop_filter_horizontal_edge_uv_neon| PROC 76 stmdb sp!, {lr} 77 vld1.s8 {d0[], d1[]}, [r2] ; flimit 78 vld1.s8 {d2[], d3[]}, [r3] ; limit 79 ldr r2, [sp, #8] ; load v ptr 80 81 sub r3, r0, r1, lsl #2 ; move u pointer down by 4 lines 82 vld1.u8 {d6}, [r3], r1 ; p3 83 vld1.u8 {d8}, [r3], r1 ; p2 84 vld1.u8 {d10}, [r3], r1 ; p1 85 vld1.u8 {d12}, [r3], r1 ; p0 86 vld1.u8 {d14}, [r3], r1 ; q0 87 vld1.u8 {d16}, [r3], r1 ; q1 88 vld1.u8 {d18}, [r3], r1 ; q2 89 vld1.u8 {d20}, [r3] ; q3 90 91 ldr r3, [sp, #4] ; load thresh pointer 92 93 sub r12, r2, r1, lsl #2 ; move v pointer down by 4 lines 94 vld1.u8 {d7}, [r12], r1 ; p3 95 vld1.u8 {d9}, [r12], r1 ; p2 96 vld1.u8 {d11}, [r12], r1 ; p1 97 vld1.u8 {d13}, [r12], r1 ; p0 98 vld1.u8 {d15}, [r12], r1 ; q0 99 vld1.u8 {d17}, [r12], r1 ; q1 100 vld1.u8 {d19}, [r12], r1 ; q2 101 vld1.u8 {d21}, [r12] ; q3 102 103 vld1.s8 {d4[], d5[]}, [r3] ; thresh 104 105 bl vp8_loop_filter_neon 106 107 sub r0, r0, r1, lsl #1 108 sub r2, r2, r1, lsl #1 109 110 vst1.u8 {d10}, [r0], r1 ; store u op1 111 vst1.u8 {d11}, [r2], r1 ; store v op1 112 vst1.u8 {d12}, [r0], r1 ; store u op0 113 vst1.u8 {d13}, [r2], r1 ; store v op0 114 vst1.u8 {d14}, [r0], r1 ; store u oq0 115 vst1.u8 {d15}, [r2], r1 ; store v oq0 116 vst1.u8 {d16}, [r0] ; store u oq1 117 vst1.u8 {d17}, [r2] ; store v oq1 118 119 ldmia sp!, {pc} 120 ENDP ; |vp8_loop_filter_horizontal_edge_uv_neon| 121 122 ; void vp8_loop_filter_vertical_edge_y_neon(unsigned char *src, int pitch, 123 ; const signed char *flimit, 124 ; const signed char *limit, 125 ; const signed char *thresh, 126 ; int count) 127 ; r0 unsigned char *src, 128 ; r1 int pitch, 129 ; r2 const signed char *flimit, 130 ; r3 const signed char *limit, 131 ; sp const signed char *thresh, 132 ; sp+4 int count (unused) 133 |vp8_loop_filter_vertical_edge_y_neon| PROC 134 stmdb sp!, {lr} 135 vld1.s8 {d0[], d1[]}, [r2] ; flimit 136 vld1.s8 {d2[], d3[]}, [r3] ; limit 137 sub r2, r0, #4 ; src ptr down by 4 columns 138 sub r0, r0, #2 ; dst ptr 139 ldr r12, [sp, #4] ; load thresh pointer 140 141 vld1.u8 {d6}, [r2], r1 ; load first 8-line src data 142 vld1.u8 {d8}, [r2], r1 143 vld1.u8 {d10}, [r2], r1 144 vld1.u8 {d12}, [r2], r1 145 vld1.u8 {d14}, [r2], r1 146 vld1.u8 {d16}, [r2], r1 147 vld1.u8 {d18}, [r2], r1 148 vld1.u8 {d20}, [r2], r1 149 150 vld1.s8 {d4[], d5[]}, [r12] ; thresh 151 152 vld1.u8 {d7}, [r2], r1 ; load second 8-line src data 153 vld1.u8 {d9}, [r2], r1 154 vld1.u8 {d11}, [r2], r1 155 vld1.u8 {d13}, [r2], r1 156 vld1.u8 {d15}, [r2], r1 157 vld1.u8 {d17}, [r2], r1 158 vld1.u8 {d19}, [r2], r1 159 vld1.u8 {d21}, [r2] 160 161 ;transpose to 8x16 matrix 162 vtrn.32 q3, q7 163 vtrn.32 q4, q8 164 vtrn.32 q5, q9 165 vtrn.32 q6, q10 166 167 vtrn.16 q3, q5 168 vtrn.16 q4, q6 169 vtrn.16 q7, q9 170 vtrn.16 q8, q10 171 172 vtrn.8 q3, q4 173 vtrn.8 q5, q6 174 vtrn.8 q7, q8 175 vtrn.8 q9, q10 176 177 bl vp8_loop_filter_neon 178 179 vswp d12, d11 180 vswp d16, d13 181 vswp d14, d12 182 vswp d16, d15 183 184 ;store op1, op0, oq0, oq1 185 vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 186 vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1 187 vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 188 vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1 189 vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 190 vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 191 vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 192 vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0], r1 193 vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r0], r1 194 vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r0], r1 195 vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r0], r1 196 vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r0], r1 197 vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r0], r1 198 vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r0], r1 199 vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r0], r1 200 vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r0] 201 202 ldmia sp!, {pc} 203 ENDP ; |vp8_loop_filter_vertical_edge_y_neon| 204 205 ; void vp8_loop_filter_vertical_edge_uv_neon(unsigned char *u, int pitch 206 ; const signed char *flimit, 207 ; const signed char *limit, 208 ; const signed char *thresh, 209 ; unsigned char *v) 210 ; r0 unsigned char *u, 211 ; r1 int pitch, 212 ; r2 const signed char *flimit, 213 ; r3 const signed char *limit, 214 ; sp const signed char *thresh, 215 ; sp+4 unsigned char *v 216 |vp8_loop_filter_vertical_edge_uv_neon| PROC 217 stmdb sp!, {lr} 218 sub r12, r0, #4 ; move u pointer down by 4 columns 219 vld1.s8 {d0[], d1[]}, [r2] ; flimit 220 vld1.s8 {d2[], d3[]}, [r3] ; limit 221 222 ldr r2, [sp, #8] ; load v ptr 223 224 vld1.u8 {d6}, [r12], r1 ;load u data 225 vld1.u8 {d8}, [r12], r1 226 vld1.u8 {d10}, [r12], r1 227 vld1.u8 {d12}, [r12], r1 228 vld1.u8 {d14}, [r12], r1 229 vld1.u8 {d16}, [r12], r1 230 vld1.u8 {d18}, [r12], r1 231 vld1.u8 {d20}, [r12] 232 233 sub r3, r2, #4 ; move v pointer down by 4 columns 234 vld1.u8 {d7}, [r3], r1 ;load v data 235 vld1.u8 {d9}, [r3], r1 236 vld1.u8 {d11}, [r3], r1 237 vld1.u8 {d13}, [r3], r1 238 vld1.u8 {d15}, [r3], r1 239 vld1.u8 {d17}, [r3], r1 240 vld1.u8 {d19}, [r3], r1 241 vld1.u8 {d21}, [r3] 242 243 ldr r12, [sp, #4] ; load thresh pointer 244 245 ;transpose to 8x16 matrix 246 vtrn.32 q3, q7 247 vtrn.32 q4, q8 248 vtrn.32 q5, q9 249 vtrn.32 q6, q10 250 251 vtrn.16 q3, q5 252 vtrn.16 q4, q6 253 vtrn.16 q7, q9 254 vtrn.16 q8, q10 255 256 vtrn.8 q3, q4 257 vtrn.8 q5, q6 258 vtrn.8 q7, q8 259 vtrn.8 q9, q10 260 261 vld1.s8 {d4[], d5[]}, [r12] ; thresh 262 263 bl vp8_loop_filter_neon 264 265 sub r0, r0, #2 266 sub r2, r2, #2 267 268 vswp d12, d11 269 vswp d16, d13 270 vswp d14, d12 271 vswp d16, d15 272 273 ;store op1, op0, oq0, oq1 274 vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 275 vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r2], r1 276 vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1 277 vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r2], r1 278 vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 279 vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r2], r1 280 vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1 281 vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r2], r1 282 vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 283 vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r2], r1 284 vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 285 vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r2], r1 286 vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 287 vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r2], r1 288 vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0] 289 vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r2] 290 291 ldmia sp!, {pc} 292 ENDP ; |vp8_loop_filter_vertical_edge_uv_neon| 293 294 ; void vp8_loop_filter_neon(); 295 ; This is a helper function for the loopfilters. The invidual functions do the 296 ; necessary load, transpose (if necessary) and store. 297 298 ; r0-r3 PRESERVE 299 ; q0 flimit 300 ; q1 limit 301 ; q2 thresh 302 ; q3 p3 303 ; q4 p2 304 ; q5 p1 305 ; q6 p0 306 ; q7 q0 307 ; q8 q1 308 ; q9 q2 309 ; q10 q3 310 |vp8_loop_filter_neon| PROC 311 ldr r12, _lf_coeff_ 312 313 ; vp8_filter_mask 314 vabd.u8 q11, q3, q4 ; abs(p3 - p2) 315 vabd.u8 q12, q4, q5 ; abs(p2 - p1) 316 vabd.u8 q13, q5, q6 ; abs(p1 - p0) 317 vabd.u8 q14, q8, q7 ; abs(q1 - q0) 318 vabd.u8 q3, q9, q8 ; abs(q2 - q1) 319 vabd.u8 q4, q10, q9 ; abs(q3 - q2) 320 vabd.u8 q9, q6, q7 ; abs(p0 - q0) 321 322 vmax.u8 q11, q11, q12 323 vmax.u8 q12, q13, q14 324 vmax.u8 q3, q3, q4 325 vmax.u8 q15, q11, q12 326 327 ; vp8_hevmask 328 vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 329 vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 330 vmax.u8 q15, q15, q3 331 332 vadd.u8 q0, q0, q0 ; flimit * 2 333 vadd.u8 q0, q0, q1 ; flimit * 2 + limit 334 vcge.u8 q15, q1, q15 335 336 vabd.u8 q2, q5, q8 ; a = abs(p1 - q1) 337 vqadd.u8 q9, q9, q9 ; b = abs(p0 - q0) * 2 338 vshr.u8 q2, q2, #1 ; a = a / 2 339 vqadd.u8 q9, q9, q2 ; a = b + a 340 vcge.u8 q9, q0, q9 ; (a > flimit * 2 + limit) * -1 341 342 vld1.u8 {q0}, [r12]! 343 344 ; vp8_filter() function 345 ; convert to signed 346 veor q7, q7, q0 ; qs0 347 veor q6, q6, q0 ; ps0 348 veor q5, q5, q0 ; ps1 349 veor q8, q8, q0 ; qs1 350 351 vld1.u8 {q10}, [r12]! 352 353 vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) 354 vsubl.s8 q11, d15, d13 355 356 vmovl.u8 q4, d20 357 358 vqsub.s8 q1, q5, q8 ; vp8_filter = clamp(ps1-qs1) 359 vorr q14, q13, q14 ; vp8_hevmask 360 361 vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) 362 vmul.i16 q11, q11, q4 363 364 vand q1, q1, q14 ; vp8_filter &= hev 365 vand q15, q15, q9 ; vp8_filter_mask 366 367 vaddw.s8 q2, q2, d2 368 vaddw.s8 q11, q11, d3 369 370 vld1.u8 {q9}, [r12]! 371 372 ; vp8_filter = clamp(vp8_filter + 3 * ( qs0 - ps0)) 373 vqmovn.s16 d2, q2 374 vqmovn.s16 d3, q11 375 vand q1, q1, q15 ; vp8_filter &= mask 376 377 vqadd.s8 q2, q1, q10 ; Filter2 = clamp(vp8_filter+3) 378 vqadd.s8 q1, q1, q9 ; Filter1 = clamp(vp8_filter+4) 379 vshr.s8 q2, q2, #3 ; Filter2 >>= 3 380 vshr.s8 q1, q1, #3 ; Filter1 >>= 3 381 382 vqadd.s8 q11, q6, q2 ; u = clamp(ps0 + Filter2) 383 vqsub.s8 q10, q7, q1 ; u = clamp(qs0 - Filter1) 384 385 ; outer tap adjustments: ++vp8_filter >> 1 386 vrshr.s8 q1, q1, #1 387 vbic q1, q1, q14 ; vp8_filter &= ~hev 388 389 vqadd.s8 q13, q5, q1 ; u = clamp(ps1 + vp8_filter) 390 vqsub.s8 q12, q8, q1 ; u = clamp(qs1 - vp8_filter) 391 392 veor q5, q13, q0 ; *op1 = u^0x80 393 veor q6, q11, q0 ; *op0 = u^0x80 394 veor q7, q10, q0 ; *oq0 = u^0x80 395 veor q8, q12, q0 ; *oq1 = u^0x80 396 397 bx lr 398 ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| 399 400 ;----------------- 401 402 _lf_coeff_ 403 DCD lf_coeff 404 lf_coeff 405 DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 406 DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 407 DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 408 DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 409 410 END 411