Home | History | Annotate | Download | only in dsp
      1 // Copyright 2016 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // MSA variant of alpha filters
     11 //
     12 // Author: Prashant Patil (prashant.patil (at) imgtec.com)
     13 
     14 #include "./dsp.h"
     15 
     16 #if defined(WEBP_USE_MSA)
     17 
     18 #include "./msa_macro.h"
     19 
     20 #include <assert.h>
     21 
     22 static WEBP_INLINE void PredictLineInverse0(const uint8_t* src,
     23                                             const uint8_t* pred,
     24                                             uint8_t* dst, int length) {
     25   v16u8 src0, pred0, dst0;
     26   assert(length >= 0);
     27   while (length >= 32) {
     28     v16u8 src1, pred1, dst1;
     29     LD_UB2(src, 16, src0, src1);
     30     LD_UB2(pred, 16, pred0, pred1);
     31     SUB2(src0, pred0, src1, pred1, dst0, dst1);
     32     ST_UB2(dst0, dst1, dst, 16);
     33     src += 32;
     34     pred += 32;
     35     dst += 32;
     36     length -= 32;
     37   }
     38   if (length > 0) {
     39     int i;
     40     if (length >= 16) {
     41       src0 = LD_UB(src);
     42       pred0 = LD_UB(pred);
     43       dst0 = src0 - pred0;
     44       ST_UB(dst0, dst);
     45       src += 16;
     46       pred += 16;
     47       dst += 16;
     48       length -= 16;
     49     }
     50     for (i = 0; i < length; i++) {
     51       dst[i] = src[i] - pred[i];
     52     }
     53   }
     54 }
     55 
     56 //------------------------------------------------------------------------------
     57 // Helpful macro.
     58 
     59 #define SANITY_CHECK(in, out)  \
     60   assert(in != NULL);          \
     61   assert(out != NULL);         \
     62   assert(width > 0);           \
     63   assert(height > 0);          \
     64   assert(stride >= width);
     65 
     66 //------------------------------------------------------------------------------
     67 // Horrizontal filter
     68 
     69 static void HorizontalFilter(const uint8_t* data, int width, int height,
     70                              int stride, uint8_t* filtered_data) {
     71   const uint8_t* preds = data;
     72   const uint8_t* in = data;
     73   uint8_t* out = filtered_data;
     74   int row = 1;
     75   SANITY_CHECK(in, out);
     76 
     77   // Leftmost pixel is the same as input for topmost scanline.
     78   out[0] = in[0];
     79   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
     80   preds += stride;
     81   in += stride;
     82   out += stride;
     83   // Filter line-by-line.
     84   while (row < height) {
     85     // Leftmost pixel is predicted from above.
     86     PredictLineInverse0(in, preds - stride, out, 1);
     87     PredictLineInverse0(in + 1, preds, out + 1, width - 1);
     88     ++row;
     89     preds += stride;
     90     in += stride;
     91     out += stride;
     92   }
     93 }
     94 
     95 //------------------------------------------------------------------------------
     96 // Gradient filter
     97 
     98 static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput,
     99                                             const uint8_t* ppred,
    100                                             uint8_t* poutput, int stride,
    101                                             int size) {
    102   int w;
    103   const v16i8 zero = { 0 };
    104   while (size >= 16) {
    105     v16u8 pred0, dst0;
    106     v8i16 a0, a1, b0, b1, c0, c1;
    107     const v16u8 tmp0 = LD_UB(ppred - 1);
    108     const v16u8 tmp1 = LD_UB(ppred - stride);
    109     const v16u8 tmp2 = LD_UB(ppred - stride - 1);
    110     const v16u8 src0 = LD_UB(pinput);
    111     ILVRL_B2_SH(zero, tmp0, a0, a1);
    112     ILVRL_B2_SH(zero, tmp1, b0, b1);
    113     ILVRL_B2_SH(zero, tmp2, c0, c1);
    114     ADD2(a0, b0, a1, b1, a0, a1);
    115     SUB2(a0, c0, a1, c1, a0, a1);
    116     CLIP_SH2_0_255(a0, a1);
    117     pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0);
    118     dst0 = src0 - pred0;
    119     ST_UB(dst0, poutput);
    120     ppred += 16;
    121     pinput += 16;
    122     poutput += 16;
    123     size -= 16;
    124   }
    125   for (w = 0; w < size; ++w) {
    126     const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1];
    127     poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred);
    128   }
    129 }
    130 
    131 
    132 static void GradientFilter(const uint8_t* data, int width, int height,
    133                            int stride, uint8_t* filtered_data) {
    134   const uint8_t* in = data;
    135   const uint8_t* preds = data;
    136   uint8_t* out = filtered_data;
    137   int row = 1;
    138   SANITY_CHECK(in, out);
    139 
    140   // left prediction for top scan-line
    141   out[0] = in[0];
    142   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
    143   preds += stride;
    144   in += stride;
    145   out += stride;
    146   // Filter line-by-line.
    147   while (row < height) {
    148     out[0] = in[0] - preds[- stride];
    149     PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1);
    150     ++row;
    151     preds += stride;
    152     in += stride;
    153     out += stride;
    154   }
    155 }
    156 
    157 //------------------------------------------------------------------------------
    158 // Vertical filter
    159 
    160 static void VerticalFilter(const uint8_t* data, int width, int height,
    161                            int stride, uint8_t* filtered_data) {
    162   const uint8_t* in = data;
    163   const uint8_t* preds = data;
    164   uint8_t* out = filtered_data;
    165   int row = 1;
    166   SANITY_CHECK(in, out);
    167 
    168   // Very first top-left pixel is copied.
    169   out[0] = in[0];
    170   // Rest of top scan-line is left-predicted.
    171   PredictLineInverse0(in + 1, preds, out + 1, width - 1);
    172   in += stride;
    173   out += stride;
    174 
    175   // Filter line-by-line.
    176   while (row < height) {
    177     PredictLineInverse0(in, preds, out, width);
    178     ++row;
    179     preds += stride;
    180     in += stride;
    181     out += stride;
    182   }
    183 }
    184 
    185 #undef SANITY_CHECK
    186 
    187 //------------------------------------------------------------------------------
    188 // Entry point
    189 
    190 extern void VP8FiltersInitMSA(void);
    191 
    192 WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) {
    193   WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
    194   WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
    195   WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
    196 }
    197 
    198 #else  // !WEBP_USE_MSA
    199 
    200 WEBP_DSP_INIT_STUB(VP8FiltersInitMSA)
    201 
    202 #endif  // WEBP_USE_MSA
    203