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@imgtec.com)
13
14#include "src/dsp/dsp.h"
15
16#if defined(WEBP_USE_MSA)
17
18#include "src/dsp/msa_macro.h"
19
20#include <assert.h>
21
22static 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
69static void HorizontalFilter_MSA(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
98static 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
132static void GradientFilter_MSA(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
160static void VerticalFilter_MSA(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
190extern void VP8FiltersInitMSA(void);
191
192WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) {
193  WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA;
194  WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA;
195  WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA;
196}
197
198#else  // !WEBP_USE_MSA
199
200WEBP_DSP_INIT_STUB(VP8FiltersInitMSA)
201
202#endif  // WEBP_USE_MSA
203