// Copyright 2016 Google Inc. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the COPYING file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. // ----------------------------------------------------------------------------- // // MSA variant of alpha filters // // Author: Prashant Patil (prashant.patil@imgtec.com) #include "src/dsp/dsp.h" #if defined(WEBP_USE_MSA) #include "src/dsp/msa_macro.h" #include static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, const uint8_t* pred, uint8_t* dst, int length) { v16u8 src0, pred0, dst0; assert(length >= 0); while (length >= 32) { v16u8 src1, pred1, dst1; LD_UB2(src, 16, src0, src1); LD_UB2(pred, 16, pred0, pred1); SUB2(src0, pred0, src1, pred1, dst0, dst1); ST_UB2(dst0, dst1, dst, 16); src += 32; pred += 32; dst += 32; length -= 32; } if (length > 0) { int i; if (length >= 16) { src0 = LD_UB(src); pred0 = LD_UB(pred); dst0 = src0 - pred0; ST_UB(dst0, dst); src += 16; pred += 16; dst += 16; length -= 16; } for (i = 0; i < length; i++) { dst[i] = src[i] - pred[i]; } } } //------------------------------------------------------------------------------ // Helpful macro. #define SANITY_CHECK(in, out) \ assert(in != NULL); \ assert(out != NULL); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); //------------------------------------------------------------------------------ // Horrizontal filter static void HorizontalFilter_MSA(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { const uint8_t* preds = data; const uint8_t* in = data; uint8_t* out = filtered_data; int row = 1; SANITY_CHECK(in, out); // Leftmost pixel is the same as input for topmost scanline. out[0] = in[0]; PredictLineInverse0(in + 1, preds, out + 1, width - 1); preds += stride; in += stride; out += stride; // Filter line-by-line. while (row < height) { // Leftmost pixel is predicted from above. PredictLineInverse0(in, preds - stride, out, 1); PredictLineInverse0(in + 1, preds, out + 1, width - 1); ++row; preds += stride; in += stride; out += stride; } } //------------------------------------------------------------------------------ // Gradient filter static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, const uint8_t* ppred, uint8_t* poutput, int stride, int size) { int w; const v16i8 zero = { 0 }; while (size >= 16) { v16u8 pred0, dst0; v8i16 a0, a1, b0, b1, c0, c1; const v16u8 tmp0 = LD_UB(ppred - 1); const v16u8 tmp1 = LD_UB(ppred - stride); const v16u8 tmp2 = LD_UB(ppred - stride - 1); const v16u8 src0 = LD_UB(pinput); ILVRL_B2_SH(zero, tmp0, a0, a1); ILVRL_B2_SH(zero, tmp1, b0, b1); ILVRL_B2_SH(zero, tmp2, c0, c1); ADD2(a0, b0, a1, b1, a0, a1); SUB2(a0, c0, a1, c1, a0, a1); CLIP_SH2_0_255(a0, a1); pred0 = (v16u8)__msa_pckev_b((v16i8)a1, (v16i8)a0); dst0 = src0 - pred0; ST_UB(dst0, poutput); ppred += 16; pinput += 16; poutput += 16; size -= 16; } for (w = 0; w < size; ++w) { const int pred = ppred[w - 1] + ppred[w - stride] - ppred[w - stride - 1]; poutput[w] = pinput[w] - (pred < 0 ? 0 : pred > 255 ? 255 : pred); } } static void GradientFilter_MSA(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { const uint8_t* in = data; const uint8_t* preds = data; uint8_t* out = filtered_data; int row = 1; SANITY_CHECK(in, out); // left prediction for top scan-line out[0] = in[0]; PredictLineInverse0(in + 1, preds, out + 1, width - 1); preds += stride; in += stride; out += stride; // Filter line-by-line. while (row < height) { out[0] = in[0] - preds[- stride]; PredictLineGradient(preds + 1, in + 1, out + 1, stride, width - 1); ++row; preds += stride; in += stride; out += stride; } } //------------------------------------------------------------------------------ // Vertical filter static void VerticalFilter_MSA(const uint8_t* data, int width, int height, int stride, uint8_t* filtered_data) { const uint8_t* in = data; const uint8_t* preds = data; uint8_t* out = filtered_data; int row = 1; SANITY_CHECK(in, out); // Very first top-left pixel is copied. out[0] = in[0]; // Rest of top scan-line is left-predicted. PredictLineInverse0(in + 1, preds, out + 1, width - 1); in += stride; out += stride; // Filter line-by-line. while (row < height) { PredictLineInverse0(in, preds, out, width); ++row; preds += stride; in += stride; out += stride; } } #undef SANITY_CHECK //------------------------------------------------------------------------------ // Entry point extern void VP8FiltersInitMSA(void); WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMSA(void) { WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_MSA; WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_MSA; WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_MSA; } #else // !WEBP_USE_MSA WEBP_DSP_INIT_STUB(VP8FiltersInitMSA) #endif // WEBP_USE_MSA