1// Copyright 2014 Google Inc. All Rights Reserved. 2// 3// Use of this source code is governed by a BSD-style license 4// that can be found in the COPYING file in the root of the source 5// tree. An additional intellectual property rights grant can be found 6// in the file PATENTS. All contributing project authors may 7// be found in the AUTHORS file in the root of the source tree. 8// ----------------------------------------------------------------------------- 9// 10// Rescaling functions 11// 12// Author: Skal (pascal.massimino@gmail.com) 13 14#include <assert.h> 15 16#include "src/dsp/dsp.h" 17#include "src/utils/rescaler_utils.h" 18 19//------------------------------------------------------------------------------ 20// Implementations of critical functions ImportRow / ExportRow 21 22#define ROUNDER (WEBP_RESCALER_ONE >> 1) 23#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) 24 25//------------------------------------------------------------------------------ 26// Row import 27 28void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk, 29 const uint8_t* src) { 30 const int x_stride = wrk->num_channels; 31 const int x_out_max = wrk->dst_width * wrk->num_channels; 32 int channel; 33 assert(!WebPRescalerInputDone(wrk)); 34 assert(wrk->x_expand); 35 for (channel = 0; channel < x_stride; ++channel) { 36 int x_in = channel; 37 int x_out = channel; 38 // simple bilinear interpolation 39 int accum = wrk->x_add; 40 int left = src[x_in]; 41 int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left; 42 x_in += x_stride; 43 while (1) { 44 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; 45 x_out += x_stride; 46 if (x_out >= x_out_max) break; 47 accum -= wrk->x_sub; 48 if (accum < 0) { 49 left = right; 50 x_in += x_stride; 51 assert(x_in < wrk->src_width * x_stride); 52 right = src[x_in]; 53 accum += wrk->x_add; 54 } 55 } 56 assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); 57 } 58} 59 60void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk, 61 const uint8_t* src) { 62 const int x_stride = wrk->num_channels; 63 const int x_out_max = wrk->dst_width * wrk->num_channels; 64 int channel; 65 assert(!WebPRescalerInputDone(wrk)); 66 assert(!wrk->x_expand); 67 for (channel = 0; channel < x_stride; ++channel) { 68 int x_in = channel; 69 int x_out = channel; 70 uint32_t sum = 0; 71 int accum = 0; 72 while (x_out < x_out_max) { 73 uint32_t base = 0; 74 accum += wrk->x_add; 75 while (accum > 0) { 76 accum -= wrk->x_sub; 77 assert(x_in < wrk->src_width * x_stride); 78 base = src[x_in]; 79 sum += base; 80 x_in += x_stride; 81 } 82 { // Emit next horizontal pixel. 83 const rescaler_t frac = base * (-accum); 84 wrk->frow[x_out] = sum * wrk->x_sub - frac; 85 // fresh fractional start for next pixel 86 sum = (int)MULT_FIX(frac, wrk->fx_scale); 87 } 88 x_out += x_stride; 89 } 90 assert(accum == 0); 91 } 92} 93 94//------------------------------------------------------------------------------ 95// Row export 96 97void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) { 98 int x_out; 99 uint8_t* const dst = wrk->dst; 100 rescaler_t* const irow = wrk->irow; 101 const int x_out_max = wrk->dst_width * wrk->num_channels; 102 const rescaler_t* const frow = wrk->frow; 103 assert(!WebPRescalerOutputDone(wrk)); 104 assert(wrk->y_accum <= 0); 105 assert(wrk->y_expand); 106 assert(wrk->y_sub != 0); 107 if (wrk->y_accum == 0) { 108 for (x_out = 0; x_out < x_out_max; ++x_out) { 109 const uint32_t J = frow[x_out]; 110 const int v = (int)MULT_FIX(J, wrk->fy_scale); 111 assert(v >= 0 && v <= 255); 112 dst[x_out] = v; 113 } 114 } else { 115 const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); 116 const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); 117 for (x_out = 0; x_out < x_out_max; ++x_out) { 118 const uint64_t I = (uint64_t)A * frow[x_out] 119 + (uint64_t)B * irow[x_out]; 120 const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); 121 const int v = (int)MULT_FIX(J, wrk->fy_scale); 122 assert(v >= 0 && v <= 255); 123 dst[x_out] = v; 124 } 125 } 126} 127 128void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { 129 int x_out; 130 uint8_t* const dst = wrk->dst; 131 rescaler_t* const irow = wrk->irow; 132 const int x_out_max = wrk->dst_width * wrk->num_channels; 133 const rescaler_t* const frow = wrk->frow; 134 const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); 135 assert(!WebPRescalerOutputDone(wrk)); 136 assert(wrk->y_accum <= 0); 137 assert(!wrk->y_expand); 138 if (yscale) { 139 for (x_out = 0; x_out < x_out_max; ++x_out) { 140 const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); 141 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); 142 assert(v >= 0 && v <= 255); 143 dst[x_out] = v; 144 irow[x_out] = frac; // new fractional start 145 } 146 } else { 147 for (x_out = 0; x_out < x_out_max; ++x_out) { 148 const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); 149 assert(v >= 0 && v <= 255); 150 dst[x_out] = v; 151 irow[x_out] = 0; 152 } 153 } 154} 155 156#undef MULT_FIX 157#undef ROUNDER 158 159//------------------------------------------------------------------------------ 160// Main entry calls 161 162void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { 163 assert(!WebPRescalerInputDone(wrk)); 164 if (!wrk->x_expand) { 165 WebPRescalerImportRowShrink(wrk, src); 166 } else { 167 WebPRescalerImportRowExpand(wrk, src); 168 } 169} 170 171void WebPRescalerExportRow(WebPRescaler* const wrk) { 172 if (wrk->y_accum <= 0) { 173 assert(!WebPRescalerOutputDone(wrk)); 174 if (wrk->y_expand) { 175 WebPRescalerExportRowExpand(wrk); 176 } else if (wrk->fxy_scale) { 177 WebPRescalerExportRowShrink(wrk); 178 } else { // special case 179 int i; 180 assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); 181 assert(wrk->src_width == 1 && wrk->dst_width <= 2); 182 for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { 183 wrk->dst[i] = wrk->irow[i]; 184 wrk->irow[i] = 0; 185 } 186 } 187 wrk->y_accum += wrk->y_add; 188 wrk->dst += wrk->dst_stride; 189 ++wrk->dst_y; 190 } 191} 192 193//------------------------------------------------------------------------------ 194 195WebPRescalerImportRowFunc WebPRescalerImportRowExpand; 196WebPRescalerImportRowFunc WebPRescalerImportRowShrink; 197 198WebPRescalerExportRowFunc WebPRescalerExportRowExpand; 199WebPRescalerExportRowFunc WebPRescalerExportRowShrink; 200 201extern void WebPRescalerDspInitSSE2(void); 202extern void WebPRescalerDspInitMIPS32(void); 203extern void WebPRescalerDspInitMIPSdspR2(void); 204extern void WebPRescalerDspInitMSA(void); 205extern void WebPRescalerDspInitNEON(void); 206 207static volatile VP8CPUInfo rescaler_last_cpuinfo_used = 208 (VP8CPUInfo)&rescaler_last_cpuinfo_used; 209 210WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { 211 if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return; 212#if !defined(WEBP_REDUCE_SIZE) 213#if !WEBP_NEON_OMIT_C_CODE 214 WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C; 215 WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C; 216#endif 217 218 WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C; 219 WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C; 220 221 if (VP8GetCPUInfo != NULL) { 222#if defined(WEBP_USE_SSE2) 223 if (VP8GetCPUInfo(kSSE2)) { 224 WebPRescalerDspInitSSE2(); 225 } 226#endif 227#if defined(WEBP_USE_MIPS32) 228 if (VP8GetCPUInfo(kMIPS32)) { 229 WebPRescalerDspInitMIPS32(); 230 } 231#endif 232#if defined(WEBP_USE_MIPS_DSP_R2) 233 if (VP8GetCPUInfo(kMIPSdspR2)) { 234 WebPRescalerDspInitMIPSdspR2(); 235 } 236#endif 237#if defined(WEBP_USE_MSA) 238 if (VP8GetCPUInfo(kMSA)) { 239 WebPRescalerDspInitMSA(); 240 } 241#endif 242 } 243 244#if defined(WEBP_USE_NEON) 245 if (WEBP_NEON_OMIT_C_CODE || 246 (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { 247 WebPRescalerDspInitNEON(); 248 } 249#endif 250 251 assert(WebPRescalerExportRowExpand != NULL); 252 assert(WebPRescalerExportRowShrink != NULL); 253 assert(WebPRescalerImportRowExpand != NULL); 254 assert(WebPRescalerImportRowShrink != NULL); 255#endif // WEBP_REDUCE_SIZE 256 rescaler_last_cpuinfo_used = VP8GetCPUInfo; 257} 258