rescaler.c (8304B)
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 #include <stddef.h> 16 17 #include "src/dsp/cpu.h" 18 #include "src/webp/types.h" 19 #include "src/dsp/dsp.h" 20 #include "src/utils/rescaler_utils.h" 21 22 //------------------------------------------------------------------------------ 23 // Implementations of critical functions ImportRow / ExportRow 24 25 #define ROUNDER (WEBP_RESCALER_ONE >> 1) 26 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) 27 #define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) 28 29 //------------------------------------------------------------------------------ 30 // Row import 31 32 void WebPRescalerImportRowExpand_C(WebPRescaler* WEBP_RESTRICT const wrk, 33 const uint8_t* WEBP_RESTRICT src) { 34 const int x_stride = wrk->num_channels; 35 const int x_out_max = wrk->dst_width * wrk->num_channels; 36 int channel; 37 assert(!WebPRescalerInputDone(wrk)); 38 assert(wrk->x_expand); 39 for (channel = 0; channel < x_stride; ++channel) { 40 int x_in = channel; 41 int x_out = channel; 42 // simple bilinear interpolation 43 int accum = wrk->x_add; 44 rescaler_t left = (rescaler_t)src[x_in]; 45 rescaler_t right = 46 (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left; 47 x_in += x_stride; 48 while (1) { 49 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; 50 x_out += x_stride; 51 if (x_out >= x_out_max) break; 52 accum -= wrk->x_sub; 53 if (accum < 0) { 54 left = right; 55 x_in += x_stride; 56 assert(x_in < wrk->src_width * x_stride); 57 right = (rescaler_t)src[x_in]; 58 accum += wrk->x_add; 59 } 60 } 61 assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); 62 } 63 } 64 65 void WebPRescalerImportRowShrink_C(WebPRescaler* WEBP_RESTRICT const wrk, 66 const uint8_t* WEBP_RESTRICT src) { 67 const int x_stride = wrk->num_channels; 68 const int x_out_max = wrk->dst_width * wrk->num_channels; 69 int channel; 70 assert(!WebPRescalerInputDone(wrk)); 71 assert(!wrk->x_expand); 72 for (channel = 0; channel < x_stride; ++channel) { 73 int x_in = channel; 74 int x_out = channel; 75 uint32_t sum = 0; 76 int accum = 0; 77 while (x_out < x_out_max) { 78 uint32_t base = 0; 79 accum += wrk->x_add; 80 while (accum > 0) { 81 accum -= wrk->x_sub; 82 assert(x_in < wrk->src_width * x_stride); 83 base = src[x_in]; 84 sum += base; 85 x_in += x_stride; 86 } 87 { // Emit next horizontal pixel. 88 const rescaler_t frac = base * (-accum); 89 wrk->frow[x_out] = sum * wrk->x_sub - frac; 90 // fresh fractional start for next pixel 91 sum = (int)MULT_FIX(frac, wrk->fx_scale); 92 } 93 x_out += x_stride; 94 } 95 assert(accum == 0); 96 } 97 } 98 99 //------------------------------------------------------------------------------ 100 // Row export 101 102 void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) { 103 int x_out; 104 uint8_t* const dst = wrk->dst; 105 rescaler_t* const irow = wrk->irow; 106 const int x_out_max = wrk->dst_width * wrk->num_channels; 107 const rescaler_t* const frow = wrk->frow; 108 assert(!WebPRescalerOutputDone(wrk)); 109 assert(wrk->y_accum <= 0); 110 assert(wrk->y_expand); 111 assert(wrk->y_sub != 0); 112 if (wrk->y_accum == 0) { 113 for (x_out = 0; x_out < x_out_max; ++x_out) { 114 const uint32_t J = frow[x_out]; 115 const int v = (int)MULT_FIX(J, wrk->fy_scale); 116 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 117 } 118 } else { 119 const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); 120 const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); 121 for (x_out = 0; x_out < x_out_max; ++x_out) { 122 const uint64_t I = (uint64_t)A * frow[x_out] 123 + (uint64_t)B * irow[x_out]; 124 const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); 125 const int v = (int)MULT_FIX(J, wrk->fy_scale); 126 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 127 } 128 } 129 } 130 131 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { 132 int x_out; 133 uint8_t* const dst = wrk->dst; 134 rescaler_t* const irow = wrk->irow; 135 const int x_out_max = wrk->dst_width * wrk->num_channels; 136 const rescaler_t* const frow = wrk->frow; 137 const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); 138 assert(!WebPRescalerOutputDone(wrk)); 139 assert(wrk->y_accum <= 0); 140 assert(!wrk->y_expand); 141 if (yscale) { 142 for (x_out = 0; x_out < x_out_max; ++x_out) { 143 const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale); 144 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); 145 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 146 irow[x_out] = frac; // new fractional start 147 } 148 } else { 149 for (x_out = 0; x_out < x_out_max; ++x_out) { 150 const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); 151 dst[x_out] = (v > 255) ? 255u : (uint8_t)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* WEBP_RESTRICT const wrk, 165 const uint8_t* WEBP_RESTRICT src) { 166 assert(!WebPRescalerInputDone(wrk)); 167 if (!wrk->x_expand) { 168 WebPRescalerImportRowShrink(wrk, src); 169 } else { 170 WebPRescalerImportRowExpand(wrk, src); 171 } 172 } 173 174 void WebPRescalerExportRow(WebPRescaler* const wrk) { 175 if (wrk->y_accum <= 0) { 176 assert(!WebPRescalerOutputDone(wrk)); 177 if (wrk->y_expand) { 178 WebPRescalerExportRowExpand(wrk); 179 } else if (wrk->fxy_scale) { 180 WebPRescalerExportRowShrink(wrk); 181 } else { // special case 182 int i; 183 assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); 184 assert(wrk->src_width == 1 && wrk->dst_width <= 2); 185 for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { 186 wrk->dst[i] = wrk->irow[i]; 187 wrk->irow[i] = 0; 188 } 189 } 190 wrk->y_accum += wrk->y_add; 191 wrk->dst += wrk->dst_stride; 192 ++wrk->dst_y; 193 } 194 } 195 196 //------------------------------------------------------------------------------ 197 198 WebPRescalerImportRowFunc WebPRescalerImportRowExpand; 199 WebPRescalerImportRowFunc WebPRescalerImportRowShrink; 200 201 WebPRescalerExportRowFunc WebPRescalerExportRowExpand; 202 WebPRescalerExportRowFunc WebPRescalerExportRowShrink; 203 204 extern VP8CPUInfo VP8GetCPUInfo; 205 extern void WebPRescalerDspInitSSE2(void); 206 extern void WebPRescalerDspInitMIPS32(void); 207 extern void WebPRescalerDspInitMIPSdspR2(void); 208 extern void WebPRescalerDspInitMSA(void); 209 extern void WebPRescalerDspInitNEON(void); 210 211 WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) { 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_HAVE_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_HAVE_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 }