| OLD | NEW |
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 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 | 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 | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 9 // | 9 // |
| 10 // Rescaling functions | 10 // Rescaling functions |
| 11 // | 11 // |
| 12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
| 13 | 13 |
| 14 #include <assert.h> | 14 #include <assert.h> |
| 15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include <string.h> | 16 #include <string.h> |
| 17 #include "../dsp/dsp.h" |
| 17 #include "./rescaler.h" | 18 #include "./rescaler.h" |
| 18 #include "../dsp/dsp.h" | |
| 19 | |
| 20 //------------------------------------------------------------------------------ | |
| 21 // Implementations of critical functions ImportRow / ExportRow | |
| 22 | |
| 23 // Import a row of data and save its contribution in the rescaler. | |
| 24 // 'channel' denotes the channel number to be imported. 'Expand' corresponds to | |
| 25 // the wrk->x_expand case. Otherwise, 'Shrink' is to be used. | |
| 26 typedef void (*WebPRescalerImportRowFunc)(WebPRescaler* const wrk, | |
| 27 const uint8_t* src); | |
| 28 static WebPRescalerImportRowFunc WebPRescalerImportRowExpand; | |
| 29 static WebPRescalerImportRowFunc WebPRescalerImportRowShrink; | |
| 30 | |
| 31 // Export one row (starting at x_out position) from rescaler. | |
| 32 // 'Expand' corresponds to the wrk->y_expand case. | |
| 33 // Otherwise 'Shrink' is to be used | |
| 34 typedef void (*WebPRescalerExportRowFunc)(WebPRescaler* const wrk); | |
| 35 static WebPRescalerExportRowFunc WebPRescalerExportRowExpand; | |
| 36 static WebPRescalerExportRowFunc WebPRescalerExportRowShrink; | |
| 37 | |
| 38 #define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies | |
| 39 #define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX) | |
| 40 #define WEBP_RESCALER_FRAC(x, y) \ | |
| 41 ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y))) | |
| 42 #define ROUNDER (WEBP_RESCALER_ONE >> 1) | |
| 43 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) | |
| 44 | |
| 45 static void ImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) { | |
| 46 const int x_stride = wrk->num_channels; | |
| 47 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 48 int channel; | |
| 49 assert(!WebPRescalerInputDone(wrk)); | |
| 50 assert(wrk->x_expand); | |
| 51 for (channel = 0; channel < x_stride; ++channel) { | |
| 52 int x_in = channel; | |
| 53 int x_out = channel; | |
| 54 // simple bilinear interpolation | |
| 55 int accum = wrk->x_add; | |
| 56 int left = src[x_in]; | |
| 57 int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left; | |
| 58 x_in += x_stride; | |
| 59 while (1) { | |
| 60 wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; | |
| 61 x_out += x_stride; | |
| 62 if (x_out >= x_out_max) break; | |
| 63 accum -= wrk->x_sub; | |
| 64 if (accum < 0) { | |
| 65 left = right; | |
| 66 x_in += x_stride; | |
| 67 assert(x_in < wrk->src_width * x_stride); | |
| 68 right = src[x_in]; | |
| 69 accum += wrk->x_add; | |
| 70 } | |
| 71 } | |
| 72 assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 static void ImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) { | |
| 77 const int x_stride = wrk->num_channels; | |
| 78 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 79 int channel; | |
| 80 assert(!WebPRescalerInputDone(wrk)); | |
| 81 assert(!wrk->x_expand); | |
| 82 for (channel = 0; channel < x_stride; ++channel) { | |
| 83 int x_in = channel; | |
| 84 int x_out = channel; | |
| 85 uint32_t sum = 0; | |
| 86 int accum = 0; | |
| 87 while (x_out < x_out_max) { | |
| 88 uint32_t base = 0; | |
| 89 accum += wrk->x_add; | |
| 90 while (accum > 0) { | |
| 91 accum -= wrk->x_sub; | |
| 92 assert(x_in < wrk->src_width * x_stride); | |
| 93 base = src[x_in]; | |
| 94 sum += base; | |
| 95 x_in += x_stride; | |
| 96 } | |
| 97 { // Emit next horizontal pixel. | |
| 98 const rescaler_t frac = base * (-accum); | |
| 99 wrk->frow[x_out] = sum * wrk->x_sub - frac; | |
| 100 // fresh fractional start for next pixel | |
| 101 sum = (int)MULT_FIX(frac, wrk->fx_scale); | |
| 102 } | |
| 103 x_out += x_stride; | |
| 104 } | |
| 105 assert(accum == 0); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 //------------------------------------------------------------------------------ | |
| 110 // Row export | |
| 111 | |
| 112 static void ExportRowExpandC(WebPRescaler* const wrk) { | |
| 113 int x_out; | |
| 114 uint8_t* const dst = wrk->dst; | |
| 115 rescaler_t* const irow = wrk->irow; | |
| 116 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 117 const rescaler_t* const frow = wrk->frow; | |
| 118 assert(!WebPRescalerOutputDone(wrk)); | |
| 119 assert(wrk->y_accum <= 0); | |
| 120 assert(wrk->y_expand); | |
| 121 assert(wrk->y_sub != 0); | |
| 122 if (wrk->y_accum == 0) { | |
| 123 for (x_out = 0; x_out < x_out_max; ++x_out) { | |
| 124 const uint32_t J = frow[x_out]; | |
| 125 const int v = (int)MULT_FIX(J, wrk->fy_scale); | |
| 126 assert(v >= 0 && v <= 255); | |
| 127 dst[x_out] = v; | |
| 128 } | |
| 129 } else { | |
| 130 const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); | |
| 131 const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); | |
| 132 for (x_out = 0; x_out < x_out_max; ++x_out) { | |
| 133 const uint64_t I = (uint64_t)A * frow[x_out] | |
| 134 + (uint64_t)B * irow[x_out]; | |
| 135 const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); | |
| 136 const int v = (int)MULT_FIX(J, wrk->fy_scale); | |
| 137 assert(v >= 0 && v <= 255); | |
| 138 dst[x_out] = v; | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 static void ExportRowShrinkC(WebPRescaler* const wrk) { | |
| 144 int x_out; | |
| 145 uint8_t* const dst = wrk->dst; | |
| 146 rescaler_t* const irow = wrk->irow; | |
| 147 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 148 const rescaler_t* const frow = wrk->frow; | |
| 149 const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); | |
| 150 assert(!WebPRescalerOutputDone(wrk)); | |
| 151 assert(wrk->y_accum <= 0); | |
| 152 assert(!wrk->y_expand); | |
| 153 if (yscale) { | |
| 154 for (x_out = 0; x_out < x_out_max; ++x_out) { | |
| 155 const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); | |
| 156 const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); | |
| 157 assert(v >= 0 && v <= 255); | |
| 158 dst[x_out] = v; | |
| 159 irow[x_out] = frac; // new fractional start | |
| 160 } | |
| 161 } else { | |
| 162 for (x_out = 0; x_out < x_out_max; ++x_out) { | |
| 163 const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); | |
| 164 assert(v >= 0 && v <= 255); | |
| 165 dst[x_out] = v; | |
| 166 irow[x_out] = 0; | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 //------------------------------------------------------------------------------ | |
| 172 // Main entry calls | |
| 173 | |
| 174 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { | |
| 175 assert(!WebPRescalerInputDone(wrk)); | |
| 176 if (!wrk->x_expand) { | |
| 177 WebPRescalerImportRowShrink(wrk, src); | |
| 178 } else { | |
| 179 WebPRescalerImportRowExpand(wrk, src); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 void WebPRescalerExportRow(WebPRescaler* const wrk) { | |
| 184 if (wrk->y_accum <= 0) { | |
| 185 assert(!WebPRescalerOutputDone(wrk)); | |
| 186 if (wrk->y_expand) { | |
| 187 WebPRescalerExportRowExpand(wrk); | |
| 188 } else if (wrk->fxy_scale) { | |
| 189 WebPRescalerExportRowShrink(wrk); | |
| 190 } else { // very special case for src = dst = 1x1 | |
| 191 int i; | |
| 192 assert(wrk->src_width == 1 && wrk->dst_width <= 2); | |
| 193 assert(wrk->src_height == 1 && wrk->dst_height == 1); | |
| 194 for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { | |
| 195 wrk->dst[i] = wrk->irow[i]; | |
| 196 wrk->irow[i] = 0; | |
| 197 } | |
| 198 } | |
| 199 wrk->y_accum += wrk->y_add; | |
| 200 wrk->dst += wrk->dst_stride; | |
| 201 ++wrk->dst_y; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 //------------------------------------------------------------------------------ | |
| 206 // MIPS version | |
| 207 | |
| 208 #if defined(WEBP_USE_MIPS32) | |
| 209 | |
| 210 static void ImportRowShrinkMIPS(WebPRescaler* const wrk, const uint8_t* src) { | |
| 211 const int x_stride = wrk->num_channels; | |
| 212 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 213 const int fx_scale = wrk->fx_scale; | |
| 214 const int x_add = wrk->x_add; | |
| 215 const int x_sub = wrk->x_sub; | |
| 216 const int x_stride1 = x_stride << 2; | |
| 217 int channel; | |
| 218 assert(!wrk->x_expand); | |
| 219 assert(!WebPRescalerInputDone(wrk)); | |
| 220 | |
| 221 for (channel = 0; channel < x_stride; ++channel) { | |
| 222 const uint8_t* src1 = src + channel; | |
| 223 rescaler_t* frow = wrk->frow + channel; | |
| 224 int temp1, temp2, temp3; | |
| 225 int base, frac, sum; | |
| 226 int accum, accum1; | |
| 227 int loop_c = x_out_max - channel; | |
| 228 | |
| 229 __asm__ volatile ( | |
| 230 "li %[temp1], 0x8000 \n\t" | |
| 231 "li %[temp2], 0x10000 \n\t" | |
| 232 "li %[sum], 0 \n\t" | |
| 233 "li %[accum], 0 \n\t" | |
| 234 "1: \n\t" | |
| 235 "addu %[accum], %[accum], %[x_add] \n\t" | |
| 236 "li %[base], 0 \n\t" | |
| 237 "blez %[accum], 3f \n\t" | |
| 238 "2: \n\t" | |
| 239 "lbu %[base], 0(%[src1]) \n\t" | |
| 240 "subu %[accum], %[accum], %[x_sub] \n\t" | |
| 241 "addu %[src1], %[src1], %[x_stride] \n\t" | |
| 242 "addu %[sum], %[sum], %[base] \n\t" | |
| 243 "bgtz %[accum], 2b \n\t" | |
| 244 "3: \n\t" | |
| 245 "negu %[accum1], %[accum] \n\t" | |
| 246 "mul %[frac], %[base], %[accum1] \n\t" | |
| 247 "mul %[temp3], %[sum], %[x_sub] \n\t" | |
| 248 "subu %[loop_c], %[loop_c], %[x_stride] \n\t" | |
| 249 "mult %[temp1], %[temp2] \n\t" | |
| 250 "maddu %[frac], %[fx_scale] \n\t" | |
| 251 "mfhi %[sum] \n\t" | |
| 252 "subu %[temp3], %[temp3], %[frac] \n\t" | |
| 253 "sw %[temp3], 0(%[frow]) \n\t" | |
| 254 "addu %[frow], %[frow], %[x_stride1] \n\t" | |
| 255 "bgtz %[loop_c], 1b \n\t" | |
| 256 : [accum]"=&r"(accum), [src1]"+r"(src1), [temp3]"=&r"(temp3), | |
| 257 [sum]"=&r"(sum), [base]"=&r"(base), [frac]"=&r"(frac), | |
| 258 [frow]"+r"(frow), [accum1]"=&r"(accum1), | |
| 259 [temp2]"=&r"(temp2), [temp1]"=&r"(temp1) | |
| 260 : [x_stride]"r"(x_stride), [fx_scale]"r"(fx_scale), | |
| 261 [x_sub]"r"(x_sub), [x_add]"r"(x_add), | |
| 262 [loop_c]"r"(loop_c), [x_stride1]"r"(x_stride1) | |
| 263 : "memory", "hi", "lo" | |
| 264 ); | |
| 265 assert(accum == 0); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 static void ImportRowExpandMIPS(WebPRescaler* const wrk, const uint8_t* src) { | |
| 270 const int x_stride = wrk->num_channels; | |
| 271 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 272 const int x_add = wrk->x_add; | |
| 273 const int x_sub = wrk->x_sub; | |
| 274 const int src_width = wrk->src_width; | |
| 275 const int x_stride1 = x_stride << 2; | |
| 276 int channel; | |
| 277 assert(wrk->x_expand); | |
| 278 assert(!WebPRescalerInputDone(wrk)); | |
| 279 | |
| 280 for (channel = 0; channel < x_stride; ++channel) { | |
| 281 const uint8_t* src1 = src + channel; | |
| 282 rescaler_t* frow = wrk->frow + channel; | |
| 283 int temp1, temp2, temp3, temp4; | |
| 284 int frac; | |
| 285 int accum; | |
| 286 int x_out = channel; | |
| 287 | |
| 288 __asm__ volatile ( | |
| 289 "addiu %[temp3], %[src_width], -1 \n\t" | |
| 290 "lbu %[temp2], 0(%[src1]) \n\t" | |
| 291 "addu %[src1], %[src1], %[x_stride] \n\t" | |
| 292 "bgtz %[temp3], 0f \n\t" | |
| 293 "addiu %[temp1], %[temp2], 0 \n\t" | |
| 294 "b 3f \n\t" | |
| 295 "0: \n\t" | |
| 296 "lbu %[temp1], 0(%[src1]) \n\t" | |
| 297 "3: \n\t" | |
| 298 "addiu %[accum], %[x_add], 0 \n\t" | |
| 299 "1: \n\t" | |
| 300 "subu %[temp3], %[temp2], %[temp1] \n\t" | |
| 301 "mul %[temp3], %[temp3], %[accum] \n\t" | |
| 302 "mul %[temp4], %[temp1], %[x_add] \n\t" | |
| 303 "addu %[temp3], %[temp4], %[temp3] \n\t" | |
| 304 "sw %[temp3], 0(%[frow]) \n\t" | |
| 305 "addu %[frow], %[frow], %[x_stride1] \n\t" | |
| 306 "addu %[x_out], %[x_out], %[x_stride] \n\t" | |
| 307 "subu %[temp3], %[x_out], %[x_out_max] \n\t" | |
| 308 "bgez %[temp3], 2f \n\t" | |
| 309 "subu %[accum], %[accum], %[x_sub] \n\t" | |
| 310 "bgez %[accum], 4f \n\t" | |
| 311 "addiu %[temp2], %[temp1], 0 \n\t" | |
| 312 "addu %[src1], %[src1], %[x_stride] \n\t" | |
| 313 "lbu %[temp1], 0(%[src1]) \n\t" | |
| 314 "addu %[accum], %[accum], %[x_add] \n\t" | |
| 315 "4: \n\t" | |
| 316 "b 1b \n\t" | |
| 317 "2: \n\t" | |
| 318 : [src1]"+r"(src1), [accum]"=&r"(accum), [temp1]"=&r"(temp1), | |
| 319 [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), | |
| 320 [x_out]"+r"(x_out), [frac]"=&r"(frac), [frow]"+r"(frow) | |
| 321 : [x_stride]"r"(x_stride), [x_add]"r"(x_add), [x_sub]"r"(x_sub), | |
| 322 [x_stride1]"r"(x_stride1), [src_width]"r"(src_width), | |
| 323 [x_out_max]"r"(x_out_max) | |
| 324 : "memory", "hi", "lo" | |
| 325 ); | |
| 326 assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 //------------------------------------------------------------------------------ | |
| 331 // Row export | |
| 332 | |
| 333 static void ExportRowExpandMIPS(WebPRescaler* const wrk) { | |
| 334 uint8_t* dst = wrk->dst; | |
| 335 rescaler_t* irow = wrk->irow; | |
| 336 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 337 const rescaler_t* frow = wrk->frow; | |
| 338 int temp0, temp1, temp3, temp4, temp5, loop_end; | |
| 339 const int temp2 = (int)wrk->fy_scale; | |
| 340 const int temp6 = x_out_max << 2; | |
| 341 assert(!WebPRescalerOutputDone(wrk)); | |
| 342 assert(wrk->y_accum <= 0); | |
| 343 assert(wrk->y_expand); | |
| 344 assert(wrk->y_sub != 0); | |
| 345 if (wrk->y_accum == 0) { | |
| 346 __asm__ volatile ( | |
| 347 "li %[temp3], 0x10000 \n\t" | |
| 348 "li %[temp4], 0x8000 \n\t" | |
| 349 "addu %[loop_end], %[frow], %[temp6] \n\t" | |
| 350 "1: \n\t" | |
| 351 "lw %[temp0], 0(%[frow]) \n\t" | |
| 352 "addiu %[dst], %[dst], 1 \n\t" | |
| 353 "addiu %[frow], %[frow], 4 \n\t" | |
| 354 "mult %[temp3], %[temp4] \n\t" | |
| 355 "maddu %[temp0], %[temp2] \n\t" | |
| 356 "mfhi %[temp5] \n\t" | |
| 357 "sb %[temp5], -1(%[dst]) \n\t" | |
| 358 "bne %[frow], %[loop_end], 1b \n\t" | |
| 359 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), | |
| 360 [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), | |
| 361 [dst]"+r"(dst), [loop_end]"=&r"(loop_end) | |
| 362 : [temp2]"r"(temp2), [temp6]"r"(temp6) | |
| 363 : "memory", "hi", "lo" | |
| 364 ); | |
| 365 } else { | |
| 366 const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); | |
| 367 const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); | |
| 368 __asm__ volatile ( | |
| 369 "li %[temp3], 0x10000 \n\t" | |
| 370 "li %[temp4], 0x8000 \n\t" | |
| 371 "addu %[loop_end], %[frow], %[temp6] \n\t" | |
| 372 "1: \n\t" | |
| 373 "lw %[temp0], 0(%[frow]) \n\t" | |
| 374 "lw %[temp1], 0(%[irow]) \n\t" | |
| 375 "addiu %[dst], %[dst], 1 \n\t" | |
| 376 "mult %[temp3], %[temp4] \n\t" | |
| 377 "maddu %[A], %[temp0] \n\t" | |
| 378 "maddu %[B], %[temp1] \n\t" | |
| 379 "addiu %[frow], %[frow], 4 \n\t" | |
| 380 "addiu %[irow], %[irow], 4 \n\t" | |
| 381 "mfhi %[temp5] \n\t" | |
| 382 "mult %[temp3], %[temp4] \n\t" | |
| 383 "maddu %[temp5], %[temp2] \n\t" | |
| 384 "mfhi %[temp5] \n\t" | |
| 385 "sb %[temp5], -1(%[dst]) \n\t" | |
| 386 "bne %[frow], %[loop_end], 1b \n\t" | |
| 387 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), | |
| 388 [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), | |
| 389 [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) | |
| 390 : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B) | |
| 391 : "memory", "hi", "lo" | |
| 392 ); | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 static void ExportRowShrinkMIPS(WebPRescaler* const wrk) { | |
| 397 const int x_out_max = wrk->dst_width * wrk->num_channels; | |
| 398 uint8_t* dst = wrk->dst; | |
| 399 rescaler_t* irow = wrk->irow; | |
| 400 const rescaler_t* frow = wrk->frow; | |
| 401 const int yscale = wrk->fy_scale * (-wrk->y_accum); | |
| 402 int temp0, temp1, temp3, temp4, temp5, loop_end; | |
| 403 const int temp2 = (int)wrk->fxy_scale; | |
| 404 const int temp6 = x_out_max << 2; | |
| 405 | |
| 406 assert(!WebPRescalerOutputDone(wrk)); | |
| 407 assert(wrk->y_accum <= 0); | |
| 408 assert(!wrk->y_expand); | |
| 409 assert(wrk->fxy_scale != 0); | |
| 410 if (yscale) { | |
| 411 __asm__ volatile ( | |
| 412 "li %[temp3], 0x10000 \n\t" | |
| 413 "li %[temp4], 0x8000 \n\t" | |
| 414 "addu %[loop_end], %[frow], %[temp6] \n\t" | |
| 415 "1: \n\t" | |
| 416 "lw %[temp0], 0(%[frow]) \n\t" | |
| 417 "mult %[temp3], %[temp4] \n\t" | |
| 418 "addiu %[frow], %[frow], 4 \n\t" | |
| 419 "maddu %[temp0], %[yscale] \n\t" | |
| 420 "mfhi %[temp1] \n\t" | |
| 421 "lw %[temp0], 0(%[irow]) \n\t" | |
| 422 "addiu %[dst], %[dst], 1 \n\t" | |
| 423 "addiu %[irow], %[irow], 4 \n\t" | |
| 424 "subu %[temp0], %[temp0], %[temp1] \n\t" | |
| 425 "mult %[temp3], %[temp4] \n\t" | |
| 426 "maddu %[temp0], %[temp2] \n\t" | |
| 427 "mfhi %[temp5] \n\t" | |
| 428 "sw %[temp1], -4(%[irow]) \n\t" | |
| 429 "sb %[temp5], -1(%[dst]) \n\t" | |
| 430 "bne %[frow], %[loop_end], 1b \n\t" | |
| 431 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), | |
| 432 [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), | |
| 433 [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) | |
| 434 : [temp2]"r"(temp2), [yscale]"r"(yscale), [temp6]"r"(temp6) | |
| 435 : "memory", "hi", "lo" | |
| 436 ); | |
| 437 } else { | |
| 438 __asm__ volatile ( | |
| 439 "li %[temp3], 0x10000 \n\t" | |
| 440 "li %[temp4], 0x8000 \n\t" | |
| 441 "addu %[loop_end], %[irow], %[temp6] \n\t" | |
| 442 "1: \n\t" | |
| 443 "lw %[temp0], 0(%[irow]) \n\t" | |
| 444 "addiu %[dst], %[dst], 1 \n\t" | |
| 445 "addiu %[irow], %[irow], 4 \n\t" | |
| 446 "mult %[temp3], %[temp4] \n\t" | |
| 447 "maddu %[temp0], %[temp2] \n\t" | |
| 448 "mfhi %[temp5] \n\t" | |
| 449 "sw $zero, -4(%[irow]) \n\t" | |
| 450 "sb %[temp5], -1(%[dst]) \n\t" | |
| 451 "bne %[irow], %[loop_end], 1b \n\t" | |
| 452 : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), | |
| 453 [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow), | |
| 454 [dst]"+r"(dst), [loop_end]"=&r"(loop_end) | |
| 455 : [temp2]"r"(temp2), [temp6]"r"(temp6) | |
| 456 : "memory", "hi", "lo" | |
| 457 ); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 #endif // WEBP_USE_MIPS32 | |
| 462 | 19 |
| 463 //------------------------------------------------------------------------------ | 20 //------------------------------------------------------------------------------ |
| 464 | 21 |
| 465 void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, | 22 void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, |
| 466 uint8_t* const dst, | 23 uint8_t* const dst, |
| 467 int dst_width, int dst_height, int dst_stride, | 24 int dst_width, int dst_height, int dst_stride, |
| 468 int num_channels, rescaler_t* const work) { | 25 int num_channels, rescaler_t* const work) { |
| 469 const int x_add = src_width, x_sub = dst_width; | 26 const int x_add = src_width, x_sub = dst_width; |
| 470 const int y_add = src_height, y_sub = dst_height; | 27 const int y_add = src_height, y_sub = dst_height; |
| 471 wrk->x_expand = (src_width < dst_width); | 28 wrk->x_expand = (src_width < dst_width); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 } | 60 } |
| 504 wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub); | 61 wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub); |
| 505 } else { | 62 } else { |
| 506 wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add); | 63 wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add); |
| 507 // wrk->fxy_scale is unused here. | 64 // wrk->fxy_scale is unused here. |
| 508 } | 65 } |
| 509 wrk->irow = work; | 66 wrk->irow = work; |
| 510 wrk->frow = work + num_channels * dst_width; | 67 wrk->frow = work + num_channels * dst_width; |
| 511 memset(work, 0, 2 * dst_width * num_channels * sizeof(*work)); | 68 memset(work, 0, 2 * dst_width * num_channels * sizeof(*work)); |
| 512 | 69 |
| 513 if (WebPRescalerImportRowExpand == NULL) { | 70 WebPRescalerDspInit(); |
| 514 WebPRescalerImportRowExpand = ImportRowExpandC; | 71 } |
| 515 WebPRescalerImportRowShrink = ImportRowShrinkC; | 72 |
| 516 WebPRescalerExportRowExpand = ExportRowExpandC; | 73 int WebPRescalerGetScaledDimensions(int src_width, int src_height, |
| 517 WebPRescalerExportRowShrink = ExportRowShrinkC; | 74 int* const scaled_width, |
| 518 if (VP8GetCPUInfo != NULL) { | 75 int* const scaled_height) { |
| 519 #if defined(WEBP_USE_MIPS32) | 76 assert(scaled_width != NULL); |
| 520 if (VP8GetCPUInfo(kMIPS32)) { | 77 assert(scaled_height != NULL); |
| 521 WebPRescalerImportRowExpand = ImportRowExpandMIPS; | 78 { |
| 522 WebPRescalerImportRowShrink = ImportRowShrinkMIPS; | 79 int width = *scaled_width; |
| 523 WebPRescalerExportRowExpand = ExportRowExpandMIPS; | 80 int height = *scaled_height; |
| 524 WebPRescalerExportRowShrink = ExportRowShrinkMIPS; | 81 |
| 525 } | 82 // if width is unspecified, scale original proportionally to height ratio. |
| 526 #endif | 83 if (width == 0) { |
| 84 width = (src_width * height + src_height / 2) / src_height; |
| 527 } | 85 } |
| 86 // if height is unspecified, scale original proportionally to width ratio. |
| 87 if (height == 0) { |
| 88 height = (src_height * width + src_width / 2) / src_width; |
| 89 } |
| 90 // Check if the overall dimensions still make sense. |
| 91 if (width <= 0 || height <= 0) { |
| 92 return 0; |
| 93 } |
| 94 |
| 95 *scaled_width = width; |
| 96 *scaled_height = height; |
| 97 return 1; |
| 528 } | 98 } |
| 529 } | 99 } |
| 530 | 100 |
| 531 #undef MULT_FIX | |
| 532 #undef WEBP_RESCALER_RFIX | |
| 533 #undef WEBP_RESCALER_ONE | |
| 534 #undef WEBP_RESCALER_FRAC | |
| 535 #undef ROUNDER | |
| 536 | |
| 537 //------------------------------------------------------------------------------ | 101 //------------------------------------------------------------------------------ |
| 538 // all-in-one calls | 102 // all-in-one calls |
| 539 | 103 |
| 540 int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) { | 104 int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) { |
| 541 const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub; | 105 const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub; |
| 542 return (num_lines > max_num_lines) ? max_num_lines : num_lines; | 106 return (num_lines > max_num_lines) ? max_num_lines : num_lines; |
| 543 } | 107 } |
| 544 | 108 |
| 545 int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, | 109 int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, |
| 546 const uint8_t* src, int src_stride) { | 110 const uint8_t* src, int src_stride) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 569 int WebPRescalerExport(WebPRescaler* const rescaler) { | 133 int WebPRescalerExport(WebPRescaler* const rescaler) { |
| 570 int total_exported = 0; | 134 int total_exported = 0; |
| 571 while (WebPRescalerHasPendingOutput(rescaler)) { | 135 while (WebPRescalerHasPendingOutput(rescaler)) { |
| 572 WebPRescalerExportRow(rescaler); | 136 WebPRescalerExportRow(rescaler); |
| 573 ++total_exported; | 137 ++total_exported; |
| 574 } | 138 } |
| 575 return total_exported; | 139 return total_exported; |
| 576 } | 140 } |
| 577 | 141 |
| 578 //------------------------------------------------------------------------------ | 142 //------------------------------------------------------------------------------ |
| OLD | NEW |