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