Index: third_party/libwebp/dsp/rescaler.c |
diff --git a/third_party/libwebp/dsp/rescaler.c b/third_party/libwebp/dsp/rescaler.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bc743d5dc54ff239692593d39a33aef14313275a |
--- /dev/null |
+++ b/third_party/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; |
+} |