Blame src/dsp/filters_msa.c

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