Home | History | Annotate | Download | only in neon
      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