diff options
Diffstat (limited to 'thirdparty/libwebp/dsp/rescaler.c')
| -rw-r--r-- | thirdparty/libwebp/dsp/rescaler.c | 238 | 
1 files changed, 238 insertions, 0 deletions
diff --git a/thirdparty/libwebp/dsp/rescaler.c b/thirdparty/libwebp/dsp/rescaler.c new file mode 100644 index 0000000000..bc743d5dc5 --- /dev/null +++ b/thirdparty/libwebp/dsp/rescaler.c @@ -0,0 +1,238 @@ +// Copyright 2014 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. +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include <assert.h> + +#include "./dsp.h" +#include "../utils/rescaler.h" + +//------------------------------------------------------------------------------ +// Implementations of critical functions ImportRow / ExportRow + +#define ROUNDER (WEBP_RESCALER_ONE >> 1) +#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) + +//------------------------------------------------------------------------------ +// Row import + +void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) { +  const int x_stride = wrk->num_channels; +  const int x_out_max = wrk->dst_width * wrk->num_channels; +  int channel; +  assert(!WebPRescalerInputDone(wrk)); +  assert(wrk->x_expand); +  for (channel = 0; channel < x_stride; ++channel) { +    int x_in = channel; +    int x_out = channel; +    // simple bilinear interpolation +    int accum = wrk->x_add; +    int left = src[x_in]; +    int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left; +    x_in += x_stride; +    while (1) { +      wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; +      x_out += x_stride; +      if (x_out >= x_out_max) break; +      accum -= wrk->x_sub; +      if (accum < 0) { +        left = right; +        x_in += x_stride; +        assert(x_in < wrk->src_width * x_stride); +        right = src[x_in]; +        accum += wrk->x_add; +      } +    } +    assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); +  } +} + +void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) { +  const int x_stride = wrk->num_channels; +  const int x_out_max = wrk->dst_width * wrk->num_channels; +  int channel; +  assert(!WebPRescalerInputDone(wrk)); +  assert(!wrk->x_expand); +  for (channel = 0; channel < x_stride; ++channel) { +    int x_in = channel; +    int x_out = channel; +    uint32_t sum = 0; +    int accum = 0; +    while (x_out < x_out_max) { +      uint32_t base = 0; +      accum += wrk->x_add; +      while (accum > 0) { +        accum -= wrk->x_sub; +        assert(x_in < wrk->src_width * x_stride); +        base = src[x_in]; +        sum += base; +        x_in += x_stride; +      } +      {        // Emit next horizontal pixel. +        const rescaler_t frac = base * (-accum); +        wrk->frow[x_out] = sum * wrk->x_sub - frac; +        // fresh fractional start for next pixel +        sum = (int)MULT_FIX(frac, wrk->fx_scale); +      } +      x_out += x_stride; +    } +    assert(accum == 0); +  } +} + +//------------------------------------------------------------------------------ +// Row export + +void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) { +  int x_out; +  uint8_t* const dst = wrk->dst; +  rescaler_t* const irow = wrk->irow; +  const int x_out_max = wrk->dst_width * wrk->num_channels; +  const rescaler_t* const frow = wrk->frow; +  assert(!WebPRescalerOutputDone(wrk)); +  assert(wrk->y_accum <= 0); +  assert(wrk->y_expand); +  assert(wrk->y_sub != 0); +  if (wrk->y_accum == 0) { +    for (x_out = 0; x_out < x_out_max; ++x_out) { +      const uint32_t J = frow[x_out]; +      const int v = (int)MULT_FIX(J, wrk->fy_scale); +      assert(v >= 0 && v <= 255); +      dst[x_out] = v; +    } +  } else { +    const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); +    const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); +    for (x_out = 0; x_out < x_out_max; ++x_out) { +      const uint64_t I = (uint64_t)A * frow[x_out] +                       + (uint64_t)B * irow[x_out]; +      const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); +      const int v = (int)MULT_FIX(J, wrk->fy_scale); +      assert(v >= 0 && v <= 255); +      dst[x_out] = v; +    } +  } +} + +void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) { +  int x_out; +  uint8_t* const dst = wrk->dst; +  rescaler_t* const irow = wrk->irow; +  const int x_out_max = wrk->dst_width * wrk->num_channels; +  const rescaler_t* const frow = wrk->frow; +  const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); +  assert(!WebPRescalerOutputDone(wrk)); +  assert(wrk->y_accum <= 0); +  assert(!wrk->y_expand); +  if (yscale) { +    for (x_out = 0; x_out < x_out_max; ++x_out) { +      const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); +      const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); +      assert(v >= 0 && v <= 255); +      dst[x_out] = v; +      irow[x_out] = frac;   // new fractional start +    } +  } else { +    for (x_out = 0; x_out < x_out_max; ++x_out) { +      const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); +      assert(v >= 0 && v <= 255); +      dst[x_out] = v; +      irow[x_out] = 0; +    } +  } +} + +#undef MULT_FIX +#undef ROUNDER + +//------------------------------------------------------------------------------ +// Main entry calls + +void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { +  assert(!WebPRescalerInputDone(wrk)); +  if (!wrk->x_expand) { +    WebPRescalerImportRowShrink(wrk, src); +  } else { +    WebPRescalerImportRowExpand(wrk, src); +  } +} + +void WebPRescalerExportRow(WebPRescaler* const wrk) { +  if (wrk->y_accum <= 0) { +    assert(!WebPRescalerOutputDone(wrk)); +    if (wrk->y_expand) { +      WebPRescalerExportRowExpand(wrk); +    } else if (wrk->fxy_scale) { +      WebPRescalerExportRowShrink(wrk); +    } else {  // very special case for src = dst = 1x1 +      int i; +      assert(wrk->src_width == 1 && wrk->dst_width <= 2); +      assert(wrk->src_height == 1 && wrk->dst_height == 1); +      for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { +        wrk->dst[i] = wrk->irow[i]; +        wrk->irow[i] = 0; +      } +    } +    wrk->y_accum += wrk->y_add; +    wrk->dst += wrk->dst_stride; +    ++wrk->dst_y; +  } +} + +//------------------------------------------------------------------------------ + +WebPRescalerImportRowFunc WebPRescalerImportRowExpand; +WebPRescalerImportRowFunc WebPRescalerImportRowShrink; + +WebPRescalerExportRowFunc WebPRescalerExportRowExpand; +WebPRescalerExportRowFunc WebPRescalerExportRowShrink; + +extern void WebPRescalerDspInitSSE2(void); +extern void WebPRescalerDspInitMIPS32(void); +extern void WebPRescalerDspInitMIPSdspR2(void); +extern void WebPRescalerDspInitNEON(void); + +static volatile VP8CPUInfo rescaler_last_cpuinfo_used = +    (VP8CPUInfo)&rescaler_last_cpuinfo_used; + +WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { +  if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return; + +  WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC; +  WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC; +  WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC; +  WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC; + +  if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_USE_SSE2) +    if (VP8GetCPUInfo(kSSE2)) { +      WebPRescalerDspInitSSE2(); +    } +#endif +#if defined(WEBP_USE_NEON) +    if (VP8GetCPUInfo(kNEON)) { +      WebPRescalerDspInitNEON(); +    } +#endif +#if defined(WEBP_USE_MIPS32) +    if (VP8GetCPUInfo(kMIPS32)) { +      WebPRescalerDspInitMIPS32(); +    } +#endif +#if defined(WEBP_USE_MIPS_DSP_R2) +    if (VP8GetCPUInfo(kMIPSdspR2)) { +      WebPRescalerDspInitMIPSdspR2(); +    } +#endif +  } +  rescaler_last_cpuinfo_used = VP8GetCPUInfo; +}  |