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 |