blob: bae72c8113bf8a7bb2764eb9a7f6700a1c5d6bf1 [file] [log] [blame]
Andrew Mahone781421a2008-12-09 23:07:59 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Michael Sevakis441fca12008-12-10 21:10:34 +00008 * $Id$
Andrew Mahone781421a2008-12-09 23:07:59 +00009 *
10 * Copyright (C) 2008 by Akio Idehara, Andrew Mahone
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * Implementation of area average and linear row and vertical scalers, and
24 * nearest-neighbor grey scaler (C) 2008 Andrew Mahone
25 *
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.
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
30 * KIND, either express or implied.
31 *
32 ****************************************************************************/
33
Andrew Mahone2fbf0972009-01-13 13:48:26 +000034#include <system.h>
Andrew Mahone781421a2008-12-09 23:07:59 +000035#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
Andrew Mahone524c5402008-12-14 17:58:04 +000038#include <general.h>
Andrew Mahone781421a2008-12-09 23:07:59 +000039#include "inttypes.h"
Andrew Mahone4eedc932009-01-04 21:22:05 +000040#ifndef PLUGIN
Andrew Mahone781421a2008-12-09 23:07:59 +000041#include "debug.h"
Andrew Mahone4eedc932009-01-04 21:22:05 +000042#endif
Andrew Mahone781421a2008-12-09 23:07:59 +000043#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"
Andrew Mahone4eedc932009-01-04 21:22:05 +000056#include <bmp.h>
Andrew Mahone781421a2008-12-09 23:07:59 +000057#include "resize.h"
Andrew Mahone781421a2008-12-09 23:07:59 +000058#else
59#undef DEBUGF
60#define DEBUGF(...)
61#endif
Andrew Mahoneeef79452009-05-06 04:53:56 +000062#include <jpeg_load.h>
Andrew Mahone781421a2008-12-09 23:07:59 +000063
Andrew Mahonef8877bf2009-03-14 01:41:02 +000064#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
72
Andrew Mahonef7fa7e52008-12-26 07:03:22 +000073/* 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.
76*/
77int recalc_dimension(struct dim *dst, struct dim *src)
78{
Andrew Mahone738a5642009-01-13 14:41:29 +000079 /* 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.
83 */
84 int sw = src->width * LCD_PIXEL_ASPECT_HEIGHT;
85 int sh = src->height * LCD_PIXEL_ASPECT_WIDTH;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +000086 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
Andrew Mahone738a5642009-01-13 14:41:29 +000092 if (dst->width > sw || dst->height > sh)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +000093 {
Andrew Mahone738a5642009-01-13 14:41:29 +000094 dst->width = sw;
95 dst->height = sh;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +000096 }
Andrew Mahone738a5642009-01-13 14:41:29 +000097 if (sw == dst->width && sh == dst->height)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +000098 return 1;
99#endif
Andrew Mahone738a5642009-01-13 14:41:29 +0000100 tmp = (sw * dst->height + (sh >> 1)) / sh;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000101 if (tmp > dst->width)
Andrew Mahone738a5642009-01-13 14:41:29 +0000102 dst->height = (sh * dst->width + (sw >> 1)) / sw;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000103 else
104 dst->width = tmp;
105 return src->width == dst->width && src->height == dst->height;
106}
107
Andrew Mahone995c89c2008-12-10 12:09:03 +0000108/* All of these scalers use variations of Bresenham's algorithm to convert from
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000109 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.
Andrew Mahone995c89c2008-12-10 12:09:03 +0000111*/
Andrew Mahone781421a2008-12-09 23:07:59 +0000112
Andrew Mahone995c89c2008-12-10 12:09:03 +0000113#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)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000117#endif
Andrew Mahone995c89c2008-12-10 12:09:03 +0000118
119/* read new img_part unconditionally, return false on failure */
Andrew Mahone781421a2008-12-09 23:07:59 +0000120#define FILL_BUF_INIT(img_part, store_part, args) { \
Andrew Mahone995c89c2008-12-10 12:09:03 +0000121 img_part = store_part(args); \
122 if (img_part == NULL) \
Andrew Mahone781421a2008-12-09 23:07:59 +0000123 return false; \
124}
125
Andrew Mahone995c89c2008-12-10 12:09:03 +0000126/* read new img_part if current one is empty, return false on failure */
Andrew Mahone781421a2008-12-09 23:07:59 +0000127#define FILL_BUF(img_part, store_part, args) { \
Andrew Mahone995c89c2008-12-10 12:09:03 +0000128 if (img_part->len == 0) \
129 img_part = store_part(args); \
130 if (img_part == NULL) \
Andrew Mahone781421a2008-12-09 23:07:59 +0000131 return false; \
132}
133
Andrew Mahone92785b82009-05-26 20:00:47 +0000134#if defined(CPU_COLDFIRE)
135#define MAC(op1, op2, num) \
136 asm volatile( \
137 "mac.l %0, %1, %%acc" #num \
138 : \
139 : "%d" (op1), "d" (op2)\
140 )
141#define MAC_OUT(dest, num) \
142 asm volatile( \
143 "movclr.l %%acc" #num ", %0" \
144 : "=d" (dest) \
145 )
146#elif defined(CPU_SH)
147/* calculate the 32-bit product of unsigned 16-bit op1 and op2 */
148static inline int32_t mul_s16_s16(int16_t op1, int16_t op2)
Andrew Mahone781421a2008-12-09 23:07:59 +0000149{
Andrew Mahone92785b82009-05-26 20:00:47 +0000150 return (int32_t)(op1 * op2);
Andrew Mahone781421a2008-12-09 23:07:59 +0000151}
152
Andrew Mahone92785b82009-05-26 20:00:47 +0000153/* calculate the 32-bit product of signed 16-bit op1 and op2 */
154static inline uint32_t mul_u16_u16(uint16_t op1, uint16_t op2)
155{
156 return (uint32_t)(op1 * op2);
157}
158#endif
159
Andrew Mahone781421a2008-12-09 23:07:59 +0000160/* horizontal area average scaler */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000161static bool scale_h_area(void *out_line_ptr,
Andrew Mahone781421a2008-12-09 23:07:59 +0000162 struct scaler_context *ctx, bool accum)
163{
164 SDEBUGF("scale_h_area\n");
165 unsigned int ix, ox, oxe, mul;
Andrew Mahone92785b82009-05-26 20:00:47 +0000166#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
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000173#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
Andrew Mahone781421a2008-12-09 23:07:59 +0000180 struct img_part *part;
181 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
182 ox = 0;
183 oxe = 0;
Andrew Mahone781421a2008-12-09 23:07:59 +0000184 mul = 0;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000185 /* give other tasks a chance to run */
Andrew Mahone07e982d2009-01-08 02:49:23 +0000186 yield();
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000187 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++)
Andrew Mahone781421a2008-12-09 23:07:59 +0000188 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000189 oxe += h_o_val;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000190 /* end of current area has been reached */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000191 /* fill buffer if needed */
192 FILL_BUF(part,ctx->store_part,ctx->args);
193#ifdef HAVE_LCD_COLOR
Andrew Mahone92785b82009-05-26 20:00:47 +0000194 if (oxe >= h_i_val)
Andrew Mahone781421a2008-12-09 23:07:59 +0000195 {
Andrew Mahone995c89c2008-12-10 12:09:03 +0000196 /* "reset" error, which now represents partial coverage of next
197 pixel by the next area
198 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000199 oxe -= h_i_val;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000200
Andrew Mahone92785b82009-05-26 20:00:47 +0000201#if defined(CPU_COLDFIRE)
202/* Coldfire EMAC math */
Andrew Mahone995c89c2008-12-10 12:09:03 +0000203 /* add saved partial pixel from start of area */
Andrew Mahone92785b82009-05-26 20:00:47 +0000204 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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000227
Andrew Mahone995c89c2008-12-10 12:09:03 +0000228 /* 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;
Andrew Mahone92785b82009-05-26 20:00:47 +0000232 mul = h_o_val - oxe;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000233 rgbvalacc.r += rgbvaltmp.r * mul;
234 rgbvalacc.g += rgbvaltmp.g * mul;
235 rgbvalacc.b += rgbvaltmp.b * mul;
Andrew Mahone92785b82009-05-26 20:00:47 +0000236#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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000240 /* store or accumulate to output row */
241 if (accum)
242 {
243 rgbvalacc.r += out_line[ox].r;
244 rgbvalacc.g += out_line[ox].g;
245 rgbvalacc.b += out_line[ox].b;
246 }
247 out_line[ox].r = rgbvalacc.r;
248 out_line[ox].g = rgbvalacc.g;
249 out_line[ox].b = rgbvalacc.b;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000250 /* reset accumulator */
251 rgbvalacc.r = 0;
252 rgbvalacc.g = 0;
253 rgbvalacc.b = 0;
Andrew Mahone92785b82009-05-26 20:00:47 +0000254 mul = oxe;
Andrew Mahone781421a2008-12-09 23:07:59 +0000255 ox += 1;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000256 /* inside an area */
Andrew Mahone781421a2008-12-09 23:07:59 +0000257 } else {
Andrew Mahone995c89c2008-12-10 12:09:03 +0000258 /* add pixel value to accumulator */
259 rgbvalacc.r += part->buf->red;
260 rgbvalacc.g += part->buf->green;
261 rgbvalacc.b += part->buf->blue;
Andrew Mahone781421a2008-12-09 23:07:59 +0000262 }
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000263#else
Andrew Mahone92785b82009-05-26 20:00:47 +0000264 if (oxe >= h_i_val)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000265 {
266 /* "reset" error, which now represents partial coverage of next
267 pixel by the next area
268 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000269 oxe -= h_i_val;
270#if defined(CPU_COLDFIRE)
271/* Coldfire EMAC math */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000272 /* add saved partial pixel from start of area */
Andrew Mahone92785b82009-05-26 20:00:47 +0000273 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);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000284
285 /* get new pixel , then add its partial coverage to this area */
286 tmp = *(part->buf);
Andrew Mahone92785b82009-05-26 20:00:47 +0000287 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);
293
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))
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000300 /* round, divide, and either store or accumulate to output row */
Andrew Mahone92785b82009-05-26 20:00:47 +0000301 acc = (acc + (1 << 21)) >> 22;
302#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000303 if (accum)
304 {
305 acc += out_line[ox];
306 }
307 out_line[ox] = acc;
308 /* reset accumulator */
309 acc = 0;
Andrew Mahone92785b82009-05-26 20:00:47 +0000310 mul = oxe;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000311 ox += 1;
312 /* inside an area */
313 } else {
314 /* add pixel value to accumulator */
315 acc += *(part->buf);
316 }
317#endif
318 part->buf++;
319 part->len--;
Andrew Mahone781421a2008-12-09 23:07:59 +0000320 }
321 return true;
322}
323
324/* vertical area average scaler */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000325static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx)
Andrew Mahone781421a2008-12-09 23:07:59 +0000326{
Andrew Mahone92785b82009-05-26 20:00:47 +0000327 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
Andrew Mahone995c89c2008-12-10 12:09:03 +0000335
336 /* Set up rounding and scale factors */
Andrew Mahone781421a2008-12-09 23:07:59 +0000337 mul = 0;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000338 oy = rset->rowstart;
Andrew Mahone781421a2008-12-09 23:07:59 +0000339 oye = 0;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000340#ifdef HAVE_LCD_COLOR
341 uint32_t *rowacc = (uint32_t *) ctx->buf,
Andrew Mahone92785b82009-05-26 20:00:47 +0000342 *rowtmp = rowacc + 3 * ctx->bm->width,
343 *rowacc_px, *rowtmp_px;
Andrew Mahone07e982d2009-01-08 02:49:23 +0000344 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb));
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000345#else
346 uint32_t *rowacc = (uint32_t *) ctx->buf,
Andrew Mahone92785b82009-05-26 20:00:47 +0000347 *rowtmp = rowacc + ctx->bm->width,
348 *rowacc_px, *rowtmp_px;
Andrew Mahone07e982d2009-01-08 02:49:23 +0000349 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t));
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000350#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000351 SDEBUGF("scale_v_area\n");
Andrew Mahone995c89c2008-12-10 12:09:03 +0000352 /* zero the accumulator and temp rows */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000353 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++)
Andrew Mahone781421a2008-12-09 23:07:59 +0000354 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000355 oye += v_o_val;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000356 /* end of current area has been reached */
Andrew Mahone92785b82009-05-26 20:00:47 +0000357 if (oye >= v_i_val)
Andrew Mahone781421a2008-12-09 23:07:59 +0000358 {
Andrew Mahone995c89c2008-12-10 12:09:03 +0000359 /* "reset" error, which now represents partial coverage of the next
360 row by the next area
361 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000362 oye -= v_i_val;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000363 /* add stored partial row to accumulator */
Andrew Mahone92785b82009-05-26 20:00:47 +0000364 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;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000367 /* store new scaled row in temp row */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000368 if(!ctx->h_scaler(rowtmp, ctx, false))
Andrew Mahone995c89c2008-12-10 12:09:03 +0000369 return false;
370 /* add partial coverage by new row to this area, then round and
371 scale to final value
372 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000373 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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000377 ctx->output_row(oy, (void*)rowacc, ctx);
Andrew Mahone995c89c2008-12-10 12:09:03 +0000378 /* clear accumulator row, store partial coverage for next row */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000379#ifdef HAVE_LCD_COLOR
Andrew Mahone07e982d2009-01-08 02:49:23 +0000380 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000381#else
Andrew Mahone07e982d2009-01-08 02:49:23 +0000382 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t));
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000383#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000384 mul = oye;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000385 oy += rset->rowstep;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000386 /* inside an area */
Andrew Mahone781421a2008-12-09 23:07:59 +0000387 } else {
Andrew Mahone995c89c2008-12-10 12:09:03 +0000388 /* accumulate new scaled row to rowacc */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000389 if (!ctx->h_scaler(rowacc, ctx, true))
Andrew Mahone995c89c2008-12-10 12:09:03 +0000390 return false;
Andrew Mahone781421a2008-12-09 23:07:59 +0000391 }
392 }
393 return true;
Andrew Mahone781421a2008-12-09 23:07:59 +0000394}
395
396#ifdef HAVE_UPSCALER
Andrew Mahone781421a2008-12-09 23:07:59 +0000397/* horizontal linear scaler */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000398static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx,
399 bool accum)
Andrew Mahone781421a2008-12-09 23:07:59 +0000400{
401 unsigned int ix, ox, ixe;
Andrew Mahone92785b82009-05-26 20:00:47 +0000402#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
Andrew Mahone995c89c2008-12-10 12:09:03 +0000409 /* 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.
412 */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000413#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
Andrew Mahone781421a2008-12-09 23:07:59 +0000419 struct img_part *part;
420 SDEBUGF("scale_h_linear\n");
421 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
422 ix = 0;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000423 /* The error is set so that values are initialized on the first pass. */
Andrew Mahone92785b82009-05-26 20:00:47 +0000424 ixe = h_o_val;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000425 /* give other tasks a chance to run */
Andrew Mahone07e982d2009-01-08 02:49:23 +0000426 yield();
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000427 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++)
428 {
429#ifdef HAVE_LCD_COLOR
Andrew Mahone92785b82009-05-26 20:00:47 +0000430 if (ixe >= h_o_val)
Andrew Mahone781421a2008-12-09 23:07:59 +0000431 {
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000432 /* Store the new "current" pixel value in rgbval, and the color
Andrew Mahone995c89c2008-12-10 12:09:03 +0000433 step value in rgbinc.
434 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000435 ixe -= h_o_val;
Andrew Mahone781421a2008-12-09 23:07:59 +0000436 rgbinc.r = -(part->buf->red);
437 rgbinc.g = -(part->buf->green);
438 rgbinc.b = -(part->buf->blue);
Andrew Mahone92785b82009-05-26 20:00:47 +0000439#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 */
Andrew Mahone781421a2008-12-09 23:07:59 +0000450 ix += 1;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000451 /* If this wasn't the last pixel, add the next one to rgbinc. */
Andrew Mahone92785b82009-05-26 20:00:47 +0000452 if (LIKELY(ix < (uint32_t)ctx->src->width)) {
Andrew Mahone781421a2008-12-09 23:07:59 +0000453 part->buf++;
454 part->len--;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000455 /* Fetch new pixels if needed */
Andrew Mahone781421a2008-12-09 23:07:59 +0000456 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;
Andrew Mahone995c89c2008-12-10 12:09:03 +0000460 /* Add a partial step to rgbval, in this pixel isn't precisely
461 aligned with the new source pixel
462 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000463#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 */
Andrew Mahone781421a2008-12-09 23:07:59 +0000470 rgbval.r += rgbinc.r * ixe;
471 rgbval.g += rgbinc.g * ixe;
472 rgbval.b += rgbinc.b * ixe;
Andrew Mahone92785b82009-05-26 20:00:47 +0000473#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000474 }
Andrew Mahone92785b82009-05-26 20:00:47 +0000475#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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000485 } else {
486 rgbval.r += rgbinc.r;
487 rgbval.g += rgbinc.g;
488 rgbval.b += rgbinc.b;
Andrew Mahone781421a2008-12-09 23:07:59 +0000489 }
Andrew Mahone995c89c2008-12-10 12:09:03 +0000490 /* round and scale values, and accumulate or store to output */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000491 if (accum)
492 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000493 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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000496 } else {
Andrew Mahone92785b82009-05-26 20:00:47 +0000497 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;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000500 }
501#else
Andrew Mahone92785b82009-05-26 20:00:47 +0000502 if (ixe >= h_o_val)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000503 {
504 /* Store the new "current" pixel value in rgbval, and the color
505 step value in rgbinc.
506 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000507 ixe -= h_o_val;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000508 val = *(part->buf);
509 inc = -val;
Andrew Mahone92785b82009-05-26 20:00:47 +0000510#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
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000520 ix += 1;
521 /* If this wasn't the last pixel, add the next one to rgbinc. */
Andrew Mahone92785b82009-05-26 20:00:47 +0000522 if (LIKELY(ix < (uint32_t)ctx->src->width)) {
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000523 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
530 */
Andrew Mahone92785b82009-05-26 20:00:47 +0000531#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
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000541 }
Andrew Mahone92785b82009-05-26 20:00:47 +0000542#if defined(CPU_COLDFIRE)
543/* get final EMAC result out of ACC register */
544 MAC_OUT(val, 0);
545#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000546 /* Now multiply the color increment to its proper value */
Andrew Mahone92785b82009-05-26 20:00:47 +0000547#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
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000554 } else
555 val += inc;
Andrew Mahone92785b82009-05-26 20:00:47 +0000556#if !(defined(CPU_SH) || defined(TEST_SH_MATH))
557 /* round and scale values, and accumulate or store to output */
558 if (accum)
559 {
560 out_line[ox] += (val + (1 << 21)) >> 22;
561 } else {
562 out_line[ox] = (val + (1 << 21)) >> 22;
563 }
564#else
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000565 /* round and scale values, and accumulate or store to output */
566 if (accum)
567 {
568 out_line[ox] += val;
569 } else {
570 out_line[ox] = val;
571 }
572#endif
Andrew Mahone92785b82009-05-26 20:00:47 +0000573#endif
574 ixe += h_i_val;
Andrew Mahone781421a2008-12-09 23:07:59 +0000575 }
576 return true;
577}
578
579/* vertical linear scaler */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000580static inline bool scale_v_linear(struct rowset *rset,
581 struct scaler_context *ctx)
Andrew Mahone781421a2008-12-09 23:07:59 +0000582{
Andrew Mahone92785b82009-05-26 20:00:47 +0000583 uint32_t mul, iy, iye;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000584 int32_t oy;
Andrew Mahone92785b82009-05-26 20:00:47 +0000585#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.
Andrew Mahone995c89c2008-12-10 12:09:03 +0000594 */
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000595#ifdef HAVE_LCD_COLOR
596 uint32_t *rowinc = (uint32_t *)(ctx->buf),
597 *rowval = rowinc + 3 * ctx->bm->width,
Andrew Mahone92785b82009-05-26 20:00:47 +0000598 *rowtmp = rowval + 3 * ctx->bm->width,
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000599#else
600 uint32_t *rowinc = (uint32_t *)(ctx->buf),
601 *rowval = rowinc + ctx->bm->width,
Andrew Mahone92785b82009-05-26 20:00:47 +0000602 *rowtmp = rowval + ctx->bm->width,
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000603#endif
Andrew Mahone92785b82009-05-26 20:00:47 +0000604 *rowinc_px, *rowval_px, *rowtmp_px;
Andrew Mahone781421a2008-12-09 23:07:59 +0000605
606 SDEBUGF("scale_v_linear\n");
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000607 mul = 0;
608 iy = 0;
Andrew Mahone92785b82009-05-26 20:00:47 +0000609 iye = v_o_val;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000610 /* get first scaled row in rowtmp */
611 if(!ctx->h_scaler((void*)rowtmp, ctx, false))
Andrew Mahone995c89c2008-12-10 12:09:03 +0000612 return false;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000613 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep)
Andrew Mahone781421a2008-12-09 23:07:59 +0000614 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000615 if (iye >= v_o_val)
Andrew Mahone781421a2008-12-09 23:07:59 +0000616 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000617 iye -= v_o_val;
Andrew Mahone781421a2008-12-09 23:07:59 +0000618 iy += 1;
Andrew Mahone92785b82009-05-26 20:00:47 +0000619 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval;
620 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++)
Andrew Mahone781421a2008-12-09 23:07:59 +0000621 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000622 *rowinc_px = -*rowtmp_px;
623 *rowval_px = *rowtmp_px * v_o_val;
Andrew Mahone781421a2008-12-09 23:07:59 +0000624 }
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000625 if (iy < (uint32_t)ctx->src->height)
626 {
627 if (!ctx->h_scaler((void*)rowtmp, ctx, false))
628 return false;
Andrew Mahone92785b82009-05-26 20:00:47 +0000629 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval;
630 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000631 {
Andrew Mahone92785b82009-05-26 20:00:47 +0000632 *rowinc_px += *rowtmp_px;
633 *rowval_px += *rowinc_px * iye;
634 *rowinc_px *= v_i_val;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000635 }
636 }
637 } else
Andrew Mahone92785b82009-05-26 20:00:47 +0000638 for(rowinc_px = rowinc, rowval_px = rowval; rowinc_px < rowval;
639 rowinc_px++, rowval_px++)
640 *rowval_px += *rowinc_px;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000641 ctx->output_row(oy, (void*)rowval, ctx);
Andrew Mahone92785b82009-05-26 20:00:47 +0000642 iye += v_i_val;
Andrew Mahone781421a2008-12-09 23:07:59 +0000643 }
644 return true;
Andrew Mahone781421a2008-12-09 23:07:59 +0000645}
646#endif /* HAVE_UPSCALER */
Andrew Mahone781421a2008-12-09 23:07:59 +0000647
Andrew Mahoneeef79452009-05-06 04:53:56 +0000648#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
Andrew Mahone91efc162009-05-09 07:31:27 +0000649static void output_row_32_native_fromyuv(uint32_t row, void * row_in,
Andrew Mahoneeef79452009-05-06 04:53:56 +0000650 struct scaler_context *ctx)
651{
652 int col;
653 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
654 uint8_t dy = DITHERY(row);
655 struct uint32_rgb *qp = (struct uint32_rgb *)row_in;
656 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
657 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
658 int delta = 127;
659 unsigned r, g, b, y, u, v;
660
661 for (col = 0; col < ctx->bm->width; col++) {
662 if (ctx->dither)
663 delta = DITHERXDY(col,dy);
Andrew Mahone92785b82009-05-26 20:00:47 +0000664 y = SC_OUT(qp->b, ctx);
665 u = SC_OUT(qp->g, ctx);
666 v = SC_OUT(qp->r, ctx);
Andrew Mahoneeef79452009-05-06 04:53:56 +0000667 qp++;
668 yuv_to_rgb(y, u, v, &r, &g, &b);
669 r = (31 * r + (r >> 3) + delta) >> 8;
670 g = (63 * g + (g >> 2) + delta) >> 8;
671 b = (31 * b + (b >> 3) + delta) >> 8;
672 *dest++ = LCD_RGBPACK_LCD(r, g, b);
673 }
674}
675#endif
676
Andrew Mahone20f76d62009-05-04 15:46:41 +0000677#if !defined(PLUGIN) || LCD_DEPTH > 1
Andrew Mahone91efc162009-05-09 07:31:27 +0000678static void output_row_32_native(uint32_t row, void * row_in,
Andrew Mahone20f76d62009-05-04 15:46:41 +0000679 struct scaler_context *ctx)
Andrew Mahone781421a2008-12-09 23:07:59 +0000680{
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000681 int col;
682 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
683 uint8_t dy = DITHERY(row);
684#ifdef HAVE_LCD_COLOR
685 struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
686#else
687 uint32_t *qp = (uint32_t*)row_in;
688#endif
Andrew Mahone4eedc932009-01-04 21:22:05 +0000689 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000690#if LCD_DEPTH == 2
691#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
692 /* greyscale iPods */
693 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
694 int shift = 6;
695 int delta = 127;
696 unsigned bright;
697 unsigned data = 0;
698
699 for (col = 0; col < ctx->bm->width; col++) {
700 if (ctx->dither)
701 delta = DITHERXDY(col,dy);
Andrew Mahone92785b82009-05-26 20:00:47 +0000702 bright = SC_OUT(*qp++, ctx);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000703 bright = (3 * bright + (bright >> 6) + delta) >> 8;
704 data |= (~bright & 3) << shift;
705 shift -= 2;
706 if (shift < 0) {
707 *dest++ = data;
708 data = 0;
709 shift = 6;
710 }
711 }
712 if (shift < 6)
713 *dest++ = data;
714#elif LCD_PIXELFORMAT == VERTICAL_PACKING
715 /* iriver H1x0 */
716 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
717 (row >> 2);
718 int shift = 2 * (row & 3);
719 int delta = 127;
720 unsigned bright;
721
722 for (col = 0; col < ctx->bm->width; col++) {
723 if (ctx->dither)
724 delta = DITHERXDY(col,dy);
Andrew Mahone92785b82009-05-26 20:00:47 +0000725 bright = SC_OUT(*qp++, ctx);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000726 bright = (3 * bright + (bright >> 6) + delta) >> 8;
727 *dest++ |= (~bright & 3) << shift;
728 }
729#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
730 /* iAudio M3 */
731 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
732 (row >> 3);
733 int shift = row & 7;
734 int delta = 127;
735 unsigned bright;
736
737 for (col = 0; col < ctx->bm->width; col++) {
738 if (ctx->dither)
739 delta = DITHERXDY(col,dy);
Andrew Mahone92785b82009-05-26 20:00:47 +0000740 bright = SC_OUT(*qp++, ctx);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000741 bright = (3 * bright + (bright >> 6) + delta) >> 8;
742 *dest++ |= vi_pattern[bright] << shift;
743 }
744#endif /* LCD_PIXELFORMAT */
745#elif LCD_DEPTH == 16
746 /* iriver h300, colour iPods, X5 */
747 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
748 int delta = 127;
749 unsigned r, g, b;
750 struct uint32_rgb q0;
751
752 for (col = 0; col < ctx->bm->width; col++) {
753 if (ctx->dither)
754 delta = DITHERXDY(col,dy);
755 q0 = *qp++;
Andrew Mahone92785b82009-05-26 20:00:47 +0000756 r = SC_OUT(q0.r, ctx);
757 g = SC_OUT(q0.g, ctx);
758 b = SC_OUT(q0.b, ctx);
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000759 r = (31 * r + (r >> 3) + delta) >> 8;
760 g = (63 * g + (g >> 2) + delta) >> 8;
761 b = (31 * b + (b >> 3) + delta) >> 8;
762 *dest++ = LCD_RGBPACK_LCD(r, g, b);
763 }
764#endif /* LCD_DEPTH */
765}
Andrew Mahone4eedc932009-01-04 21:22:05 +0000766#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000767
Andrew Mahone20f76d62009-05-04 15:46:41 +0000768#if defined(PLUGIN) && LCD_DEPTH > 1
769unsigned int get_size_native(struct bitmap *bm)
770{
Andrew Mahonecda90742009-05-08 03:59:51 +0000771 return BM_SIZE(bm->width,bm->height,FORMAT_NATIVE,0);
Andrew Mahone20f76d62009-05-04 15:46:41 +0000772}
773
774const struct custom_format format_native = {
Andrew Mahone91efc162009-05-09 07:31:27 +0000775 .output_row_8 = output_row_8_native,
Andrew Mahoneeef79452009-05-06 04:53:56 +0000776#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
Andrew Mahone91efc162009-05-09 07:31:27 +0000777 .output_row_32 = {
778 output_row_32_native,
779 output_row_32_native_fromyuv
Andrew Mahoneeef79452009-05-06 04:53:56 +0000780 },
781#else
Andrew Mahone91efc162009-05-09 07:31:27 +0000782 .output_row_32 = output_row_32_native,
Andrew Mahoneeef79452009-05-06 04:53:56 +0000783#endif
Andrew Mahone20f76d62009-05-04 15:46:41 +0000784 .get_size = get_size_native
785};
786#endif
787
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000788int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
789 struct rowset *rset, unsigned char *buf, unsigned int len,
Andrew Mahone90586202008-12-26 07:05:13 +0000790 const struct custom_format *format,
Andrew Mahoneeef79452009-05-06 04:53:56 +0000791 IF_PIX_FMT(int format_index,)
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000792 struct img_part* (*store_part)(void *args),
793 void *args)
794{
Andrew Mahone781421a2008-12-09 23:07:59 +0000795 const int sw = src->width;
796 const int sh = src->height;
797 const int dw = bm->width;
798 const int dh = bm->height;
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000799 int ret;
800#ifdef HAVE_LCD_COLOR
801 unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
Andrew Mahone781421a2008-12-09 23:07:59 +0000802#else
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000803 unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
Andrew Mahone781421a2008-12-09 23:07:59 +0000804#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000805#if MAX_SC_STACK_ALLOC
806 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
807 0 : needed];
Andrew Mahone781421a2008-12-09 23:07:59 +0000808#endif
Andrew Mahone2fbf0972009-01-13 13:48:26 +0000809 ALIGN_BUFFER(buf, len, sizeof(uint32_t));
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000810 if (needed > len)
811 {
812#if MAX_SC_STACK_ALLOC
813 if (needed > MAX_SC_STACK_ALLOC)
Andrew Mahone781421a2008-12-09 23:07:59 +0000814 {
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000815 DEBUGF("unable to allocate required buffer: %d needed, "
816 "%d available, %d permitted from stack\n",
817 needed, len, MAX_SC_STACK_ALLOC);
818 return 0;
Andrew Mahone781421a2008-12-09 23:07:59 +0000819 }
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000820 if (sizeof(sc_buf) < needed)
821 {
822 DEBUGF("failed to allocate large enough buffer on stack: "
823 "%d needed, only got %d",
824 needed, MAX_SC_STACK_ALLOC);
825 return 0;
826 }
827#else
828 DEBUGF("unable to allocate required buffer: %d needed, "
829 "%d available\n", needed, len);
830 return 0;
831#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000832 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000833
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000834 struct scaler_context ctx;
Andrew Mahone4eedc932009-01-04 21:22:05 +0000835#ifdef HAVE_ADJUSTABLE_CPU_FREQ
Andrew Mahone07e982d2009-01-08 02:49:23 +0000836 cpu_boost(true);
Andrew Mahone4eedc932009-01-04 21:22:05 +0000837#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000838 ctx.store_part = store_part;
839 ctx.args = args;
Andrew Mahone781421a2008-12-09 23:07:59 +0000840#if MAX_SC_STACK_ALLOC
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000841 ctx.buf = needed > len ? sc_buf : buf;
Andrew Mahone781421a2008-12-09 23:07:59 +0000842#else
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000843 ctx.buf = buf;
Andrew Mahone781421a2008-12-09 23:07:59 +0000844#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000845 ctx.len = len;
846 ctx.bm = bm;
847 ctx.src = src;
848 ctx.dither = dither;
Andrew Mahone92785b82009-05-26 20:00:47 +0000849#if defined(CPU_SH) || defined (TEST_SH_MATH)
850 uint32_t div;
851#endif
Andrew Mahone20f76d62009-05-04 15:46:41 +0000852#if !defined(PLUGIN)
Andrew Mahoneeef79452009-05-06 04:53:56 +0000853#if defined(HAVE_LCD_COLOR) && defined(HAVE_JPEG)
Andrew Mahone91efc162009-05-09 07:31:27 +0000854 ctx.output_row = format_index ? output_row_32_native_fromyuv
855 : output_row_32_native;
Andrew Mahoneeef79452009-05-06 04:53:56 +0000856#else
Andrew Mahone91efc162009-05-09 07:31:27 +0000857 ctx.output_row = output_row_32_native;
Andrew Mahoneeef79452009-05-06 04:53:56 +0000858#endif
Andrew Mahone90586202008-12-26 07:05:13 +0000859 if (format)
Andrew Mahone4eedc932009-01-04 21:22:05 +0000860#endif
Andrew Mahone00d6cfd2009-05-26 20:26:05 +0000861#ifdef HAVE_LCD_COLOR
Andrew Mahone91efc162009-05-09 07:31:27 +0000862 ctx.output_row = format->output_row_32[format_index];
Andrew Mahoneeef79452009-05-06 04:53:56 +0000863#else
Andrew Mahone91efc162009-05-09 07:31:27 +0000864 ctx.output_row = format->output_row_32;
Andrew Mahoneeef79452009-05-06 04:53:56 +0000865#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000866#ifdef HAVE_UPSCALER
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000867 if (sw > dw)
868 {
Andrew Mahone781421a2008-12-09 23:07:59 +0000869#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000870 ctx.h_scaler = scale_h_area;
Andrew Mahone92785b82009-05-26 20:00:47 +0000871#if defined(CPU_SH) || defined (TEST_SH_MATH)
872 div = sw;
873#else
874 uint32_t h_div = (1U << 24) / sw;
875 ctx.h_i_val = sw * h_div;
876 ctx.h_o_val = dw * h_div;
877#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000878#ifdef HAVE_UPSCALER
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000879 } else {
880 ctx.h_scaler = scale_h_linear;
Andrew Mahone92785b82009-05-26 20:00:47 +0000881#if defined(CPU_SH) || defined (TEST_SH_MATH)
882 div = dw - 1;
883#else
884 uint32_t h_div = (1U << 24) / (dw - 1);
885 ctx.h_i_val = (sw - 1) * h_div;
886 ctx.h_o_val = (dw - 1) * h_div;
887#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000888 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000889#endif
Andrew Mahone92785b82009-05-26 20:00:47 +0000890#ifdef CPU_COLDFIRE
891 coldfire_set_macsr(EMAC_UNSIGNED);
892#endif
Andrew Mahone781421a2008-12-09 23:07:59 +0000893#ifdef HAVE_UPSCALER
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000894 if (sh > dh)
Andrew Mahone781421a2008-12-09 23:07:59 +0000895#endif
Andrew Mahone92785b82009-05-26 20:00:47 +0000896 {
897#if defined(CPU_SH) || defined (TEST_SH_MATH)
898 div *= sh;
899 ctx.recip = ((uint32_t)(-div)) / div + 1;
900#else
901 uint32_t v_div = (1U << 22) / sh;
902 ctx.v_i_val = sh * v_div;
903 ctx.v_o_val = dh * v_div;
904#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000905 ret = scale_v_area(rset, &ctx);
Andrew Mahone92785b82009-05-26 20:00:47 +0000906 }
Andrew Mahone781421a2008-12-09 23:07:59 +0000907#ifdef HAVE_UPSCALER
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000908 else
Andrew Mahone92785b82009-05-26 20:00:47 +0000909 {
910#if defined(CPU_SH) || defined (TEST_SH_MATH)
911 div *= dh - 1;
912 ctx.recip = ((uint32_t)(-div)) / div + 1;
913#else
914 uint32_t v_div = (1U << 22) / dh;
915 ctx.v_i_val = (sh - 1) * v_div;
916 ctx.v_o_val = (dh - 1) * v_div;
Andrew Mahone781421a2008-12-09 23:07:59 +0000917#endif
Andrew Mahone92785b82009-05-26 20:00:47 +0000918 ret = scale_v_linear(rset, &ctx);
919 }
920#endif
Andrew Mahone4eedc932009-01-04 21:22:05 +0000921#ifdef HAVE_ADJUSTABLE_CPU_FREQ
Andrew Mahone07e982d2009-01-08 02:49:23 +0000922 cpu_boost(false);
Andrew Mahone4eedc932009-01-04 21:22:05 +0000923#endif
Andrew Mahonef7fa7e52008-12-26 07:03:22 +0000924 if (!ret)
925 return 0;
Andrew Mahone90586202008-12-26 07:05:13 +0000926 return 1;
Andrew Mahone781421a2008-12-09 23:07:59 +0000927}