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 (at) 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 dst[x_out] = (v > 255) ? 255u : (uint8_t)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 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 123 } 124 } 125 } 126 127 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { 128 int x_out; 129 uint8_t* const dst = wrk->dst; 130 rescaler_t* const irow = wrk->irow; 131 const int x_out_max = wrk->dst_width * wrk->num_channels; 132 const rescaler_t* const frow = wrk->frow; 133 const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); 134 assert(!WebPRescalerOutputDone(wrk)); 135 assert(wrk->y_accum <= 0); 136 assert(!wrk->y_expand); 137 if (yscale) { 138 for (x_out = 0; x_out < x_out_max; ++x_out) { 139 const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale); 140 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); 141 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 142 irow[x_out] = frac; // new fractional start 143 } 144 } else { 145 for (x_out = 0; x_out < x_out_max; ++x_out) { 146 const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); 147 dst[x_out] = (v > 255) ? 255u : (uint8_t)v; 148 irow[x_out] = 0; 149 } 150 } 151 } 152 153 #undef MULT_FIX_FLOOR 154 #undef MULT_FIX 155 #undef ROUNDER 156 157 //------------------------------------------------------------------------------ 158 // Main entry calls 159 160 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { 161 assert(!WebPRescalerInputDone(wrk)); 162 if (!wrk->x_expand) { 163 WebPRescalerImportRowShrink(wrk, src); 164 } else { 165 WebPRescalerImportRowExpand(wrk, src); 166 } 167 } 168 169 void WebPRescalerExportRow(WebPRescaler* const wrk) { 170 if (wrk->y_accum <= 0) { 171 assert(!WebPRescalerOutputDone(wrk)); 172 if (wrk->y_expand) { 173 WebPRescalerExportRowExpand(wrk); 174 } else if (wrk->fxy_scale) { 175 WebPRescalerExportRowShrink(wrk); 176 } else { // special case 177 int i; 178 assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1); 179 assert(wrk->src_width == 1 && wrk->dst_width <= 2); 180 for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { 181 wrk->dst[i] = wrk->irow[i]; 182 wrk->irow[i] = 0; 183 } 184 } 185 wrk->y_accum += wrk->y_add; 186 wrk->dst += wrk->dst_stride; 187 ++wrk->dst_y; 188 } 189 } 190 191 //------------------------------------------------------------------------------ 192 193 WebPRescalerImportRowFunc WebPRescalerImportRowExpand; 194 WebPRescalerImportRowFunc WebPRescalerImportRowShrink; 195 196 WebPRescalerExportRowFunc WebPRescalerExportRowExpand; 197 WebPRescalerExportRowFunc WebPRescalerExportRowShrink; 198 199 extern void WebPRescalerDspInitSSE2(void); 200 extern void WebPRescalerDspInitMIPS32(void); 201 extern void WebPRescalerDspInitMIPSdspR2(void); 202 extern void WebPRescalerDspInitMSA(void); 203 extern void WebPRescalerDspInitNEON(void); 204 205 WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) { 206 #if !defined(WEBP_REDUCE_SIZE) 207 #if !WEBP_NEON_OMIT_C_CODE 208 WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C; 209 WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C; 210 #endif 211 212 WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C; 213 WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C; 214 215 if (VP8GetCPUInfo != NULL) { 216 #if defined(WEBP_USE_SSE2) 217 if (VP8GetCPUInfo(kSSE2)) { 218 WebPRescalerDspInitSSE2(); 219 } 220 #endif 221 #if defined(WEBP_USE_MIPS32) 222 if (VP8GetCPUInfo(kMIPS32)) { 223 WebPRescalerDspInitMIPS32(); 224 } 225 #endif 226 #if defined(WEBP_USE_MIPS_DSP_R2) 227 if (VP8GetCPUInfo(kMIPSdspR2)) { 228 WebPRescalerDspInitMIPSdspR2(); 229 } 230 #endif 231 #if defined(WEBP_USE_MSA) 232 if (VP8GetCPUInfo(kMSA)) { 233 WebPRescalerDspInitMSA(); 234 } 235 #endif 236 } 237 238 #if defined(WEBP_USE_NEON) 239 if (WEBP_NEON_OMIT_C_CODE || 240 (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { 241 WebPRescalerDspInitNEON(); 242 } 243 #endif 244 245 assert(WebPRescalerExportRowExpand != NULL); 246 assert(WebPRescalerExportRowShrink != NULL); 247 assert(WebPRescalerImportRowExpand != NULL); 248 assert(WebPRescalerImportRowShrink != NULL); 249 #endif // WEBP_REDUCE_SIZE 250 } 251