GSoC/Buflib: Enable compaction in buflib.
[kugel-rb.git] / apps / recorder / resize.c
blobb5701161799dc85bc8a59d08c6017ab2433e930e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Akio Idehara, Andrew Mahone
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * Implementation of area average and linear row and vertical scalers, and
24 * nearest-neighbor grey scaler (C) 2008 Andrew Mahone
26 * All files in this archive are subject to the GNU General Public License.
27 * See the file COPYING in the source tree root for full license agreement.
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
30 * KIND, either express or implied.
32 ****************************************************************************/
34 #include <system.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <general.h>
39 #include "inttypes.h"
40 #ifndef PLUGIN
41 #include "debug.h"
42 #endif
43 #include "lcd.h"
44 #include "file.h"
45 #ifdef HAVE_REMOTE_LCD
46 #include "lcd-remote.h"
47 #endif
48 #ifdef ROCKBOX_DEBUG_SCALERS
49 #define SDEBUGF DEBUGF
50 #else
51 #define SDEBUGF(...)
52 #endif
53 #ifndef __PCTOOL__
54 #include "config.h"
55 #include "system.h"
56 #include <bmp.h>
57 #include "resize.h"
58 #else
59 #undef DEBUGF
60 #define DEBUGF(...)
61 #endif
62 #include <jpeg_load.h>
64 #if CONFIG_CPU == SH7034
65 /* 16*16->32 bit multiplication is a single instrcution on the SH1 */
66 #define MULUQ(a, b) ((uint32_t) (((uint16_t) (a)) * ((uint16_t) (b))))
67 #define MULQ(a, b) ((int32_t) (((int16_t) (a)) * ((int16_t) (b))))
68 #else
69 #define MULUQ(a, b) ((a) * (b))
70 #define MULQ(a, b) ((a) * (b))
71 #endif
73 /* calculate the maximum dimensions which will preserve the aspect ration of
74 src while fitting in the constraints passed in dst, and store result in dst,
75 returning 0 if rounding and 1 if not rounding.
77 int recalc_dimension(struct dim *dst, struct dim *src)
79 /* This only looks backwards. The input image size is being pre-scaled by
80 * the inverse of the pixel aspect ratio, so that once the size it scaled
81 * to meet the output constraints, the scaled image will have appropriate
82 * proportions.
84 int sw = src->width * LCD_PIXEL_ASPECT_HEIGHT;
85 int sh = src->height * LCD_PIXEL_ASPECT_WIDTH;
86 int tmp;
87 if (dst->width <= 0)
88 dst->width = LCD_WIDTH;
89 if (dst->height <= 0)
90 dst->height = LCD_HEIGHT;
91 #ifndef HAVE_UPSCALER
92 if (dst->width > sw || dst->height > sh)
94 dst->width = sw;
95 dst->height = sh;
97 if (sw == dst->width && sh == dst->height)
98 return 1;
99 #endif
100 tmp = (sw * dst->height + (sh >> 1)) / sh;
101 if (tmp > dst->width)
102 dst->height = (sh * dst->width + (sw >> 1)) / sw;
103 else
104 dst->width = tmp;
105 return src->width == dst->width && src->height == dst->height;
108 /* All of these scalers use variations of Bresenham's algorithm to convert from
109 their input to output coordinates. The error value is shifted from the
110 "classic" version such that it is a useful input to the scaling calculation.
113 #ifdef HAVE_LCD_COLOR
114 /* dither + pack on channel of RGB565, R an B share a packing macro */
115 #define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8)
116 #define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8)
117 #endif
119 /* read new img_part unconditionally, return false on failure */
120 #define FILL_BUF_INIT(img_part, store_part, args) { \
121 img_part = store_part(args); \
122 if (img_part == NULL) \
123 return false; \
126 /* read new img_part if current one is empty, return false on failure */
127 #define FILL_BUF(img_part, store_part, args) { \
128 if (img_part->len == 0) \
129 img_part = store_part(args); \
130 if (img_part == NULL) \
131 return false; \
134 #if defined(CPU_COLDFIRE)
135 #define MAC(op1, op2, num) \
136 asm volatile( \
137 "mac.l %0, %1, %%acc" #num \
139 : "%d" (op1), "d" (op2)\
141 #define MAC_OUT(dest, num) \
142 asm volatile( \
143 "movclr.l %%acc" #num ", %0" \
144 : "=d" (dest) \
146 #elif defined(CPU_SH)
147 /* calculate the 32-bit product of unsigned 16-bit op1 and op2 */
148 static inline int32_t mul_s16_s16(int16_t op1, int16_t op2)
150 return (int32_t)(op1 * op2);
153 /* calculate the 32-bit product of signed 16-bit op1 and op2 */
154 static inline uint32_t mul_u16_u16(uint16_t op1, uint16_t op2)
156 return (uint32_t)(op1 * op2);
158 #endif
160 /* horizontal area average scaler */
161 static bool scale_h_area(void *out_line_ptr,
162 struct scaler_context *ctx, bool accum)
164 SDEBUGF("scale_h_area\n");
165 unsigned int ix, ox, oxe, mul;
166 #if defined(CPU_SH) || defined (TEST_SH_MATH)
167 const uint32_t h_i_val = ctx->src->width,
168 h_o_val = ctx->bm->width;
169 #else
170 const uint32_t h_i_val = ctx->h_i_val,
171 h_o_val = ctx->h_o_val;
172 #endif
173 #ifdef HAVE_LCD_COLOR
174 struct uint32_rgb rgbvalacc = { 0, 0, 0 },
175 rgbvaltmp = { 0, 0, 0 },
176 *out_line = (struct uint32_rgb *)out_line_ptr;
177 #else
178 uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr;
179 #endif
180 struct img_part *part;
181 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
182 ox = 0;
183 oxe = 0;
184 mul = 0;
185 /* give other tasks a chance to run */
186 yield();
187 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++)
189 oxe += h_o_val;
190 /* end of current area has been reached */
191 /* fill buffer if needed */
192 FILL_BUF(part,ctx->store_part,ctx->args);
193 #ifdef HAVE_LCD_COLOR
194 if (oxe >= h_i_val)
196 /* "reset" error, which now represents partial coverage of next
197 pixel by the next area
199 oxe -= h_i_val;
201 #if defined(CPU_COLDFIRE)
202 /* Coldfire EMAC math */
203 /* add saved partial pixel from start of area */
204 MAC(rgbvalacc.r, h_o_val, 0);
205 MAC(rgbvalacc.g, h_o_val, 1);
206 MAC(rgbvalacc.b, h_o_val, 2);
207 MAC(rgbvaltmp.r, mul, 0);
208 MAC(rgbvaltmp.g, mul, 1);
209 MAC(rgbvaltmp.b, mul, 2);
210 /* get new pixel , then add its partial coverage to this area */
211 mul = h_o_val - oxe;
212 rgbvaltmp.r = part->buf->red;
213 rgbvaltmp.g = part->buf->green;
214 rgbvaltmp.b = part->buf->blue;
215 MAC(rgbvaltmp.r, mul, 0);
216 MAC(rgbvaltmp.g, mul, 1);
217 MAC(rgbvaltmp.b, mul, 2);
218 MAC_OUT(rgbvalacc.r, 0);
219 MAC_OUT(rgbvalacc.g, 1);
220 MAC_OUT(rgbvalacc.b, 2);
221 #else
222 /* generic C math */
223 /* add saved partial pixel from start of area */
224 rgbvalacc.r = rgbvalacc.r * h_o_val + rgbvaltmp.r * mul;
225 rgbvalacc.g = rgbvalacc.g * h_o_val + rgbvaltmp.g * mul;
226 rgbvalacc.b = rgbvalacc.b * h_o_val + rgbvaltmp.b * mul;
228 /* get new pixel , then add its partial coverage to this area */
229 rgbvaltmp.r = part->buf->red;
230 rgbvaltmp.g = part->buf->green;
231 rgbvaltmp.b = part->buf->blue;
232 mul = h_o_val - oxe;
233 rgbvalacc.r += rgbvaltmp.r * mul;
234 rgbvalacc.g += rgbvaltmp.g * mul;
235 rgbvalacc.b += rgbvaltmp.b * mul;
236 #endif /* CPU */
237 rgbvalacc.r = (rgbvalacc.r + (1 << 21)) >> 22;
238 rgbvalacc.g = (rgbvalacc.g + (1 << 21)) >> 22;
239 rgbvalacc.b = (rgbvalacc.b + (1 << 21)) >> 22;
240 /* store or accumulate to output row */
241 if (accum)
243 rgbvalacc.r += out_line[ox].r;
244 rgbvalacc.g += out_line[ox].g;
245 rgbvalacc.b += out_line[ox].b;
247 out_line[ox].r = rgbvalacc.r;
248 out_line[ox].g = rgbvalacc.g;
249 out_line[ox].b = rgbvalacc.b;
250 /* reset accumulator */
251 rgbvalacc.r = 0;
252 rgbvalacc.g = 0;
253 rgbvalacc.b = 0;
254 mul = oxe;
255 ox += 1;
256 /* inside an area */
257 } else {
258 /* add pixel value to accumulator */
259 rgbvalacc.r += part->buf->red;
260 rgbvalacc.g += part->buf->green;
261 rgbvalacc.b += part->buf->blue;
263 #else
264 if (oxe >= h_i_val)
266 /* "reset" error, which now represents partial coverage of next
267 pixel by the next area
269 oxe -= h_i_val;
270 #if defined(CPU_COLDFIRE)
271 /* Coldfire EMAC math */
272 /* add saved partial pixel from start of area */
273 MAC(acc, h_o_val, 0);
274 MAC(tmp, mul, 0);
275 /* get new pixel , then add its partial coverage to this area */
276 tmp = *(part->buf);
277 mul = h_o_val - oxe;
278 MAC(tmp, mul, 0);
279 MAC_OUT(acc, 0);
280 #elif defined(CPU_SH)
281 /* SH-1 16x16->32 math */
282 /* add saved partial pixel from start of area */
283 acc = mul_u16_u16(acc, h_o_val) + mul_u16_u16(tmp, mul);
285 /* get new pixel , then add its partial coverage to this area */
286 tmp = *(part->buf);
287 mul = h_o_val - oxe;
288 acc += mul_u16_u16(tmp, mul);
289 #else
290 /* generic C math */
291 /* add saved partial pixel from start of area */
292 acc = (acc * h_o_val) + (tmp * mul);
294 /* get new pixel , then add its partial coverage to this area */
295 tmp = *(part->buf);
296 mul = h_o_val - oxe;
297 acc += tmp * mul;
298 #endif /* CPU */
299 #if !(defined(CPU_SH) || defined(TEST_SH_MATH))
300 /* round, divide, and either store or accumulate to output row */
301 acc = (acc + (1 << 21)) >> 22;
302 #endif
303 if (accum)
305 acc += out_line[ox];
307 out_line[ox] = acc;
308 /* reset accumulator */
309 acc = 0;
310 mul = oxe;
311 ox += 1;
312 /* inside an area */
313 } else {
314 /* add pixel value to accumulator */
315 acc += *(part->buf);
317 #endif
318 part->buf++;
319 part->len--;
321 return true;
324 /* vertical area average scaler */
325 static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx)
327 uint32_t mul, oy, iy, oye;
328 #if defined(CPU_SH) || defined (TEST_SH_MATH)
329 const uint32_t v_i_val = ctx->src->height,
330 v_o_val = ctx->bm->height;
331 #else
332 const uint32_t v_i_val = ctx->v_i_val,
333 v_o_val = ctx->v_o_val;
334 #endif
336 /* Set up rounding and scale factors */
337 mul = 0;
338 oy = rset->rowstart;
339 oye = 0;
340 #ifdef HAVE_LCD_COLOR
341 uint32_t *rowacc = (uint32_t *) ctx->buf,
342 *rowtmp = rowacc + 3 * ctx->bm->width,
343 *rowacc_px, *rowtmp_px;
344 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb));
345 #else
346 uint32_t *rowacc = (uint32_t *) ctx->buf,
347 *rowtmp = rowacc + ctx->bm->width,
348 *rowacc_px, *rowtmp_px;
349 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t));
350 #endif
351 SDEBUGF("scale_v_area\n");
352 /* zero the accumulator and temp rows */
353 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++)
355 oye += v_o_val;
356 /* end of current area has been reached */
357 if (oye >= v_i_val)
359 /* "reset" error, which now represents partial coverage of the next
360 row by the next area
362 oye -= v_i_val;
363 /* add stored partial row to accumulator */
364 for(rowacc_px = rowacc, rowtmp_px = rowtmp; rowacc_px != rowtmp;
365 rowacc_px++, rowtmp_px++)
366 *rowacc_px = *rowacc_px * v_o_val + *rowtmp_px * mul;
367 /* store new scaled row in temp row */
368 if(!ctx->h_scaler(rowtmp, ctx, false))
369 return false;
370 /* add partial coverage by new row to this area, then round and
371 scale to final value
373 mul = v_o_val - oye;
374 for(rowacc_px = rowacc, rowtmp_px = rowtmp; rowacc_px != rowtmp;
375 rowacc_px++, rowtmp_px++)
376 *rowacc_px += mul * *rowtmp_px;
377 ctx->output_row(oy, (void*)rowacc, ctx);
378 /* clear accumulator row, store partial coverage for next row */
379 #ifdef HAVE_LCD_COLOR
380 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3);
381 #else
382 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t));
383 #endif
384 mul = oye;
385 oy += rset->rowstep;
386 /* inside an area */
387 } else {
388 /* accumulate new scaled row to rowacc */
389 if (!ctx->h_scaler(rowacc, ctx, true))
390 return false;
393 return true;
396 #ifdef HAVE_UPSCALER
397 /* horizontal linear scaler */
398 static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx,
399 bool accum)
401 unsigned int ix, ox, ixe;
402 #if defined(CPU_SH) || defined (TEST_SH_MATH)
403 const uint32_t h_i_val = ctx->src->width - 1,
404 h_o_val = ctx->bm->width - 1;
405 #else
406 const uint32_t h_i_val = ctx->h_i_val,
407 h_o_val = ctx->h_o_val;
408 #endif
409 /* type x = x is an ugly hack for hiding an unitialized data warning. The
410 values are conditionally initialized before use, but other values are
411 set such that this will occur before these are used.
413 #ifdef HAVE_LCD_COLOR
414 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc,
415 *out_line = (struct uint32_rgb*)out_line_ptr;
416 #else
417 uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr;
418 #endif
419 struct img_part *part;
420 SDEBUGF("scale_h_linear\n");
421 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
422 ix = 0;
423 /* The error is set so that values are initialized on the first pass. */
424 ixe = h_o_val;
425 /* give other tasks a chance to run */
426 yield();
427 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++)
429 #ifdef HAVE_LCD_COLOR
430 if (ixe >= h_o_val)
432 /* Store the new "current" pixel value in rgbval, and the color
433 step value in rgbinc.
435 ixe -= h_o_val;
436 rgbinc.r = -(part->buf->red);
437 rgbinc.g = -(part->buf->green);
438 rgbinc.b = -(part->buf->blue);
439 #if defined(CPU_COLDFIRE)
440 /* Coldfire EMAC math */
441 MAC(part->buf->red, h_o_val, 0);
442 MAC(part->buf->green, h_o_val, 1);
443 MAC(part->buf->blue, h_o_val, 2);
444 #else
445 /* generic C math */
446 rgbval.r = (part->buf->red) * h_o_val;
447 rgbval.g = (part->buf->green) * h_o_val;
448 rgbval.b = (part->buf->blue) * h_o_val;
449 #endif /* CPU */
450 ix += 1;
451 /* If this wasn't the last pixel, add the next one to rgbinc. */
452 if (LIKELY(ix < (uint32_t)ctx->src->width)) {
453 part->buf++;
454 part->len--;
455 /* Fetch new pixels if needed */
456 FILL_BUF(part,ctx->store_part,ctx->args);
457 rgbinc.r += part->buf->red;
458 rgbinc.g += part->buf->green;
459 rgbinc.b += part->buf->blue;
460 /* Add a partial step to rgbval, in this pixel isn't precisely
461 aligned with the new source pixel
463 #if defined(CPU_COLDFIRE)
464 /* Coldfire EMAC math */
465 MAC(rgbinc.r, ixe, 0);
466 MAC(rgbinc.g, ixe, 1);
467 MAC(rgbinc.b, ixe, 2);
468 #else
469 /* generic C math */
470 rgbval.r += rgbinc.r * ixe;
471 rgbval.g += rgbinc.g * ixe;
472 rgbval.b += rgbinc.b * ixe;
473 #endif
475 #if defined(CPU_COLDFIRE)
476 /* get final EMAC result out of ACC registers */
477 MAC_OUT(rgbval.r, 0);
478 MAC_OUT(rgbval.g, 1);
479 MAC_OUT(rgbval.b, 2);
480 #endif
481 /* Now multiply the color increment to its proper value */
482 rgbinc.r *= h_i_val;
483 rgbinc.g *= h_i_val;
484 rgbinc.b *= h_i_val;
485 } else {
486 rgbval.r += rgbinc.r;
487 rgbval.g += rgbinc.g;
488 rgbval.b += rgbinc.b;
490 /* round and scale values, and accumulate or store to output */
491 if (accum)
493 out_line[ox].r += (rgbval.r + (1 << 21)) >> 22;
494 out_line[ox].g += (rgbval.g + (1 << 21)) >> 22;
495 out_line[ox].b += (rgbval.b + (1 << 21)) >> 22;
496 } else {
497 out_line[ox].r = (rgbval.r + (1 << 21)) >> 22;
498 out_line[ox].g = (rgbval.g + (1 << 21)) >> 22;
499 out_line[ox].b = (rgbval.b + (1 << 21)) >> 22;
501 #else
502 if (ixe >= h_o_val)
504 /* Store the new "current" pixel value in rgbval, and the color
505 step value in rgbinc.
507 ixe -= h_o_val;
508 val = *(part->buf);
509 inc = -val;
510 #if defined(CPU_COLDFIRE)
511 /* Coldfire EMAC math */
512 MAC(val, h_o_val, 0);
513 #elif defined(CPU_SH)
514 /* SH-1 16x16->32 math */
515 val = mul_u16_u16(val, h_o_val);
516 #else
517 /* generic C math */
518 val = val * h_o_val;
519 #endif
520 ix += 1;
521 /* If this wasn't the last pixel, add the next one to rgbinc. */
522 if (LIKELY(ix < (uint32_t)ctx->src->width)) {
523 part->buf++;
524 part->len--;
525 /* Fetch new pixels if needed */
526 FILL_BUF(part,ctx->store_part,ctx->args);
527 inc += *(part->buf);
528 /* Add a partial step to rgbval, in this pixel isn't precisely
529 aligned with the new source pixel
531 #if defined(CPU_COLDFIRE)
532 /* Coldfire EMAC math */
533 MAC(inc, ixe, 0);
534 #elif defined(CPU_SH)
535 /* SH-1 16x16->32 math */
536 val += mul_s16_s16(inc, ixe);
537 #else
538 /* generic C math */
539 val += inc * ixe;
540 #endif
542 #if defined(CPU_COLDFIRE)
543 /* get final EMAC result out of ACC register */
544 MAC_OUT(val, 0);
545 #endif
546 /* Now multiply the color increment to its proper value */
547 #if defined(CPU_SH)
548 /* SH-1 16x16->32 math */
549 inc = mul_s16_s16(inc, h_i_val);
550 #else
551 /* generic C math */
552 inc *= h_i_val;
553 #endif
554 } else
555 val += inc;
556 #if !(defined(CPU_SH) || defined(TEST_SH_MATH))
557 /* round and scale values, and accumulate or store to output */
558 if (accum)
560 out_line[ox] += (val + (1 << 21)) >> 22;
561 } else {
562 out_line[ox] = (val + (1 << 21)) >> 22;
564 #else
565 /* round and scale values, and accumulate or store to output */
566 if (accum)
568 out_line[ox] += val;
569 } else {
570 out_line[ox] = val;
572 #endif
573 #endif
574 ixe += h_i_val;
576 return true;
579 /* vertical linear scaler */
580 static inline bool scale_v_linear(struct rowset *rset,
581 struct scaler_context *ctx)
583 uint32_t iy, iye;
584 int32_t oy;
585 #if defined(CPU_SH) || defined (TEST_SH_MATH)
586 const uint32_t v_i_val = ctx->src->height - 1,
587 v_o_val = ctx->bm->height - 1;
588 #else
589 const uint32_t v_i_val = ctx->v_i_val,
590 v_o_val = ctx->v_o_val;
591 #endif
592 /* Set up our buffers, to store the increment and current value for each
593 column, and one temp buffer used to read in new rows.
595 #ifdef HAVE_LCD_COLOR
596 uint32_t *rowinc = (uint32_t *)(ctx->buf),
597 *rowval = rowinc + 3 * ctx->bm->width,
598 *rowtmp = rowval + 3 * ctx->bm->width,
599 #else
600 uint32_t *rowinc = (uint32_t *)(ctx->buf),
601 *rowval = rowinc + ctx->bm->width,
602 *rowtmp = rowval + ctx->bm->width,
603 #endif
604 *rowinc_px, *rowval_px, *rowtmp_px;
606 SDEBUGF("scale_v_linear\n");
607 iy = 0;
608 iye = v_o_val;
609 /* get first scaled row in rowtmp */
610 if(!ctx->h_scaler((void*)rowtmp, ctx, false))
611 return false;
612 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep)
614 if (iye >= v_o_val)
616 iye -= v_o_val;
617 iy += 1;
618 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval;
619 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++)
621 *rowinc_px = -*rowtmp_px;
622 *rowval_px = *rowtmp_px * v_o_val;
624 if (iy < (uint32_t)ctx->src->height)
626 if (!ctx->h_scaler((void*)rowtmp, ctx, false))
627 return false;
628 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval;
629 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++)
631 *rowinc_px += *rowtmp_px;
632 *rowval_px += *rowinc_px * iye;
633 *rowinc_px *= v_i_val;
636 } else
637 for(rowinc_px = rowinc, rowval_px = rowval; rowinc_px < rowval;
638 rowinc_px++, rowval_px++)
639 *rowval_px += *rowinc_px;
640 ctx->output_row(oy, (void*)rowval, ctx);
641 iye += v_i_val;
643 return true;
645 #endif /* HAVE_UPSCALER */
647 #if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
648 static void output_row_32_native_fromyuv(uint32_t row, void * row_in,
649 struct scaler_context *ctx)
651 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
652 #define DEST_STEP (ctx->bm->height)
653 #define Y_STEP (1)
654 #else
655 #define DEST_STEP (1)
656 #define Y_STEP (BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0))
657 #endif
659 int col;
660 uint8_t dy = DITHERY(row);
661 struct uint32_rgb *qp = (struct uint32_rgb *)row_in;
662 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
663 fb_data *dest = (fb_data *)ctx->bm->data + Y_STEP * row;
664 int delta = 127;
665 unsigned r, g, b, y, u, v;
667 for (col = 0; col < ctx->bm->width; col++) {
668 if (ctx->dither)
669 delta = DITHERXDY(col,dy);
670 y = SC_OUT(qp->b, ctx);
671 u = SC_OUT(qp->g, ctx);
672 v = SC_OUT(qp->r, ctx);
673 qp++;
674 yuv_to_rgb(y, u, v, &r, &g, &b);
675 r = (31 * r + (r >> 3) + delta) >> 8;
676 g = (63 * g + (g >> 2) + delta) >> 8;
677 b = (31 * b + (b >> 3) + delta) >> 8;
678 *dest = LCD_RGBPACK_LCD(r, g, b);
679 dest += DEST_STEP;
682 #endif
684 #if !defined(PLUGIN) || LCD_DEPTH > 1
685 static void output_row_32_native(uint32_t row, void * row_in,
686 struct scaler_context *ctx)
688 int col;
689 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
690 uint8_t dy = DITHERY(row);
691 #ifdef HAVE_LCD_COLOR
692 struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
693 #else
694 uint32_t *qp = (uint32_t*)row_in;
695 #endif
696 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
697 #if LCD_DEPTH == 2
698 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
699 /* greyscale iPods */
700 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
701 int shift = 6;
702 int delta = 127;
703 unsigned bright;
704 unsigned data = 0;
706 for (col = 0; col < ctx->bm->width; col++) {
707 if (ctx->dither)
708 delta = DITHERXDY(col,dy);
709 bright = SC_OUT(*qp++, ctx);
710 bright = (3 * bright + (bright >> 6) + delta) >> 8;
711 data |= (~bright & 3) << shift;
712 shift -= 2;
713 if (shift < 0) {
714 *dest++ = data;
715 data = 0;
716 shift = 6;
719 if (shift < 6)
720 *dest++ = data;
721 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
722 /* iriver H1x0 */
723 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
724 (row >> 2);
725 int shift = 2 * (row & 3);
726 int delta = 127;
727 unsigned bright;
729 for (col = 0; col < ctx->bm->width; col++) {
730 if (ctx->dither)
731 delta = DITHERXDY(col,dy);
732 bright = SC_OUT(*qp++, ctx);
733 bright = (3 * bright + (bright >> 6) + delta) >> 8;
734 *dest++ |= (~bright & 3) << shift;
736 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
737 /* iAudio M3 */
738 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
739 (row >> 3);
740 int shift = row & 7;
741 int delta = 127;
742 unsigned bright;
744 for (col = 0; col < ctx->bm->width; col++) {
745 if (ctx->dither)
746 delta = DITHERXDY(col,dy);
747 bright = SC_OUT(*qp++, ctx);
748 bright = (3 * bright + (bright >> 6) + delta) >> 8;
749 *dest++ |= vi_pattern[bright] << shift;
751 #endif /* LCD_PIXELFORMAT */
752 #elif LCD_DEPTH == 16
754 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
755 /* M:Robe 500 */
756 (void) fb_width;
757 fb_data *dest = (fb_data *)ctx->bm->data + row;
758 int delta = 127;
759 unsigned r, g, b;
760 struct uint32_rgb q0;
762 for (col = 0; col < ctx->bm->width; col++) {
763 if (ctx->dither)
764 delta = DITHERXDY(col,dy);
765 q0 = *qp++;
766 r = SC_OUT(q0.r, ctx);
767 g = SC_OUT(q0.g, ctx);
768 b = SC_OUT(q0.b, ctx);
769 r = (31 * r + (r >> 3) + delta) >> 8;
770 g = (63 * g + (g >> 2) + delta) >> 8;
771 b = (31 * b + (b >> 3) + delta) >> 8;
772 *dest = LCD_RGBPACK_LCD(r, g, b);
773 dest += ctx->bm->height;
775 #else
776 /* iriver h300, colour iPods, X5 */
777 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
778 int delta = 127;
779 unsigned r, g, b;
780 struct uint32_rgb q0;
782 for (col = 0; col < ctx->bm->width; col++) {
783 if (ctx->dither)
784 delta = DITHERXDY(col,dy);
785 q0 = *qp++;
786 r = SC_OUT(q0.r, ctx);
787 g = SC_OUT(q0.g, ctx);
788 b = SC_OUT(q0.b, ctx);
789 r = (31 * r + (r >> 3) + delta) >> 8;
790 g = (63 * g + (g >> 2) + delta) >> 8;
791 b = (31 * b + (b >> 3) + delta) >> 8;
792 *dest++ = LCD_RGBPACK_LCD(r, g, b);
794 #endif
796 #endif /* LCD_DEPTH */
798 #endif
800 #if defined(PLUGIN) && LCD_DEPTH > 1
801 unsigned int get_size_native(struct bitmap *bm)
803 return BM_SIZE(bm->width,bm->height,FORMAT_NATIVE,0);
806 const struct custom_format format_native = {
807 .output_row_8 = output_row_8_native,
808 #if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
809 .output_row_32 = {
810 output_row_32_native,
811 output_row_32_native_fromyuv
813 #else
814 .output_row_32 = output_row_32_native,
815 #endif
816 .get_size = get_size_native
818 #endif
820 int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
821 struct rowset *rset, unsigned char *buf, unsigned int len,
822 const struct custom_format *format,
823 IF_PIX_FMT(int format_index,)
824 struct img_part* (*store_part)(void *args),
825 void *args)
827 const int sw = src->width;
828 const int sh = src->height;
829 const int dw = bm->width;
830 const int dh = bm->height;
831 int ret;
832 #ifdef HAVE_LCD_COLOR
833 unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
834 #else
835 unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
836 #endif
837 #if MAX_SC_STACK_ALLOC
838 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
839 0 : needed];
840 #endif
841 ALIGN_BUFFER(buf, len, sizeof(uint32_t));
842 if (needed > len)
844 #if MAX_SC_STACK_ALLOC
845 if (needed > MAX_SC_STACK_ALLOC)
847 DEBUGF("unable to allocate required buffer: %d needed, "
848 "%d available, %d permitted from stack\n",
849 needed, len, MAX_SC_STACK_ALLOC);
850 return 0;
852 if (sizeof(sc_buf) < needed)
854 DEBUGF("failed to allocate large enough buffer on stack: "
855 "%d needed, only got %d",
856 needed, MAX_SC_STACK_ALLOC);
857 return 0;
859 #else
860 DEBUGF("unable to allocate required buffer: %d needed, "
861 "%d available\n", needed, len);
862 return 0;
863 #endif
866 struct scaler_context ctx;
867 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
868 cpu_boost(true);
869 #endif
870 ctx.store_part = store_part;
871 ctx.args = args;
872 #if MAX_SC_STACK_ALLOC
873 ctx.buf = needed > len ? sc_buf : buf;
874 #else
875 ctx.buf = buf;
876 #endif
877 ctx.len = len;
878 ctx.bm = bm;
879 ctx.src = src;
880 ctx.dither = dither;
881 #if defined(CPU_SH) || defined (TEST_SH_MATH)
882 uint32_t div;
883 #endif
884 #if !defined(PLUGIN)
885 #if defined(HAVE_LCD_COLOR) && defined(HAVE_JPEG)
886 ctx.output_row = format_index ? output_row_32_native_fromyuv
887 : output_row_32_native;
888 #else
889 ctx.output_row = output_row_32_native;
890 #endif
891 if (format)
892 #endif
893 #ifdef HAVE_LCD_COLOR
894 ctx.output_row = format->output_row_32[format_index];
895 #else
896 ctx.output_row = format->output_row_32;
897 #endif
898 #ifdef HAVE_UPSCALER
899 if (sw > dw)
901 #endif
902 ctx.h_scaler = scale_h_area;
903 #if defined(CPU_SH) || defined (TEST_SH_MATH)
904 div = sw;
905 #else
906 uint32_t h_div = (1U << 24) / sw;
907 ctx.h_i_val = sw * h_div;
908 ctx.h_o_val = dw * h_div;
909 #endif
910 #ifdef HAVE_UPSCALER
911 } else {
912 ctx.h_scaler = scale_h_linear;
913 #if defined(CPU_SH) || defined (TEST_SH_MATH)
914 div = dw - 1;
915 #else
916 uint32_t h_div = (1U << 24) / (dw - 1);
917 ctx.h_i_val = (sw - 1) * h_div;
918 ctx.h_o_val = (dw - 1) * h_div;
919 #endif
921 #endif
922 #ifdef CPU_COLDFIRE
923 unsigned old_macsr = coldfire_get_macsr();
924 coldfire_set_macsr(EMAC_UNSIGNED);
925 #endif
926 #ifdef HAVE_UPSCALER
927 if (sh > dh)
928 #endif
930 #if defined(CPU_SH) || defined (TEST_SH_MATH)
931 div *= sh;
932 ctx.recip = ((uint32_t)(-div)) / div + 1;
933 #else
934 uint32_t v_div = (1U << 22) / sh;
935 ctx.v_i_val = sh * v_div;
936 ctx.v_o_val = dh * v_div;
937 #endif
938 ret = scale_v_area(rset, &ctx);
940 #ifdef HAVE_UPSCALER
941 else
943 #if defined(CPU_SH) || defined (TEST_SH_MATH)
944 div *= dh - 1;
945 ctx.recip = ((uint32_t)(-div)) / div + 1;
946 #else
947 uint32_t v_div = (1U << 22) / dh;
948 ctx.v_i_val = (sh - 1) * v_div;
949 ctx.v_o_val = (dh - 1) * v_div;
950 #endif
951 ret = scale_v_linear(rset, &ctx);
953 #endif
954 #ifdef CPU_COLDFIRE
955 /* Restore emac status; other modules like tone control filter
956 * calculation may rely on it. */
957 coldfire_set_macsr(old_macsr);
958 #endif
959 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
960 cpu_boost(false);
961 #endif
962 if (!ret)
963 return 0;
964 return 1;