Blame src/dsp/rescaler.c

Packit 9c6abc
// Copyright 2014 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
// Rescaling functions
Packit 9c6abc
//
Packit 9c6abc
// Author: Skal (pascal.massimino@gmail.com)
Packit 9c6abc
Packit 9c6abc
#include <assert.h>
Packit 9c6abc
Packit 9c6abc
#include "src/dsp/dsp.h"
Packit 9c6abc
#include "src/utils/rescaler_utils.h"
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Implementations of critical functions ImportRow / ExportRow
Packit 9c6abc
Packit 9c6abc
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
Packit 9c6abc
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Row import
Packit 9c6abc
Packit 9c6abc
void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
Packit 9c6abc
                                   const uint8_t* src) {
Packit 9c6abc
  const int x_stride = wrk->num_channels;
Packit 9c6abc
  const int x_out_max = wrk->dst_width * wrk->num_channels;
Packit 9c6abc
  int channel;
Packit 9c6abc
  assert(!WebPRescalerInputDone(wrk));
Packit 9c6abc
  assert(wrk->x_expand);
Packit 9c6abc
  for (channel = 0; channel < x_stride; ++channel) {
Packit 9c6abc
    int x_in = channel;
Packit 9c6abc
    int x_out = channel;
Packit 9c6abc
    // simple bilinear interpolation
Packit 9c6abc
    int accum = wrk->x_add;
Packit 9c6abc
    int left = src[x_in];
Packit 9c6abc
    int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
Packit 9c6abc
    x_in += x_stride;
Packit 9c6abc
    while (1) {
Packit 9c6abc
      wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
Packit 9c6abc
      x_out += x_stride;
Packit 9c6abc
      if (x_out >= x_out_max) break;
Packit 9c6abc
      accum -= wrk->x_sub;
Packit 9c6abc
      if (accum < 0) {
Packit 9c6abc
        left = right;
Packit 9c6abc
        x_in += x_stride;
Packit 9c6abc
        assert(x_in < wrk->src_width * x_stride);
Packit 9c6abc
        right = src[x_in];
Packit 9c6abc
        accum += wrk->x_add;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
Packit 9c6abc
                                   const uint8_t* src) {
Packit 9c6abc
  const int x_stride = wrk->num_channels;
Packit 9c6abc
  const int x_out_max = wrk->dst_width * wrk->num_channels;
Packit 9c6abc
  int channel;
Packit 9c6abc
  assert(!WebPRescalerInputDone(wrk));
Packit 9c6abc
  assert(!wrk->x_expand);
Packit 9c6abc
  for (channel = 0; channel < x_stride; ++channel) {
Packit 9c6abc
    int x_in = channel;
Packit 9c6abc
    int x_out = channel;
Packit 9c6abc
    uint32_t sum = 0;
Packit 9c6abc
    int accum = 0;
Packit 9c6abc
    while (x_out < x_out_max) {
Packit 9c6abc
      uint32_t base = 0;
Packit 9c6abc
      accum += wrk->x_add;
Packit 9c6abc
      while (accum > 0) {
Packit 9c6abc
        accum -= wrk->x_sub;
Packit 9c6abc
        assert(x_in < wrk->src_width * x_stride);
Packit 9c6abc
        base = src[x_in];
Packit 9c6abc
        sum += base;
Packit 9c6abc
        x_in += x_stride;
Packit 9c6abc
      }
Packit 9c6abc
      {        // Emit next horizontal pixel.
Packit 9c6abc
        const rescaler_t frac = base * (-accum);
Packit 9c6abc
        wrk->frow[x_out] = sum * wrk->x_sub - frac;
Packit 9c6abc
        // fresh fractional start for next pixel
Packit 9c6abc
        sum = (int)MULT_FIX(frac, wrk->fx_scale);
Packit 9c6abc
      }
Packit 9c6abc
      x_out += x_stride;
Packit 9c6abc
    }
Packit 9c6abc
    assert(accum == 0);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Row export
Packit 9c6abc
Packit 9c6abc
void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
Packit 9c6abc
  int x_out;
Packit 9c6abc
  uint8_t* const dst = wrk->dst;
Packit 9c6abc
  rescaler_t* const irow = wrk->irow;
Packit 9c6abc
  const int x_out_max = wrk->dst_width * wrk->num_channels;
Packit 9c6abc
  const rescaler_t* const frow = wrk->frow;
Packit 9c6abc
  assert(!WebPRescalerOutputDone(wrk));
Packit 9c6abc
  assert(wrk->y_accum <= 0);
Packit 9c6abc
  assert(wrk->y_expand);
Packit 9c6abc
  assert(wrk->y_sub != 0);
Packit 9c6abc
  if (wrk->y_accum == 0) {
Packit 9c6abc
    for (x_out = 0; x_out < x_out_max; ++x_out) {
Packit 9c6abc
      const uint32_t J = frow[x_out];
Packit 9c6abc
      const int v = (int)MULT_FIX(J, wrk->fy_scale);
Packit 9c6abc
      assert(v >= 0 && v <= 255);
Packit 9c6abc
      dst[x_out] = v;
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
Packit 9c6abc
    const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
Packit 9c6abc
    for (x_out = 0; x_out < x_out_max; ++x_out) {
Packit 9c6abc
      const uint64_t I = (uint64_t)A * frow[x_out]
Packit 9c6abc
                       + (uint64_t)B * irow[x_out];
Packit 9c6abc
      const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
Packit 9c6abc
      const int v = (int)MULT_FIX(J, wrk->fy_scale);
Packit 9c6abc
      assert(v >= 0 && v <= 255);
Packit 9c6abc
      dst[x_out] = v;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
Packit 9c6abc
  int x_out;
Packit 9c6abc
  uint8_t* const dst = wrk->dst;
Packit 9c6abc
  rescaler_t* const irow = wrk->irow;
Packit 9c6abc
  const int x_out_max = wrk->dst_width * wrk->num_channels;
Packit 9c6abc
  const rescaler_t* const frow = wrk->frow;
Packit 9c6abc
  const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
Packit 9c6abc
  assert(!WebPRescalerOutputDone(wrk));
Packit 9c6abc
  assert(wrk->y_accum <= 0);
Packit 9c6abc
  assert(!wrk->y_expand);
Packit 9c6abc
  if (yscale) {
Packit 9c6abc
    for (x_out = 0; x_out < x_out_max; ++x_out) {
Packit 9c6abc
      const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
Packit 9c6abc
      const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
Packit 9c6abc
      assert(v >= 0 && v <= 255);
Packit 9c6abc
      dst[x_out] = v;
Packit 9c6abc
      irow[x_out] = frac;   // new fractional start
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    for (x_out = 0; x_out < x_out_max; ++x_out) {
Packit 9c6abc
      const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
Packit 9c6abc
      assert(v >= 0 && v <= 255);
Packit 9c6abc
      dst[x_out] = v;
Packit 9c6abc
      irow[x_out] = 0;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#undef MULT_FIX
Packit 9c6abc
#undef ROUNDER
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Main entry calls
Packit 9c6abc
Packit 9c6abc
void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
Packit 9c6abc
  assert(!WebPRescalerInputDone(wrk));
Packit 9c6abc
  if (!wrk->x_expand) {
Packit 9c6abc
    WebPRescalerImportRowShrink(wrk, src);
Packit 9c6abc
  } else {
Packit 9c6abc
    WebPRescalerImportRowExpand(wrk, src);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
void WebPRescalerExportRow(WebPRescaler* const wrk) {
Packit 9c6abc
  if (wrk->y_accum <= 0) {
Packit 9c6abc
    assert(!WebPRescalerOutputDone(wrk));
Packit 9c6abc
    if (wrk->y_expand) {
Packit 9c6abc
      WebPRescalerExportRowExpand(wrk);
Packit 9c6abc
    } else if (wrk->fxy_scale) {
Packit 9c6abc
      WebPRescalerExportRowShrink(wrk);
Packit 9c6abc
    } else {  // special case
Packit 9c6abc
      int i;
Packit 9c6abc
      assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
Packit 9c6abc
      assert(wrk->src_width == 1 && wrk->dst_width <= 2);
Packit 9c6abc
      for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
Packit 9c6abc
        wrk->dst[i] = wrk->irow[i];
Packit 9c6abc
        wrk->irow[i] = 0;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    wrk->y_accum += wrk->y_add;
Packit 9c6abc
    wrk->dst += wrk->dst_stride;
Packit 9c6abc
    ++wrk->dst_y;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
Packit 9c6abc
WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
Packit 9c6abc
Packit 9c6abc
WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
Packit 9c6abc
WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
Packit 9c6abc
Packit 9c6abc
extern void WebPRescalerDspInitSSE2(void);
Packit 9c6abc
extern void WebPRescalerDspInitMIPS32(void);
Packit 9c6abc
extern void WebPRescalerDspInitMIPSdspR2(void);
Packit 9c6abc
extern void WebPRescalerDspInitMSA(void);
Packit 9c6abc
extern void WebPRescalerDspInitNEON(void);
Packit 9c6abc
Packit 9c6abc
WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
Packit 9c6abc
#if !defined(WEBP_REDUCE_SIZE)
Packit 9c6abc
#if !WEBP_NEON_OMIT_C_CODE
Packit 9c6abc
  WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
Packit 9c6abc
  WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
Packit 9c6abc
#endif
Packit 9c6abc
Packit 9c6abc
  WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
Packit 9c6abc
  WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
Packit 9c6abc
Packit 9c6abc
  if (VP8GetCPUInfo != NULL) {
Packit 9c6abc
#if defined(WEBP_USE_SSE2)
Packit 9c6abc
    if (VP8GetCPUInfo(kSSE2)) {
Packit 9c6abc
      WebPRescalerDspInitSSE2();
Packit 9c6abc
    }
Packit 9c6abc
#endif
Packit 9c6abc
#if defined(WEBP_USE_MIPS32)
Packit 9c6abc
    if (VP8GetCPUInfo(kMIPS32)) {
Packit 9c6abc
      WebPRescalerDspInitMIPS32();
Packit 9c6abc
    }
Packit 9c6abc
#endif
Packit 9c6abc
#if defined(WEBP_USE_MIPS_DSP_R2)
Packit 9c6abc
    if (VP8GetCPUInfo(kMIPSdspR2)) {
Packit 9c6abc
      WebPRescalerDspInitMIPSdspR2();
Packit 9c6abc
    }
Packit 9c6abc
#endif
Packit 9c6abc
#if defined(WEBP_USE_MSA)
Packit 9c6abc
    if (VP8GetCPUInfo(kMSA)) {
Packit 9c6abc
      WebPRescalerDspInitMSA();
Packit 9c6abc
    }
Packit 9c6abc
#endif
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
#if defined(WEBP_USE_NEON)
Packit 9c6abc
  if (WEBP_NEON_OMIT_C_CODE ||
Packit 9c6abc
      (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
Packit 9c6abc
    WebPRescalerDspInitNEON();
Packit 9c6abc
  }
Packit 9c6abc
#endif
Packit 9c6abc
Packit 9c6abc
  assert(WebPRescalerExportRowExpand != NULL);
Packit 9c6abc
  assert(WebPRescalerExportRowShrink != NULL);
Packit 9c6abc
  assert(WebPRescalerImportRowExpand != NULL);
Packit 9c6abc
  assert(WebPRescalerImportRowShrink != NULL);
Packit 9c6abc
#endif   // WEBP_REDUCE_SIZE
Packit 9c6abc
}