filters_msa.c (6112B)
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 22 static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, 23 const uint8_t* pred, 24 uint8_t* WEBP_RESTRICT dst, 25 int length) { 26 v16u8 src0, pred0, dst0; 27 assert(length >= 0); 28 while (length >= 32) { 29 v16u8 src1, pred1, dst1; 30 LD_UB2(src, 16, src0, src1); 31 LD_UB2(pred, 16, pred0, pred1); 32 SUB2(src0, pred0, src1, pred1, dst0, dst1); 33 ST_UB2(dst0, dst1, dst, 16); 34 src += 32; 35 pred += 32; 36 dst += 32; 37 length -= 32; 38 } 39 if (length > 0) { 40 int i; 41 if (length >= 16) { 42 src0 = LD_UB(src); 43 pred0 = LD_UB(pred); 44 dst0 = src0 - pred0; 45 ST_UB(dst0, dst); 46 src += 16; 47 pred += 16; 48 dst += 16; 49 length -= 16; 50 } 51 for (i = 0; i < length; i++) { 52 dst[i] = src[i] - pred[i]; 53 } 54 } 55 } 56 57 //------------------------------------------------------------------------------ 58 // Helpful macro. 59 60 #define DCHECK(in, out) \ 61 do { \ 62 assert((in) != NULL); \ 63 assert((out) != NULL); \ 64 assert((in) != (out)); \ 65 assert(width > 0); \ 66 assert(height > 0); \ 67 assert(stride >= width); \ 68 } while (0) 69 70 //------------------------------------------------------------------------------ 71 // Horrizontal filter 72 73 static void HorizontalFilter_MSA(const uint8_t* WEBP_RESTRICT data, 74 int width, int height, int stride, 75 uint8_t* WEBP_RESTRICT filtered_data) { 76 const uint8_t* preds = data; 77 const uint8_t* in = data; 78 uint8_t* out = filtered_data; 79 int row = 1; 80 DCHECK(in, out); 81 82 // Leftmost pixel is the same as input for topmost scanline. 83 out[0] = in[0]; 84 PredictLineInverse0(in + 1, preds, out + 1, width - 1); 85 preds += stride; 86 in += stride; 87 out += stride; 88 // Filter line-by-line. 89 while (row < height) { 90 // Leftmost pixel is predicted from above. 91 PredictLineInverse0(in, preds - stride, out, 1); 92 PredictLineInverse0(in + 1, preds, out + 1, width - 1); 93 ++row; 94 preds += stride; 95 in += stride; 96 out += stride; 97 } 98 } 99 100 //------------------------------------------------------------------------------ 101 // Gradient filter 102 103 static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, 104 const uint8_t* ppred, 105 uint8_t* WEBP_RESTRICT poutput, 106 int stride, int size) { 107 int w; 108 const v16i8 zero = { 0 }; 109 while (size >= 16) { 110 v16u8 pred0, dst0; 111 v8i16 a0, a1, b0, b1, c0, c1; 112 const v16u8 tmp0 = LD_UB(ppred - 1); 113 const v16u8 tmp1 = LD_UB(ppred - stride); 114 const v16u8 tmp2 = LD_UB(ppred - stride - 1); 115 const v16u8 src0 = LD_UB(pinput); 116 ILVRL_B2_SH(zero, tmp0, a0, a1); 117 ILVRL_B2_SH(zero, tmp1, b0, b1); 118 ILVRL_B2_SH(zero, tmp2, c0, c1); 119 ADD2(a0, b0, a1, b1, a0, a1); 120 SUB2(a0, c0, a1, c1, a0, a1); 121 CLIP_SH2_0_255(a0, a1); 122 pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); 123 dst0 = src0 - pred0; 124 ST_UB(dst0, poutput); 125 ppred += 16; 126 pinput += 16; 127 poutput += 16; 128 size -= 16; 129 } 130 for (w = 0; w < size; ++w) { 131 const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1]; 132 poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred); 133 } 134 } 135 136 137 static void GradientFilter_MSA(const uint8_t* WEBP_RESTRICT data, 138 int width, int height, int stride, 139 uint8_t* WEBP_RESTRICT filtered_data) { 140 const uint8_t* in = data; 141 const uint8_t* preds = data; 142 uint8_t* out = filtered_data; 143 int row = 1; 144 DCHECK(in, out); 145 146 // left prediction for top scan-line 147 out[0] = in[0]; 148 PredictLineInverse0(in + 1, preds, out + 1, width - 1); 149 preds += stride; 150 in += stride; 151 out += stride; 152 // Filter line-by-line. 153 while (row < height) { 154 out[0] = in[0] - preds[- stride]; 155 PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1); 156 ++row; 157 preds += stride; 158 in += stride; 159 out += stride; 160 } 161 } 162 163 //------------------------------------------------------------------------------ 164 // Vertical filter 165 166 static void VerticalFilter_MSA(const uint8_t* WEBP_RESTRICT data, 167 int width, int height, int stride, 168 uint8_t* WEBP_RESTRICT filtered_data) { 169 const uint8_t* in = data; 170 const uint8_t* preds = data; 171 uint8_t* out = filtered_data; 172 int row = 1; 173 DCHECK(in, out); 174 175 // Very first top-left pixel is copied. 176 out[0] = in[0]; 177 // Rest of top scan-line is left-predicted. 178 PredictLineInverse0(in + 1, preds, out + 1, width - 1); 179 in += stride; 180 out += stride; 181 182 // Filter line-by-line. 183 while (row < height) { 184 PredictLineInverse0(in, preds, out, width); 185 ++row; 186 preds += stride; 187 in += stride; 188 out += stride; 189 } 190 } 191 192 #undef DCHECK 193 194 //------------------------------------------------------------------------------ 195 // Entry point 196 197 extern void VP8FiltersInitMSA(void); 198 199 WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) { 200 WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA; 201 WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA; 202 WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA; 203 } 204 205 #else // !WEBP_USE_MSA 206 207 WEBP_DSP_INIT_STUB(VP8FiltersInitMSA) 208 209 #endif // WEBP_USE_MSA