Home | History | Annotate | Download | only in arm
      1 ;
      2 ;  Copyright (c) 2013 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     EXPORT  |vpx_lpf_horizontal_8_neon|
     12     EXPORT  |vpx_lpf_vertical_8_neon|
     13     ARM
     14 
     15     AREA ||.text||, CODE, READONLY, ALIGN=2
     16 
     17 ; Currently vpx only works on iterations 8 at a time. The vp8 loop filter
     18 ; works on 16 iterations at a time.
     19 ; TODO(fgalligan): See about removing the count code as this function is only
     20 ; called with a count of 1.
     21 ;
     22 ; void vpx_lpf_horizontal_8_neon(uint8_t *s, int p,
     23 ;                                const uint8_t *blimit,
     24 ;                                const uint8_t *limit,
     25 ;                                const uint8_t *thresh,
     26 ;                                int count)
     27 ; r0    uint8_t *s,
     28 ; r1    int p, /* pitch */
     29 ; r2    const uint8_t *blimit,
     30 ; r3    const uint8_t *limit,
     31 ; sp    const uint8_t *thresh,
     32 ; sp+4  int count
     33 |vpx_lpf_horizontal_8_neon| PROC
     34     push        {r4-r5, lr}
     35 
     36     vld1.8      {d0[]}, [r2]               ; duplicate *blimit
     37     ldr         r12, [sp, #16]             ; load count
     38     ldr         r2, [sp, #12]              ; load thresh
     39     add         r1, r1, r1                 ; double pitch
     40 
     41     cmp         r12, #0
     42     beq         end_vpx_mblf_h_edge
     43 
     44     vld1.8      {d1[]}, [r3]               ; duplicate *limit
     45     vld1.8      {d2[]}, [r2]               ; duplicate *thresh
     46 
     47 count_mblf_h_loop
     48     sub         r3, r0, r1, lsl #1         ; move src pointer down by 4 lines
     49     add         r2, r3, r1, lsr #1         ; set to 3 lines down
     50 
     51     vld1.u8     {d3}, [r3@64], r1          ; p3
     52     vld1.u8     {d4}, [r2@64], r1          ; p2
     53     vld1.u8     {d5}, [r3@64], r1          ; p1
     54     vld1.u8     {d6}, [r2@64], r1          ; p0
     55     vld1.u8     {d7}, [r3@64], r1          ; q0
     56     vld1.u8     {d16}, [r2@64], r1         ; q1
     57     vld1.u8     {d17}, [r3@64]             ; q2
     58     vld1.u8     {d18}, [r2@64], r1         ; q3
     59 
     60     sub         r3, r3, r1, lsl #1
     61     sub         r2, r2, r1, lsl #2
     62 
     63     bl          vpx_mbloop_filter_neon
     64 
     65     vst1.u8     {d0}, [r2@64], r1          ; store op2
     66     vst1.u8     {d1}, [r3@64], r1          ; store op1
     67     vst1.u8     {d2}, [r2@64], r1          ; store op0
     68     vst1.u8     {d3}, [r3@64], r1          ; store oq0
     69     vst1.u8     {d4}, [r2@64], r1          ; store oq1
     70     vst1.u8     {d5}, [r3@64], r1          ; store oq2
     71 
     72     add         r0, r0, #8
     73     subs        r12, r12, #1
     74     bne         count_mblf_h_loop
     75 
     76 end_vpx_mblf_h_edge
     77     pop         {r4-r5, pc}
     78 
     79     ENDP        ; |vpx_lpf_horizontal_8_neon|
     80 
     81 ; void vpx_lpf_vertical_8_neon(uint8_t *s,
     82 ;                              int pitch,
     83 ;                              const uint8_t *blimit,
     84 ;                              const uint8_t *limit,
     85 ;                              const uint8_t *thresh,
     86 ;                              int count)
     87 ;
     88 ; r0    uint8_t *s,
     89 ; r1    int pitch,
     90 ; r2    const uint8_t *blimit,
     91 ; r3    const uint8_t *limit,
     92 ; sp    const uint8_t *thresh,
     93 ; sp+4  int count
     94 |vpx_lpf_vertical_8_neon| PROC
     95     push        {r4-r5, lr}
     96 
     97     vld1.8      {d0[]}, [r2]              ; duplicate *blimit
     98     ldr         r12, [sp, #16]            ; load count
     99     vld1.8      {d1[]}, [r3]              ; duplicate *limit
    100 
    101     ldr         r3, [sp, #12]             ; load thresh
    102     sub         r2, r0, #4                ; move s pointer down by 4 columns
    103     cmp         r12, #0
    104     beq         end_vpx_mblf_v_edge
    105 
    106     vld1.8      {d2[]}, [r3]              ; duplicate *thresh
    107 
    108 count_mblf_v_loop
    109     vld1.u8     {d3}, [r2], r1             ; load s data
    110     vld1.u8     {d4}, [r2], r1
    111     vld1.u8     {d5}, [r2], r1
    112     vld1.u8     {d6}, [r2], r1
    113     vld1.u8     {d7}, [r2], r1
    114     vld1.u8     {d16}, [r2], r1
    115     vld1.u8     {d17}, [r2], r1
    116     vld1.u8     {d18}, [r2]
    117 
    118     ;transpose to 8x16 matrix
    119     vtrn.32     d3, d7
    120     vtrn.32     d4, d16
    121     vtrn.32     d5, d17
    122     vtrn.32     d6, d18
    123 
    124     vtrn.16     d3, d5
    125     vtrn.16     d4, d6
    126     vtrn.16     d7, d17
    127     vtrn.16     d16, d18
    128 
    129     vtrn.8      d3, d4
    130     vtrn.8      d5, d6
    131     vtrn.8      d7, d16
    132     vtrn.8      d17, d18
    133 
    134     sub         r2, r0, #3
    135     add         r3, r0, #1
    136 
    137     bl          vpx_mbloop_filter_neon
    138 
    139     ;store op2, op1, op0, oq0
    140     vst4.8      {d0[0], d1[0], d2[0], d3[0]}, [r2], r1
    141     vst4.8      {d0[1], d1[1], d2[1], d3[1]}, [r2], r1
    142     vst4.8      {d0[2], d1[2], d2[2], d3[2]}, [r2], r1
    143     vst4.8      {d0[3], d1[3], d2[3], d3[3]}, [r2], r1
    144     vst4.8      {d0[4], d1[4], d2[4], d3[4]}, [r2], r1
    145     vst4.8      {d0[5], d1[5], d2[5], d3[5]}, [r2], r1
    146     vst4.8      {d0[6], d1[6], d2[6], d3[6]}, [r2], r1
    147     vst4.8      {d0[7], d1[7], d2[7], d3[7]}, [r2]
    148 
    149     ;store oq1, oq2
    150     vst2.8      {d4[0], d5[0]}, [r3], r1
    151     vst2.8      {d4[1], d5[1]}, [r3], r1
    152     vst2.8      {d4[2], d5[2]}, [r3], r1
    153     vst2.8      {d4[3], d5[3]}, [r3], r1
    154     vst2.8      {d4[4], d5[4]}, [r3], r1
    155     vst2.8      {d4[5], d5[5]}, [r3], r1
    156     vst2.8      {d4[6], d5[6]}, [r3], r1
    157     vst2.8      {d4[7], d5[7]}, [r3]
    158 
    159     add         r0, r0, r1, lsl #3         ; s += pitch * 8
    160     subs        r12, r12, #1
    161     subne       r2, r0, #4                 ; move s pointer down by 4 columns
    162     bne         count_mblf_v_loop
    163 
    164 end_vpx_mblf_v_edge
    165     pop         {r4-r5, pc}
    166     ENDP        ; |vpx_lpf_vertical_8_neon|
    167 
    168 ; void vpx_mbloop_filter_neon();
    169 ; This is a helper function for the loopfilters. The invidual functions do the
    170 ; necessary load, transpose (if necessary) and store. The function does not use
    171 ; registers d8-d15.
    172 ;
    173 ; Inputs:
    174 ; r0-r3, r12 PRESERVE
    175 ; d0    blimit
    176 ; d1    limit
    177 ; d2    thresh
    178 ; d3    p3
    179 ; d4    p2
    180 ; d5    p1
    181 ; d6    p0
    182 ; d7    q0
    183 ; d16   q1
    184 ; d17   q2
    185 ; d18   q3
    186 ;
    187 ; Outputs:
    188 ; d0    op2
    189 ; d1    op1
    190 ; d2    op0
    191 ; d3    oq0
    192 ; d4    oq1
    193 ; d5    oq2
    194 |vpx_mbloop_filter_neon| PROC
    195     ; filter_mask
    196     vabd.u8     d19, d3, d4                ; m1 = abs(p3 - p2)
    197     vabd.u8     d20, d4, d5                ; m2 = abs(p2 - p1)
    198     vabd.u8     d21, d5, d6                ; m3 = abs(p1 - p0)
    199     vabd.u8     d22, d16, d7               ; m4 = abs(q1 - q0)
    200     vabd.u8     d23, d17, d16              ; m5 = abs(q2 - q1)
    201     vabd.u8     d24, d18, d17              ; m6 = abs(q3 - q2)
    202 
    203     ; only compare the largest value to limit
    204     vmax.u8     d19, d19, d20              ; m1 = max(m1, m2)
    205     vmax.u8     d20, d21, d22              ; m2 = max(m3, m4)
    206 
    207     vabd.u8     d25, d6, d4                ; m7 = abs(p0 - p2)
    208 
    209     vmax.u8     d23, d23, d24              ; m3 = max(m5, m6)
    210 
    211     vabd.u8     d26, d7, d17               ; m8 = abs(q0 - q2)
    212 
    213     vmax.u8     d19, d19, d20
    214 
    215     vabd.u8     d24, d6, d7                ; m9 = abs(p0 - q0)
    216     vabd.u8     d27, d3, d6                ; m10 = abs(p3 - p0)
    217     vabd.u8     d28, d18, d7               ; m11 = abs(q3 - q0)
    218 
    219     vmax.u8     d19, d19, d23
    220 
    221     vabd.u8     d23, d5, d16               ; a = abs(p1 - q1)
    222     vqadd.u8    d24, d24, d24              ; b = abs(p0 - q0) * 2
    223 
    224     ; abs () > limit
    225     vcge.u8     d19, d1, d19
    226 
    227     ; only compare the largest value to thresh
    228     vmax.u8     d25, d25, d26              ; m4 = max(m7, m8)
    229     vmax.u8     d26, d27, d28              ; m5 = max(m10, m11)
    230 
    231     vshr.u8     d23, d23, #1               ; a = a / 2
    232 
    233     vmax.u8     d25, d25, d26              ; m4 = max(m4, m5)
    234 
    235     vqadd.u8    d24, d24, d23              ; a = b + a
    236 
    237     vmax.u8     d20, d20, d25              ; m2 = max(m2, m4)
    238 
    239     vmov.u8     d23, #1
    240     vcge.u8     d24, d0, d24               ; a > blimit
    241 
    242     vcgt.u8     d21, d21, d2               ; (abs(p1 - p0) > thresh)*-1
    243 
    244     vcge.u8     d20, d23, d20              ; flat
    245 
    246     vand        d19, d19, d24              ; mask
    247 
    248     vcgt.u8     d23, d22, d2               ; (abs(q1 - q0) > thresh)*-1
    249 
    250     vand        d20, d20, d19              ; flat & mask
    251 
    252     vmov.u8     d22, #0x80
    253 
    254     vorr        d23, d21, d23              ; hev
    255 
    256     ; This instruction will truncate the "flat & mask" masks down to 4 bits
    257     ; each to fit into one 32 bit arm register. The values are stored in
    258     ; q10.64[0].
    259     vshrn.u16   d30, q10, #4
    260     vmov.u32    r4, d30[0]                 ; flat & mask 4bits
    261 
    262     adds        r5, r4, #1                 ; Check for all 1's
    263 
    264     ; If mask and flat are 1's for all vectors, then we only need to execute
    265     ; the power branch for all vectors.
    266     beq         power_branch_only
    267 
    268     cmp         r4, #0                     ; Check for 0, set flag for later
    269 
    270     ; mbfilter() function
    271     ; filter() function
    272     ; convert to signed
    273     veor        d21, d7, d22               ; qs0
    274     veor        d24, d6, d22               ; ps0
    275     veor        d25, d5, d22               ; ps1
    276     veor        d26, d16, d22              ; qs1
    277 
    278     vmov.u8     d27, #3
    279 
    280     vsub.s8     d28, d21, d24              ; ( qs0 - ps0)
    281 
    282     vqsub.s8    d29, d25, d26              ; filter = clamp(ps1-qs1)
    283 
    284     vmull.s8    q15, d28, d27              ; 3 * ( qs0 - ps0)
    285 
    286     vand        d29, d29, d23              ; filter &= hev
    287 
    288     vaddw.s8    q15, q15, d29              ; filter + 3 * (qs0 - ps0)
    289 
    290     vmov.u8     d29, #4
    291 
    292     ; filter = clamp(filter + 3 * ( qs0 - ps0))
    293     vqmovn.s16  d28, q15
    294 
    295     vand        d28, d28, d19              ; filter &= mask
    296 
    297     vqadd.s8    d30, d28, d27              ; filter2 = clamp(filter+3)
    298     vqadd.s8    d29, d28, d29              ; filter1 = clamp(filter+4)
    299     vshr.s8     d30, d30, #3               ; filter2 >>= 3
    300     vshr.s8     d29, d29, #3               ; filter1 >>= 3
    301 
    302     vqadd.s8    d24, d24, d30              ; op0 = clamp(ps0 + filter2)
    303     vqsub.s8    d21, d21, d29              ; oq0 = clamp(qs0 - filter1)
    304 
    305     ; outer tap adjustments: ++filter1 >> 1
    306     vrshr.s8    d29, d29, #1
    307     vbic        d29, d29, d23              ; filter &= ~hev
    308 
    309     vqadd.s8    d25, d25, d29              ; op1 = clamp(ps1 + filter)
    310     vqsub.s8    d26, d26, d29              ; oq1 = clamp(qs1 - filter)
    311 
    312     ; If mask and flat are 0's for all vectors, then we only need to execute
    313     ; the filter branch for all vectors.
    314     beq         filter_branch_only
    315 
    316     ; If mask and flat are mixed then we must perform both branches and
    317     ; combine the data.
    318     veor        d24, d24, d22              ; *f_op0 = u^0x80
    319     veor        d21, d21, d22              ; *f_oq0 = u^0x80
    320     veor        d25, d25, d22              ; *f_op1 = u^0x80
    321     veor        d26, d26, d22              ; *f_oq1 = u^0x80
    322 
    323     ; At this point we have already executed the filter branch. The filter
    324     ; branch does not set op2 or oq2, so use p2 and q2. Execute the power
    325     ; branch and combine the data.
    326     vmov.u8     d23, #2
    327     vaddl.u8    q14, d6, d7                ; r_op2 = p0 + q0
    328     vmlal.u8    q14, d3, d27               ; r_op2 += p3 * 3
    329     vmlal.u8    q14, d4, d23               ; r_op2 += p2 * 2
    330 
    331     vbif        d0, d4, d20                ; op2 |= p2 & ~(flat & mask)
    332 
    333     vaddw.u8    q14, d5                    ; r_op2 += p1
    334 
    335     vbif        d1, d25, d20               ; op1 |= f_op1 & ~(flat & mask)
    336 
    337     vqrshrn.u16 d30, q14, #3               ; r_op2
    338 
    339     vsubw.u8    q14, d3                    ; r_op1 = r_op2 - p3
    340     vsubw.u8    q14, d4                    ; r_op1 -= p2
    341     vaddw.u8    q14, d5                    ; r_op1 += p1
    342     vaddw.u8    q14, d16                   ; r_op1 += q1
    343 
    344     vbif        d2, d24, d20               ; op0 |= f_op0 & ~(flat & mask)
    345 
    346     vqrshrn.u16 d31, q14, #3               ; r_op1
    347 
    348     vsubw.u8    q14, d3                    ; r_op0 = r_op1 - p3
    349     vsubw.u8    q14, d5                    ; r_op0 -= p1
    350     vaddw.u8    q14, d6                    ; r_op0 += p0
    351     vaddw.u8    q14, d17                   ; r_op0 += q2
    352 
    353     vbit        d0, d30, d20               ; op2 |= r_op2 & (flat & mask)
    354 
    355     vqrshrn.u16 d23, q14, #3               ; r_op0
    356 
    357     vsubw.u8    q14, d3                    ; r_oq0 = r_op0 - p3
    358     vsubw.u8    q14, d6                    ; r_oq0 -= p0
    359     vaddw.u8    q14, d7                    ; r_oq0 += q0
    360 
    361     vbit        d1, d31, d20               ; op1 |= r_op1 & (flat & mask)
    362 
    363     vaddw.u8    q14, d18                   ; oq0 += q3
    364 
    365     vbit        d2, d23, d20               ; op0 |= r_op0 & (flat & mask)
    366 
    367     vqrshrn.u16 d22, q14, #3               ; r_oq0
    368 
    369     vsubw.u8    q14, d4                    ; r_oq1 = r_oq0 - p2
    370     vsubw.u8    q14, d7                    ; r_oq1 -= q0
    371     vaddw.u8    q14, d16                   ; r_oq1 += q1
    372 
    373     vbif        d3, d21, d20               ; oq0 |= f_oq0 & ~(flat & mask)
    374 
    375     vaddw.u8    q14, d18                   ; r_oq1 += q3
    376 
    377     vbif        d4, d26, d20               ; oq1 |= f_oq1 & ~(flat & mask)
    378 
    379     vqrshrn.u16 d6, q14, #3                ; r_oq1
    380 
    381     vsubw.u8    q14, d5                    ; r_oq2 = r_oq1 - p1
    382     vsubw.u8    q14, d16                   ; r_oq2 -= q1
    383     vaddw.u8    q14, d17                   ; r_oq2 += q2
    384     vaddw.u8    q14, d18                   ; r_oq2 += q3
    385 
    386     vbif        d5, d17, d20               ; oq2 |= q2 & ~(flat & mask)
    387 
    388     vqrshrn.u16 d7, q14, #3                ; r_oq2
    389 
    390     vbit        d3, d22, d20               ; oq0 |= r_oq0 & (flat & mask)
    391     vbit        d4, d6, d20                ; oq1 |= r_oq1 & (flat & mask)
    392     vbit        d5, d7, d20                ; oq2 |= r_oq2 & (flat & mask)
    393 
    394     bx          lr
    395 
    396 power_branch_only
    397     vmov.u8     d27, #3
    398     vmov.u8     d21, #2
    399     vaddl.u8    q14, d6, d7                ; op2 = p0 + q0
    400     vmlal.u8    q14, d3, d27               ; op2 += p3 * 3
    401     vmlal.u8    q14, d4, d21               ; op2 += p2 * 2
    402     vaddw.u8    q14, d5                    ; op2 += p1
    403     vqrshrn.u16 d0, q14, #3                ; op2
    404 
    405     vsubw.u8    q14, d3                    ; op1 = op2 - p3
    406     vsubw.u8    q14, d4                    ; op1 -= p2
    407     vaddw.u8    q14, d5                    ; op1 += p1
    408     vaddw.u8    q14, d16                   ; op1 += q1
    409     vqrshrn.u16 d1, q14, #3                ; op1
    410 
    411     vsubw.u8    q14, d3                    ; op0 = op1 - p3
    412     vsubw.u8    q14, d5                    ; op0 -= p1
    413     vaddw.u8    q14, d6                    ; op0 += p0
    414     vaddw.u8    q14, d17                   ; op0 += q2
    415     vqrshrn.u16 d2, q14, #3                ; op0
    416 
    417     vsubw.u8    q14, d3                    ; oq0 = op0 - p3
    418     vsubw.u8    q14, d6                    ; oq0 -= p0
    419     vaddw.u8    q14, d7                    ; oq0 += q0
    420     vaddw.u8    q14, d18                   ; oq0 += q3
    421     vqrshrn.u16 d3, q14, #3                ; oq0
    422 
    423     vsubw.u8    q14, d4                    ; oq1 = oq0 - p2
    424     vsubw.u8    q14, d7                    ; oq1 -= q0
    425     vaddw.u8    q14, d16                   ; oq1 += q1
    426     vaddw.u8    q14, d18                   ; oq1 += q3
    427     vqrshrn.u16 d4, q14, #3                ; oq1
    428 
    429     vsubw.u8    q14, d5                    ; oq2 = oq1 - p1
    430     vsubw.u8    q14, d16                   ; oq2 -= q1
    431     vaddw.u8    q14, d17                   ; oq2 += q2
    432     vaddw.u8    q14, d18                   ; oq2 += q3
    433     vqrshrn.u16 d5, q14, #3                ; oq2
    434 
    435     bx          lr
    436 
    437 filter_branch_only
    438     ; TODO(fgalligan): See if we can rearange registers so we do not need to
    439     ; do the 2 vswp.
    440     vswp        d0, d4                      ; op2
    441     vswp        d5, d17                     ; oq2
    442     veor        d2, d24, d22                ; *op0 = u^0x80
    443     veor        d3, d21, d22                ; *oq0 = u^0x80
    444     veor        d1, d25, d22                ; *op1 = u^0x80
    445     veor        d4, d26, d22                ; *oq1 = u^0x80
    446 
    447     bx          lr
    448 
    449     ENDP        ; |vpx_mbloop_filter_neon|
    450 
    451     END
    452