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 #define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) 25 26 //------------------------------------------------------------------------------ 27 // Row import 28 29 void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk, 30 const uint8_t* src) { 31 const int x_stride = wrk->num_channels; 32 const int x_out_max = wrk->dst_width * wrk->num_channels; 33 int channel; 34 assert(!WebPRescalerInputDone(wrk)); 35 assert(wrk->x_expand); 36 for (channel = 0; channel < x_stride; ++channel) { 37 int x_in = channel; 38 int x_out = channel; 39 // simple bilinear interpolation 40 int accum = wrk->x_add; 41 int left = src[x_in]; 42 int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left; 43 x_in += x_stride; 44 while (1) { 45 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; 46 x_out += x_stride; 47 if (x_out >= x_out_max) break; 48 accum -= wrk->x_sub; 49 if (accum < 0) { 50 left = right; 51 x_in += x_stride; 52 assert(x_in < wrk->src_width * x_stride); 53 right = src[x_in]; 54 accum += wrk->x_add; 55 } 56 } 57 assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); 58 } 59 } 60 61 void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk, 62 const uint8_t* src) { 63 const int x_stride = wrk->num_channels; 64 const int x_out_max = wrk->dst_width * wrk->num_channels; 65 int channel; 66 assert(!WebPRescalerInputDone(wrk)); 67 assert(!wrk->x_expand); 68 for (channel = 0; channel < x_stride; ++channel) { 69 int x_in = channel; 70 int x_out = channel; 71 uint32_t sum = 0; 72 int accum = 0; 73 while (x_out < x_out_max) { 74 uint32_t base = 0; 75 accum += wrk->x_add; 76 while (accum > 0) { 77 accum -= wrk->x_sub; 78 assert(x_in < wrk->src_width * x_stride); 79 base = src[x_in]; 80 sum += base; 81 x_in += x_stride; 82 } 83 { // Emit next horizontal pixel. 84 const rescaler_t frac = base * (-accum); 85 wrk->frow[x_out] = sum * wrk->x_sub - frac; 86 // fresh fractional start for next pixel 87 sum = (int)MULT_FIX(frac, wrk->fx_scale); 88 } 89 x_out += x_stride; 90 } 91 assert(accum == 0); 92 } 93 } 94 95 //------------------------------------------------------------------------------ 96 // Row export 97 98 void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) { 99 int x_out; 100 uint8_t* const dst = wrk->dst; 101 rescaler_t* const irow = wrk->irow; 102 const int x_out_max = wrk->dst_width * wrk->num_channels; 103 const rescaler_t* const frow = wrk->frow; 104 assert(!WebPRescalerOutputDone(wrk)); 105 assert(wrk->y_accum <= 0); 106 assert(wrk->y_expand); 107 assert(wrk->y_sub != 0); 108 if (wrk->y_accum == 0) { 109 for (x_out = 0; x_out < x_out_max; ++x_out) { 110 const uint32_t J = frow[x_out]; 111 const int v = (int)MULT_FIX(J, wrk->fy_scale); 112 assert(v >= 0 && v <= 255); 113 dst[x_out] = v; 114 } 115 } else { 116 const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); 117 const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); 118 for (x_out = 0; x_out < x_out_max; ++x_out) { 119 const uint64_t I = (uint64_t)A * frow[x_out] 120 + (uint64_t)B * irow[x_out]; 121 const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); 122 const int v = (int)MULT_FIX(J, wrk->fy_scale); 123 assert(v >= 0 && v <= 255); 124 dst[x_out] = v; 125 } 126 } 127 } 128 129 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { 130 int x_out; 131 uint8_t* const dst = wrk->dst; 132 rescaler_t* const irow = wrk->irow; 133 const int x_out_max = wrk->dst_width * wrk->num_channels; 134 const rescaler_t* const frow = wrk->frow; 135 const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); 136 assert(!WebPRescalerOutputDone(wrk)); 137 assert(wrk->y_accum <= 0); 138 assert(!wrk->y_expand); 139 if (yscale) { 140 for (x_out = 0; x_out < x_out_max; ++x_out) { 141 const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); 142 const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); 143 assert(v >= 0 && v <= 255); 144 dst[x_out] = v; 145 irow[x_out] = frac; // new fractional start 146 } 147 } else { 148 for (x_out = 0; x_out < x_out_max; ++x_out) { 149 const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); 150 assert(v >= 0 && v <= 255); 151 dst[x_out] = v; 152 irow[x_out] = 0; 153 } 154 } 155 } 156 157 #undef MULT_FIX_FLOOR 158 #undef MULT_FIX 159 #undef ROUNDER 160 161 //------------------------------------------------------------------------------ 162 // Main entry calls 163 164 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { 165 assert(!WebPRescalerInputDone(wrk)); 166 if (!wrk->x_expand) { 167 WebPRescalerImportRowShrink(wrk, src); 168 } else { 169 WebPRescalerImportRowExpand(wrk, src); 170 } 171 } 172 173 void WebPRescalerExportRow(WebPRescaler* const wrk) { 174 if (wrk->y_accum <= 0) { 175 assert(!WebPRescalerOutputDone(wrk)); 176 if (wrk->y_expand) { 177 WebPRescalerExportRowExpand(wrk); 178 } else if (wrk->fxy_scale) { 179 WebPRescalerExportRowShrink(wrk); 180 } else { // special case 181 int i; 182 assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); 183 assert(wrk->src_width == 1 && wrk->dst_width <= 2); 184 for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { 185 wrk->dst[i] = wrk->irow[i]; 186 wrk->irow[i] = 0; 187 } 188 } 189 wrk->y_accum += wrk->y_add; 190 wrk->dst += wrk->dst_stride; 191 ++wrk->dst_y; 192 } 193 } 194 195 //------------------------------------------------------------------------------ 196 197 WebPRescalerImportRowFunc WebPRescalerImportRowExpand; 198 WebPRescalerImportRowFunc WebPRescalerImportRowShrink; 199 200 WebPRescalerExportRowFunc WebPRescalerExportRowExpand; 201 WebPRescalerExportRowFunc WebPRescalerExportRowShrink; 202 203 extern void WebPRescalerDspInitSSE2(void); 204 extern void WebPRescalerDspInitMIPS32(void); 205 extern void WebPRescalerDspInitMIPSdspR2(void); 206 extern void WebPRescalerDspInitMSA(void); 207 extern void WebPRescalerDspInitNEON(void); 208 209 WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) { 210 #if !defined(WEBP_REDUCE_SIZE) 211 #if !WEBP_NEON_OMIT_C_CODE 212 WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C; 213 WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C; 214 #endif 215 216 WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C; 217 WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C; 218 219 if (VP8GetCPUInfo != NULL) { 220 #if defined(WEBP_USE_SSE2) 221 if (VP8GetCPUInfo(kSSE2)) { 222 WebPRescalerDspInitSSE2(); 223 } 224 #endif 225 #if defined(WEBP_USE_MIPS32) 226 if (VP8GetCPUInfo(kMIPS32)) { 227 WebPRescalerDspInitMIPS32(); 228 } 229 #endif 230 #if defined(WEBP_USE_MIPS_DSP_R2) 231 if (VP8GetCPUInfo(kMIPSdspR2)) { 232 WebPRescalerDspInitMIPSdspR2(); 233 } 234 #endif 235 #if defined(WEBP_USE_MSA) 236 if (VP8GetCPUInfo(kMSA)) { 237 WebPRescalerDspInitMSA(); 238 } 239 #endif 240 } 241 242 #if defined(WEBP_USE_NEON) 243 if (WEBP_NEON_OMIT_C_CODE || 244 (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { 245 WebPRescalerDspInitNEON(); 246 } 247 #endif 248 249 assert(WebPRescalerExportRowExpand != NULL); 250 assert(WebPRescalerExportRowShrink != NULL); 251 assert(WebPRescalerImportRowExpand != NULL); 252 assert(WebPRescalerImportRowShrink != NULL); 253 #endif // WEBP_REDUCE_SIZE 254 } 255