summaryrefslogtreecommitdiff
path: root/apps/recorder/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/recorder/resize.c')
-rw-r--r--apps/recorder/resize.c920
1 files changed, 418 insertions, 502 deletions
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index e41501032a..3c1d34f046 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -59,15 +59,45 @@
59#define DEBUGF(...) 59#define DEBUGF(...)
60#endif 60#endif
61 61
62/* calculate the maximum dimensions which will preserve the aspect ration of
63 src while fitting in the constraints passed in dst, and store result in dst,
64 returning 0 if rounding and 1 if not rounding.
65*/
66int recalc_dimension(struct dim *dst, struct dim *src)
67{
68 int tmp;
69 if (dst->width <= 0)
70 dst->width = LCD_WIDTH;
71 if (dst->height <= 0)
72 dst->height = LCD_HEIGHT;
73#ifndef HAVE_UPSCALER
74 if (dst->width > src->width || dst->height > src->height)
75 {
76 dst->width = src->width;
77 dst->height = src->height;
78 }
79 if (src->width == dst->width && src->height == dst->height)
80 return 1;
81#endif
82 tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
83 if (tmp > dst->width)
84 dst->height = (src->height * dst->width + (src->width >> 1))
85 / src->width;
86 else
87 dst->width = tmp;
88 return src->width == dst->width && src->height == dst->height;
89}
90
62/* All of these scalers use variations of Bresenham's algorithm to convert from 91/* All of these scalers use variations of Bresenham's algorithm to convert from
63 their input to output coordinates. The color scalers have the error value 92 their input to output coordinates. The error value is shifted from the
64 shifted so that it is a useful input to the scaling algorithm. 93 "classic" version such that it is a useful input to the scaling calculation.
65*/ 94*/
66 95
67#ifdef HAVE_LCD_COLOR 96#ifdef HAVE_LCD_COLOR
68/* dither + pack on channel of RGB565, R an B share a packing macro */ 97/* dither + pack on channel of RGB565, R an B share a packing macro */
69#define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) 98#define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8)
70#define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) 99#define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8)
100#endif
71 101
72/* read new img_part unconditionally, return false on failure */ 102/* read new img_part unconditionally, return false on failure */
73#define FILL_BUF_INIT(img_part, store_part, args) { \ 103#define FILL_BUF_INIT(img_part, store_part, args) { \
@@ -84,183 +114,204 @@
84 return false; \ 114 return false; \
85} 115}
86 116
87struct uint32_rgb { 117/* struct which containers various parameters shared between vertical scaler,
88 uint32_t r; 118 horizontal scaler, and row output
89 uint32_t g; 119*/
90 uint32_t b;
91};
92
93struct scaler_context { 120struct scaler_context {
94 uint32_t divmul; 121 uint32_t divisor;
95 uint32_t round; 122 uint32_t round;
96 struct img_part* (*store_part)(void *); 123 struct bitmap *bm;
97 long last_tick; 124 struct dim *src;
98 unsigned char *buf; 125 unsigned char *buf;
126 bool dither;
99 int len; 127 int len;
100 void *args; 128 void *args;
129 struct img_part* (*store_part)(void *);
130 void (*output_row)(uint32_t,void*,struct scaler_context*);
131 bool (*h_scaler)(void*,struct scaler_context*, bool);
101}; 132};
102 133
103/* Set up rounding and scale factors for horizontal area scaler */ 134/* Set up rounding and scale factors for horizontal area scaler */
104static void scale_h_area_setup(struct bitmap *bm, struct dim *src, 135static inline void scale_h_area_setup(struct scaler_context *ctx)
105 struct scaler_context *ctx)
106{ 136{
107 (void) bm;
108/* sum is output value * src->width */ 137/* sum is output value * src->width */
109 ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1; 138 SDEBUGF("scale_h_area_setup\n");
110 ctx->round = (src->width + 1) >> 1; 139 ctx->divisor = ctx->src->width;
111} 140}
112 141
113/* horizontal area average scaler */ 142/* horizontal area average scaler */
114static bool scale_h_area(struct bitmap *bm, struct dim *src, 143static bool scale_h_area(void *out_line_ptr,
115 struct uint32_rgb *out_line,
116 struct scaler_context *ctx, bool accum) 144 struct scaler_context *ctx, bool accum)
117{ 145{
118 SDEBUGF("scale_h_area\n"); 146 SDEBUGF("scale_h_area\n");
119 unsigned int ix, ox, oxe, mul; 147 unsigned int ix, ox, oxe, mul;
120 struct uint32_rgb rgbvalacc = { 0, 0, 0 }, 148#ifdef HAVE_LCD_COLOR
121 rgbvaltmp = { 0, 0, 0 }; 149 struct uint32_rgb rgbvalacc = { 0, 0, 0 },
150 rgbvaltmp = { 0, 0, 0 },
151 *out_line = (struct uint32_rgb *)out_line_ptr;
152#else
153 uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr;
154#endif
122 struct img_part *part; 155 struct img_part *part;
123 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 156 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
124 ox = 0; 157 ox = 0;
125 oxe = 0; 158 oxe = 0;
126 mul = 0; 159 mul = 0;
127 for (ix = 0; ix < (unsigned int)src->width; ix++) 160 /* give other tasks a chance to run */
161 yield();
162 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++)
128 { 163 {
129 oxe += bm->width; 164 oxe += ctx->bm->width;
130 /* end of current area has been reached */ 165 /* end of current area has been reached */
131 if (oxe >= (unsigned int)src->width) 166 /* fill buffer if needed */
167 FILL_BUF(part,ctx->store_part,ctx->args);
168#ifdef HAVE_LCD_COLOR
169 if (oxe >= (unsigned int)ctx->src->width)
132 { 170 {
133 /* yield if we haven't since last tick */
134 if (ctx->last_tick != current_tick)
135 {
136 yield();
137 ctx->last_tick = current_tick;
138 }
139 /* "reset" error, which now represents partial coverage of next 171 /* "reset" error, which now represents partial coverage of next
140 pixel by the next area 172 pixel by the next area
141 */ 173 */
142 oxe -= src->width; 174 oxe -= ctx->src->width;
175
143 /* add saved partial pixel from start of area */ 176 /* add saved partial pixel from start of area */
144 rgbvalacc.r = rgbvalacc.r * bm->width + rgbvaltmp.r * mul; 177 rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul;
145 rgbvalacc.g = rgbvalacc.g * bm->width + rgbvaltmp.g * mul; 178 rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul;
146 rgbvalacc.b = rgbvalacc.b * bm->width + rgbvaltmp.b * mul; 179 rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul;
147 /* fill buffer if needed */ 180
148 FILL_BUF(part,ctx->store_part,ctx->args);
149 /* get new pixel , then add its partial coverage to this area */ 181 /* get new pixel , then add its partial coverage to this area */
150 rgbvaltmp.r = part->buf->red; 182 rgbvaltmp.r = part->buf->red;
151 rgbvaltmp.g = part->buf->green; 183 rgbvaltmp.g = part->buf->green;
152 rgbvaltmp.b = part->buf->blue; 184 rgbvaltmp.b = part->buf->blue;
153 part->buf++; 185 mul = ctx->bm->width - oxe;
154 part->len--;
155 mul = bm->width - oxe;
156 rgbvalacc.r += rgbvaltmp.r * mul; 186 rgbvalacc.r += rgbvaltmp.r * mul;
157 rgbvalacc.g += rgbvaltmp.g * mul; 187 rgbvalacc.g += rgbvaltmp.g * mul;
158 rgbvalacc.b += rgbvaltmp.b * mul; 188 rgbvalacc.b += rgbvaltmp.b * mul;
159 /* round, divide, and either store or accumulate to output row */ 189 /* store or accumulate to output row */
160 out_line[ox].r = (accum ? out_line[ox].r : 0) + 190 if (accum)
161 ((rgbvalacc.r + ctx->round) * 191 {
162 (uint64_t)ctx->divmul >> 32); 192 rgbvalacc.r += out_line[ox].r;
163 out_line[ox].g = (accum ? out_line[ox].g : 0) + 193 rgbvalacc.g += out_line[ox].g;
164 ((rgbvalacc.g + ctx->round) * 194 rgbvalacc.b += out_line[ox].b;
165 (uint64_t)ctx->divmul >> 32); 195 }
166 out_line[ox].b = (accum ? out_line[ox].b : 0) + 196 out_line[ox].r = rgbvalacc.r;
167 ((rgbvalacc.b + ctx->round) * 197 out_line[ox].g = rgbvalacc.g;
168 (uint64_t)ctx->divmul >> 32); 198 out_line[ox].b = rgbvalacc.b;
169 /* reset accumulator */ 199 /* reset accumulator */
170 rgbvalacc.r = 0; 200 rgbvalacc.r = 0;
171 rgbvalacc.g = 0; 201 rgbvalacc.g = 0;
172 rgbvalacc.b = 0; 202 rgbvalacc.b = 0;
173 mul = bm->width - mul; 203 mul = ctx->bm->width - mul;
174 ox += 1; 204 ox += 1;
175 /* inside an area */ 205 /* inside an area */
176 } else { 206 } else {
177 /* fill buffer if needed */
178 FILL_BUF(part,ctx->store_part,ctx->args);
179 /* add pixel value to accumulator */ 207 /* add pixel value to accumulator */
180 rgbvalacc.r += part->buf->red; 208 rgbvalacc.r += part->buf->red;
181 rgbvalacc.g += part->buf->green; 209 rgbvalacc.g += part->buf->green;
182 rgbvalacc.b += part->buf->blue; 210 rgbvalacc.b += part->buf->blue;
183 part->buf++;
184 part->len--;
185 } 211 }
212#else
213 if (oxe >= (unsigned int)ctx->src->width)
214 {
215 /* "reset" error, which now represents partial coverage of next
216 pixel by the next area
217 */
218 oxe -= ctx->src->width;
219
220 /* add saved partial pixel from start of area */
221 acc = acc * ctx->bm->width + tmp * mul;
222
223 /* get new pixel , then add its partial coverage to this area */
224 tmp = *(part->buf);
225 mul = ctx->bm->width - oxe;
226 acc += tmp * mul;
227 /* round, divide, and either store or accumulate to output row */
228 if (accum)
229 {
230 acc += out_line[ox];
231 }
232 out_line[ox] = acc;
233 /* reset accumulator */
234 acc = 0;
235 mul = ctx->bm->width - mul;
236 ox += 1;
237 /* inside an area */
238 } else {
239 /* add pixel value to accumulator */
240 acc += *(part->buf);
241 }
242#endif
243 part->buf++;
244 part->len--;
186 } 245 }
187 return true; 246 return true;
188} 247}
189 248
190/* vertical area average scaler */ 249/* vertical area average scaler */
191static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, 250static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx)
192 struct rowset *rset,
193 bool (*h_scaler)(struct bitmap*, struct dim*,
194 struct uint32_rgb*,
195 struct scaler_context*, bool),
196 struct scaler_context *ctx)
197{ 251{
198 uint32_t mul, divmul, x, oy, iy, oye, round; 252 uint32_t mul, x, oy, iy, oye;
199 int delta = 127, r, g, b;
200 fb_data *row, *pix;
201 253
202 /* Set up rounding and scale factors */ 254 /* Set up rounding and scale factors */
203 divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1; 255 ctx->divisor *= ctx->src->height;
204 round = (src->height + 1) >> 1; 256 ctx->round = ctx->divisor >> 1;
257 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
205 mul = 0; 258 mul = 0;
206 oy = 0; 259 oy = rset->rowstart;
207 oye = 0; 260 oye = 0;
208 struct uint32_rgb *rowacc = (struct uint32_rgb *)(ctx->buf), 261#ifdef HAVE_LCD_COLOR
209 *rowtmp = rowacc + bm->width; 262 uint32_t *rowacc = (uint32_t *) ctx->buf,
210 263 *rowtmp = rowacc + 3 * ctx->bm->width;
264 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb));
265#else
266 uint32_t *rowacc = (uint32_t *) ctx->buf,
267 *rowtmp = rowacc + ctx->bm->width;
268 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t));
269#endif
211 SDEBUGF("scale_v_area\n"); 270 SDEBUGF("scale_v_area\n");
212 /* zero the accumulator and temp rows */ 271 /* zero the accumulator and temp rows */
213 memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb)); 272 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++)
214 row = (fb_data *)(bm->data) + bm->width * rset->rowstart;
215 for (iy = 0; iy < (unsigned int)src->height; iy++)
216 { 273 {
217 oye += bm->height; 274 oye += ctx->bm->height;
218 /* end of current area has been reached */ 275 /* end of current area has been reached */
219 if (oye >= (unsigned int)src->height) 276 if (oye >= (unsigned int)ctx->src->height)
220 { 277 {
221 /* "reset" error, which now represents partial coverage of the next 278 /* "reset" error, which now represents partial coverage of the next
222 row by the next area 279 row by the next area
223 */ 280 */
224 oye -= src->height; 281 oye -= ctx->src->height;
225 /* add stored partial row to accumulator */ 282 /* add stored partial row to accumulator */
226 for (x = 0; x < 3 *(unsigned int)bm->width; x++) 283#ifdef HAVE_LCD_COLOR
227 ((uint32_t*)rowacc)[x] = ((uint32_t*)rowacc)[x] * 284 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
228 bm->height + mul * 285#else
229 ((uint32_t*)rowtmp)[x]; 286 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
287#endif
288 rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x];
230 /* store new scaled row in temp row */ 289 /* store new scaled row in temp row */
231 if(!h_scaler(bm, src, rowtmp, ctx, false)) 290 if(!ctx->h_scaler(rowtmp, ctx, false))
232 return false; 291 return false;
233 /* add partial coverage by new row to this area, then round and 292 /* add partial coverage by new row to this area, then round and
234 scale to final value 293 scale to final value
235 */ 294 */
236 mul = bm->height - oye; 295 mul = ctx->bm->height - oye;
237 for (x = 0; x < 3 *(unsigned int)bm->width; x++) 296#ifdef HAVE_LCD_COLOR
238 { 297 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
239 ((uint32_t*)rowacc)[x] += mul * ((uint32_t*)rowtmp)[x]; 298#else
240 ((uint32_t*)rowacc)[x] = (round + 299 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
241 ((uint32_t*)rowacc)[x]) * 300#endif
242 (uint64_t)divmul >> 32; 301 rowacc[x] += mul * rowtmp[x];
243 } 302 ctx->output_row(oy, (void*)rowacc, ctx);
244 /* convert to RGB565 in output bitmap */
245 pix = row;
246 for (x = 0; x < (unsigned int)bm->width; x++)
247 {
248 if (dither)
249 delta = dither_mat(x & 0xf, oy & 0xf);
250 r = PACKRB(rowacc[x].r,delta);
251 g = PACKG(rowacc[x].g,delta);
252 b = PACKRB(rowacc[x].b,delta);
253 *pix++ = LCD_RGBPACK_LCD(r, g, b);
254 }
255 /* clear accumulator row, store partial coverage for next row */ 303 /* clear accumulator row, store partial coverage for next row */
256 memset((void *)rowacc, 0, bm->width * sizeof(struct uint32_rgb)); 304#ifdef HAVE_LCD_COLOR
305 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3);
306#else
307 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t));
308#endif
257 mul = oye; 309 mul = oye;
258 row += bm->width * rset->rowstep; 310 oy += rset->rowstep;
259 oy += 1;
260 /* inside an area */ 311 /* inside an area */
261 } else { 312 } else {
262 /* accumulate new scaled row to rowacc */ 313 /* accumulate new scaled row to rowacc */
263 if (!h_scaler(bm, src, rowacc, ctx, true)) 314 if (!ctx->h_scaler(rowacc, ctx, true))
264 return false; 315 return false;
265 } 316 }
266 } 317 }
@@ -272,53 +323,52 @@ static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src,
272 is bm->width - 1, so that the first and last pixels in the row align 323 is bm->width - 1, so that the first and last pixels in the row align
273 exactly between input and output 324 exactly between input and output
274*/ 325*/
275static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, 326static inline void scale_h_linear_setup(struct scaler_context *ctx)
276 struct scaler_context *ctx)
277{ 327{
278 (void) src; 328 ctx->divisor = ctx->bm->width - 1;
279 ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1;
280 ctx->round = bm->width >> 1;
281} 329}
282 330
283/* horizontal linear scaler */ 331/* horizontal linear scaler */
284static bool scale_h_linear(struct bitmap *bm, struct dim *src, 332static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx,
285 struct uint32_rgb *out_line, 333 bool accum)
286 struct scaler_context *ctx, bool accum)
287{ 334{
288 unsigned int ix, ox, ixe; 335 unsigned int ix, ox, ixe;
289 /* type x = x is an ugly hack for hiding an unitialized data warning. The 336 /* type x = x is an ugly hack for hiding an unitialized data warning. The
290 values are conditionally initialized before use, but other values are 337 values are conditionally initialized before use, but other values are
291 set such that this will occur before these are used. 338 set such that this will occur before these are used.
292 */ 339 */
293 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc; 340#ifdef HAVE_LCD_COLOR
341 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc,
342 *out_line = (struct uint32_rgb*)out_line_ptr;
343#else
344 uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr;
345#endif
294 struct img_part *part; 346 struct img_part *part;
295 SDEBUGF("scale_h_linear\n"); 347 SDEBUGF("scale_h_linear\n");
296 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 348 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
297 ix = 0; 349 ix = 0;
298 /* The error is set so that values are initialized on the first pass. */ 350 /* The error is set so that values are initialized on the first pass. */
299 ixe = bm->width - 1; 351 ixe = ctx->bm->width - 1;
300 for (ox = 0; ox < (uint32_t)bm->width; ox++) { 352 /* give other tasks a chance to run */
301 if (ixe >= ((uint32_t)bm->width - 1)) 353 yield();
354 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++)
355 {
356#ifdef HAVE_LCD_COLOR
357 if (ixe >= ((uint32_t)ctx->bm->width - 1))
302 { 358 {
303 /* yield once each tick */ 359 /* Store the new "current" pixel value in rgbval, and the color
304 if (ctx->last_tick != current_tick)
305 {
306 yield();
307 ctx->last_tick = current_tick;
308 }
309 /* Store the new "current" pixel value in rgbval, and the color
310 step value in rgbinc. 360 step value in rgbinc.
311 */ 361 */
312 ixe -= (bm->width - 1); 362 ixe -= (ctx->bm->width - 1);
313 rgbinc.r = -(part->buf->red); 363 rgbinc.r = -(part->buf->red);
314 rgbinc.g = -(part->buf->green); 364 rgbinc.g = -(part->buf->green);
315 rgbinc.b = -(part->buf->blue); 365 rgbinc.b = -(part->buf->blue);
316 rgbval.r = (part->buf->red) * (bm->width - 1); 366 rgbval.r = (part->buf->red) * (ctx->bm->width - 1);
317 rgbval.g = (part->buf->green) * (bm->width - 1); 367 rgbval.g = (part->buf->green) * (ctx->bm->width - 1);
318 rgbval.b = (part->buf->blue) * (bm->width - 1); 368 rgbval.b = (part->buf->blue) * (ctx->bm->width - 1);
319 ix += 1; 369 ix += 1;
320 /* If this wasn't the last pixel, add the next one to rgbinc. */ 370 /* If this wasn't the last pixel, add the next one to rgbinc. */
321 if (ix < (uint32_t)src->width) { 371 if (ix < (uint32_t)ctx->src->width) {
322 part->buf++; 372 part->buf++;
323 part->len--; 373 part->len--;
324 /* Fetch new pixels if needed */ 374 /* Fetch new pixels if needed */
@@ -334,448 +384,314 @@ static bool scale_h_linear(struct bitmap *bm, struct dim *src,
334 rgbval.b += rgbinc.b * ixe; 384 rgbval.b += rgbinc.b * ixe;
335 } 385 }
336 /* Now multiple the color increment to its proper value */ 386 /* Now multiple the color increment to its proper value */
337 rgbinc.r *= src->width - 1; 387 rgbinc.r *= ctx->src->width - 1;
338 rgbinc.g *= src->width - 1; 388 rgbinc.g *= ctx->src->width - 1;
339 rgbinc.b *= src->width - 1; 389 rgbinc.b *= ctx->src->width - 1;
390 } else {
391 rgbval.r += rgbinc.r;
392 rgbval.g += rgbinc.g;
393 rgbval.b += rgbinc.b;
340 } 394 }
341 /* round and scale values, and accumulate or store to output */ 395 /* round and scale values, and accumulate or store to output */
342 out_line[ox].r = (accum ? out_line[ox].r : 0) + 396 if (accum)
343 ((rgbval.r + ctx->round) * 397 {
344 (uint64_t)ctx->divmul >> 32); 398 out_line[ox].r += rgbval.r;
345 out_line[ox].g = (accum ? out_line[ox].g : 0) + 399 out_line[ox].g += rgbval.g;
346 ((rgbval.g + ctx->round) * 400 out_line[ox].b += rgbval.b;
347 (uint64_t)ctx->divmul >> 32); 401 } else {
348 out_line[ox].b = (accum ? out_line[ox].b : 0) + 402 out_line[ox].r = rgbval.r;
349 ((rgbval.b + ctx->round) * 403 out_line[ox].g = rgbval.g;
350 (uint64_t)ctx->divmul >> 32); 404 out_line[ox].b = rgbval.b;
351 rgbval.r += rgbinc.r; 405 }
352 rgbval.g += rgbinc.g; 406#else
353 rgbval.b += rgbinc.b; 407 if (ixe >= ((uint32_t)ctx->bm->width - 1))
354 ixe += src->width - 1; 408 {
409 /* Store the new "current" pixel value in rgbval, and the color
410 step value in rgbinc.
411 */
412 ixe -= (ctx->bm->width - 1);
413 val = *(part->buf);
414 inc = -val;
415 val *= (ctx->bm->width - 1);
416 ix += 1;
417 /* If this wasn't the last pixel, add the next one to rgbinc. */
418 if (ix < (uint32_t)ctx->src->width) {
419 part->buf++;
420 part->len--;
421 /* Fetch new pixels if needed */
422 FILL_BUF(part,ctx->store_part,ctx->args);
423 inc += *(part->buf);
424 /* Add a partial step to rgbval, in this pixel isn't precisely
425 aligned with the new source pixel
426 */
427 val += inc * ixe;
428 }
429 /* Now multiply the color increment to its proper value */
430 inc *= ctx->src->width - 1;
431 } else
432 val += inc;
433 /* round and scale values, and accumulate or store to output */
434 if (accum)
435 {
436 out_line[ox] += val;
437 } else {
438 out_line[ox] = val;
439 }
440#endif
441 ixe += ctx->src->width - 1;
355 } 442 }
356 return true; 443 return true;
357} 444}
358 445
359/* vertical linear scaler */ 446/* vertical linear scaler */
360static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, 447static inline bool scale_v_linear(struct rowset *rset,
361 struct rowset *rset, 448 struct scaler_context *ctx)
362 bool (*h_scaler)(struct bitmap*, struct dim*,
363 struct uint32_rgb*,
364 struct scaler_context*, bool),
365 struct scaler_context *ctx)
366{ 449{
367 uint32_t mul, divmul, x, oy, iy, iye, round; 450 uint32_t mul, x, iy, iye;
368 int delta = 127; 451 int32_t oy;
369 struct uint32_rgb p;
370 fb_data *row, *pix;
371 /* Set up scale and rounding factors, the divisor is bm->height - 1 */ 452 /* Set up scale and rounding factors, the divisor is bm->height - 1 */
372 divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1; 453 ctx->divisor *= (ctx->bm->height - 1);
373 round = bm->height >> 1; 454 ctx->round = ctx->divisor >> 1;
374 mul = 0; 455 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
375 iy = 0;
376 iye = bm->height - 1;
377 /* Set up our two temp buffers. The names are generic because they'll be 456 /* Set up our two temp buffers. The names are generic because they'll be
378 swapped each time a new input row is read 457 swapped each time a new input row is read
379 */ 458 */
380 struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), 459#ifdef HAVE_LCD_COLOR
381 *crow2 = crow1 + bm->width, 460 uint32_t *rowinc = (uint32_t *)(ctx->buf),
382 *t; 461 *rowval = rowinc + 3 * ctx->bm->width,
462 *rowtmp = rowval + 3 * ctx->bm->width;
463#else
464 uint32_t *rowinc = (uint32_t *)(ctx->buf),
465 *rowval = rowinc + ctx->bm->width,
466 *rowtmp = rowval + ctx->bm->width;
467#endif
383 468
384 SDEBUGF("scale_v_linear\n"); 469 SDEBUGF("scale_v_linear\n");
385 row = (fb_data *)(bm->data) + bm->width * rset->rowstart; 470 mul = 0;
386 /* get first scaled row in crow2 */ 471 iy = 0;
387 if(!h_scaler(bm, src, crow2, ctx, false)) 472 iye = ctx->bm->height - 1;
473 /* get first scaled row in rowtmp */
474 if(!ctx->h_scaler((void*)rowtmp, ctx, false))
388 return false; 475 return false;
389 for (oy = 0; oy < (uint32_t)bm->height; oy++) 476 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep)
390 { 477 {
391 if (iye >= (uint32_t)bm->height - 1) 478 if (iye >= (uint32_t)ctx->bm->height - 1)
392 { 479 {
393 /* swap temp rows, then read another row into crow2 */ 480 iye -= ctx->bm->height - 1;
394 t = crow2;
395 crow2 = crow1;
396 crow1 = t;
397 iye -= bm->height - 1;
398 iy += 1; 481 iy += 1;
399 if (iy < (uint32_t)src->height) 482#ifdef HAVE_LCD_COLOR
483 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
484#else
485 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
486#endif
400 { 487 {
401 if (!h_scaler(bm, src, crow2, ctx, false)) 488 rowinc[x] = -rowtmp[x];
489 rowval[x] = rowtmp[x] * (ctx->bm->height - 1);
490 }
491 if (iy < (uint32_t)ctx->src->height)
492 {
493 if (!ctx->h_scaler((void*)rowtmp, ctx, false))
402 return false; 494 return false;
495#ifdef HAVE_LCD_COLOR
496 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
497#else
498 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
499#endif
500 {
501 rowinc[x] += rowtmp[x];
502 rowval[x] += rowinc[x] * iye;
503 rowinc[x] *= ctx->src->height - 1;
504 }
403 } 505 }
404 } 506 } else
405 pix = row; 507#ifdef HAVE_LCD_COLOR
406 for (x = 0; x < (uint32_t)bm->width; x++) 508 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
407 { 509#else
408 /* iye and bm-height - 1 - iye represent the contribution of each 510 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
409 row to the output. Calculate their weighted sum, then round and 511#endif
410 scale it. 512 rowval[x] += rowinc[x];
411 */ 513 ctx->output_row(oy, (void*)rowval, ctx);
412 p.r = (crow1[x].r * (bm->height - 1 - iye) + 514 iye += ctx->src->height - 1;
413 crow2[x].r * iye + round) * (uint64_t)divmul >> 32;
414 p.g = (crow1[x].g * (bm->height - 1 - iye) +
415 crow2[x].g * iye + round) * (uint64_t)divmul >> 32;
416 p.b = (crow1[x].b * (bm->height - 1 - iye) +
417 crow2[x].b * iye + round) * (uint64_t)divmul >> 32;
418 /* dither and pack pixels to output */
419 if (dither)
420 delta = dither_mat(x & 0xf, oy & 0xf);
421 p.r = PACKRB(p.r,delta);
422 p.g = PACKG(p.g,delta);
423 p.b = PACKRB(p.b,delta);
424 *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b);
425 }
426 row += bm->width * rset->rowstep;
427 iye += src->height - 1;
428 } 515 }
429 return true; 516 return true;
430} 517}
431#endif /* HAVE_UPSCALER */ 518#endif /* HAVE_UPSCALER */
432#endif /* HAVE_LCD_COLOR */
433 519
434/* docs for this are still TODO, but it's Bresenham's again, used to skip or 520void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx)
435 repeat input pixels, and with the *ls values being used for "long steps"
436 that skip all the way, or nearly all the way, to the next transition of
437 the associated value.
438*/
439#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8)
440/* nearest-neighbor up/down/non-scaler */
441static inline bool scale_nearest(struct bitmap *bm,
442 struct dim *src,
443 struct rowset *rset,
444 bool remote, bool dither,
445 struct img_part* (*store_part)(void *args),
446 bool (*skip_lines)(void *args, unsigned int),
447 void *args)
448{ 521{
449 const int sw = src->width; 522 int col;
450 const int sh = src->height; 523 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
451 const int dw = bm->width; 524 uint8_t dy = DITHERY(row);
452 const int dh = bm->height; 525#ifdef HAVE_LCD_COLOR
453 unsigned char *bitmap = bm->data; 526 struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
454 const int rowstep = rset->rowstep;
455 const int rowstart = rset->rowstart;
456 const int rowstop = rset->rowstop;
457 const int fb_width = get_fb_width(bm, false);
458 long last_tick = current_tick;
459 /* yet/oyt will always be initialized before use, since they are set in the
460 inside loop, and not used elsewhere until the end of the outside loop.
461 */
462 int ix, ox, lx, xe, iy, oy, ly, ye, yet = yet, oyt = oyt;
463 int xelim, ixls, xels, yelim, iyls, yels, p;
464 struct img_part *cur_part;
465#ifndef HAVE_LCD_COLOR
466 fb_data *dest = dest, *dest_t;
467#endif
468#ifdef HAVE_REMOTE_LCD
469 fb_remote_data *rdest = rdest, *rdest_t;
470#endif
471
472 SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw,
473 dh, remote);
474 ly = 0;
475 iy = 0;
476 ye = 0;
477 xelim = sw == dw - 1 ? dw : dw - 1;
478 ixls = xelim ? sw / xelim : 1;
479 xels = sw - ixls * (xelim ? xelim : 1);
480 yelim = sh == dh - 1 ? dh : dh - 1;
481 iyls = yelim ? sh / yelim : 1;
482 yels = iyls * (yelim ? yelim : 1);
483 int delta = 127;
484#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \
485 (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING)
486 uint8_t buf[4];
487 int data, oxt;
488#endif
489#if LCD_PIXELFORMAT == VERTICAL_PACKING || \
490 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \
491 (defined(HAVE_REMOTE_LCD) && \
492 (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \
493 LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING))
494 int bright, shift;
495#endif
496 for (oy = rowstart; oy != rowstop;) {
497 SDEBUGF("oy=%d iy=%d\n", oy, iy);
498 if (last_tick != current_tick)
499 {
500 yield();
501 last_tick = current_tick;
502 }
503 if (iy > ly && !skip_lines(args, iy - ly - 1))
504 return false;
505 ly = iy;
506
507 cur_part = store_part(args);
508 if (cur_part == NULL)
509 return false;
510
511 lx = 0;
512 ix = 0;
513 xe = 0;
514#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
515 if(!remote)
516#else 527#else
517 (void)remote; 528 uint32_t *qp = (uint32_t*)row_in;
518#endif
519#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
520 dest = (fb_data *)bitmap + fb_width * oy;
521#elif LCD_PIXELFORMAT == VERTICAL_PACKING
522 dest = (fb_data *)bitmap + fb_width * (oy >> 2);
523#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
524 dest = (fb_data *)bitmap + fb_width * (oy >> 3);
525#endif
526#ifdef HAVE_REMOTE_LCD
527#ifndef HAVE_LCD_COLOR
528 else
529#endif
530 rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3);
531#endif
532 for (ox = 0; ox < dw; ox++) {
533 while (cur_part->len <= ix - lx)
534 {
535 lx += cur_part->len;
536 cur_part = store_part(args);
537 if (cur_part == NULL)
538 return false;
539 }
540 cur_part->len -= ix - lx;
541 cur_part->buf += ix - lx;
542 lx = ix;
543#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
544 if(!remote)
545 {
546#endif 529#endif
530 SDEBUGF("output_row: y: %d in: %p\n",row, row_in);
531#if LCD_DEPTH == 2
547#if LCD_PIXELFORMAT == HORIZONTAL_PACKING 532#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
548 /* greyscale iPods */ 533 /* greyscale iPods */
549 buf[ox & 3] = brightness(*(cur_part->buf)); 534 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
550 if ((ox & 3) == 3 || ox == dw - 1) 535 int shift = 6;
551 { 536 int delta = 127;
552 dest_t = dest++; 537 unsigned bright;
553 oyt = oy; 538 unsigned data = 0;
554 yet = ye; 539
555 int xo = ox & ~3; 540 for (col = 0; col < ctx->bm->width; col++) {
556 while(yet < dh) 541 if (ctx->dither)
557 { 542 delta = DITHERXDY(col,dy);
543 bright = ((*qp++) + ctx->round) *
544 (uint64_t)ctx->divisor >> 32;
545 bright = (3 * bright + (bright >> 6) + delta) >> 8;
546 data |= (~bright & 3) << shift;
547 shift -= 2;
548 if (shift < 0) {
549 *dest++ = data;
558 data = 0; 550 data = 0;
559 for (oxt = 0; oxt < (ox & 3) + 1; oxt++) 551 shift = 6;
560 {
561 if (dither)
562 delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf);
563 p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8;
564 data |= (~p & 3) << ((3 - oxt) << 1);
565 }
566 *dest_t = data;
567 dest_t += rowstep * fb_width;
568 yet += sh;
569 oyt += rowstep;
570 } 552 }
571 } 553 }
554 if (shift < 6)
555 *dest++ = data;
572#elif LCD_PIXELFORMAT == VERTICAL_PACKING 556#elif LCD_PIXELFORMAT == VERTICAL_PACKING
573 /* iriver H1x0 */ 557 /* iriver H1x0 */
574 bright = brightness(*(cur_part->buf)); 558 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
575 dest_t = dest++; 559 (row >> 2);
576 oyt = oy; 560 int shift = 2 * (row & 3);
577 yet = ye; 561 int delta = 127;
578 while(yet < dh) 562 unsigned bright;
579 {
580 shift = (oyt & 3) << 1;
581 if (dither)
582 delta = dither_mat(oyt & 0xf, ox & 0xf);
583 563
584 p = (3 * bright + (bright >> 6) + delta) >> 8; 564 for (col = 0; col < ctx->bm->width; col++) {
585 *dest_t |= (~p & 3) << shift; 565 if (ctx->dither)
586 if ((rowstep > 0 && shift == 6) || shift == 0) 566 delta = DITHERXDY(col,dy);
587 dest_t += rowstep * fb_width; 567 bright = ((*qp++) + ctx->round) *
588 yet += sh; 568 (uint64_t)ctx->divisor >> 32;
589 oyt += rowstep; 569 bright = (3 * bright + (bright >> 6) + delta) >> 8;
570 *dest++ |= (~bright & 3) << shift;
590 } 571 }
591#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED 572#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
592 bright = brightness(*(cur_part->buf)); 573 /* iAudio M3 */
593 dest_t = dest++; 574 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
594 oyt = oy; 575 (row >> 3);
595 yet = ye; 576 int shift = row & 7;
596 while(yet < dh) 577 int delta = 127;
597 { 578 unsigned bright;
598 shift = oyt & 7;
599 if (dither)
600 delta = dither_mat(oyt & 0xf, ox & 0xf);
601 579
602 p = (3 * bright + (bright >> 6) + delta) >> 8; 580 for (col = 0; col < ctx->bm->width; col++) {
603 *dest_t |= vi_pat(p) << shift; 581 if (ctx->dither)
604 if ((rowstep > 0 && shift == 7) || shift == 0) 582 delta = DITHERXDY(col,dy);
605 dest_t += rowstep * fb_width; 583 bright = ((*qp++) + ctx->round) *
606 yet += sh; 584 (uint64_t)ctx->divisor >> 32;
607 oyt += rowstep; 585 bright = (3 * bright + (bright >> 6) + delta) >> 8;
586 *dest++ |= vi_pattern[bright] << shift;
608 } 587 }
609#endif /* LCD_PIXELFORMAT */ 588#endif /* LCD_PIXELFORMAT */
610#ifdef HAVE_REMOTE_LCD 589#elif LCD_DEPTH == 16
611#ifndef HAVE_LCD_COLOR 590 /* iriver h300, colour iPods, X5 */
612 } else 591 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
613#endif 592 int delta = 127;
614 { 593 unsigned r, g, b;
615#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED 594 struct uint32_rgb q0;
616 bright = brightness(*(cur_part->buf));
617 rdest_t = rdest++;
618 oyt = oy;
619 yet = ye;
620 while(yet < dh)
621 {
622 shift = oyt & 7;
623 if (dither)
624 delta = dither_mat(oyt & 0xf, ox & 0xf);
625 595
626 p = (3 * bright + (bright >> 6) + delta) >> 8; 596 for (col = 0; col < ctx->bm->width; col++) {
627 *rdest_t |= vi_pat(p) << shift; 597 if (ctx->dither)
628 if ((rowstep > 0 && shift == 7) || shift == 0) 598 delta = DITHERXDY(col,dy);
629 rdest_t += rowstep * fb_width; 599 q0 = *qp++;
630 yet += sh; 600 r = (q0.r + ctx->round) * (uint64_t)ctx->divisor >> 32;
631 oyt += rowstep; 601 g = (q0.g + ctx->round) * (uint64_t)ctx->divisor >> 32;
632 } 602 b = (q0.b + ctx->round) * (uint64_t)ctx->divisor >> 32;
633#else 603 r = (31 * r + (r >> 3) + delta) >> 8;
634 bright = brightness(*(cur_part->buf)); 604 g = (63 * g + (g >> 2) + delta) >> 8;
635 rdest_t = rdest++; 605 b = (31 * b + (b >> 3) + delta) >> 8;
636 oyt = oy; 606 *dest++ = LCD_RGBPACK_LCD(r, g, b);
637 yet = ye;
638 while(yet < dh)
639 {
640 shift = oyt & 7;
641 if (dither)
642 delta = dither_mat(oyt & 0xf, ox & 0xf);
643 p = (bright + delta) >> 8;
644 *rdest_t |= (~p & 1) << shift;
645 if ((rowstep > 0 && shift == 7) || shift == 0)
646 rdest_t += rowstep * fb_width;
647 yet += sh;
648 oyt += rowstep;
649 } 607 }
650#endif 608#endif /* LCD_DEPTH */
651 }
652#endif
653 xe += xels;
654 ix += ixls;
655 while (xe > xelim)
656 {
657 xe -= xelim;
658 ix += 1;
659 }
660 }
661 oy = oyt;
662 ye = yet - yels;
663 iy += iyls;
664 while (ye > yelim)
665 {
666 ye -= yelim;
667 iy += 1;
668 }
669 }
670 return true;
671} 609}
672#endif
673 610
674int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, 611int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
675 struct rowset *rset, bool remote, 612 struct rowset *rset, unsigned char *buf, unsigned int len,
676#ifdef HAVE_LCD_COLOR
677 unsigned char *buf, unsigned int len,
678#endif
679 struct img_part* (*store_part)(void *args), 613 struct img_part* (*store_part)(void *args),
680 bool (*skip_lines)(void *args, unsigned int lines),
681 void *args) 614 void *args)
682{ 615{
683 616
684#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD) 617#ifdef HAVE_UPSCALER
685 (void)skip_lines; 618 const int sw = src->width;
619 const int sh = src->height;
620 const int dw = bm->width;
621 const int dh = bm->height;
686#endif 622#endif
623 int ret;
687#ifdef HAVE_LCD_COLOR 624#ifdef HAVE_LCD_COLOR
688#ifdef HAVE_REMOTE_LCD 625 unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
689 if (!remote) 626#else
690#endif 627 unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
691 {
692#ifdef HAVE_UPSCALER
693 const int sw = src->width;
694 const int sh = src->height;
695 const int dw = bm->width;
696 const int dh = bm->height;
697#endif 628#endif
698 int ret;
699 unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width;
700#if MAX_SC_STACK_ALLOC 629#if MAX_SC_STACK_ALLOC
701 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? 630 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
702 0 : needed]; 631 0 : needed];
703 if (len && buf)
704#endif 632#endif
705 len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, 633 len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len,
706 sizeof(uint32_t)); 634 sizeof(uint32_t));
707 if (needed > len) 635 if (needed > len)
708 { 636 {
709#if MAX_SC_STACK_ALLOC 637#if MAX_SC_STACK_ALLOC
710 if (needed > MAX_SC_STACK_ALLOC) 638 if (needed > MAX_SC_STACK_ALLOC)
711 { 639 {
712 DEBUGF("unable to allocate required buffer: %d needed, " 640 DEBUGF("unable to allocate required buffer: %d needed, "
713 "%d available, %d permitted from stack\n", 641 "%d available, %d permitted from stack\n",
714 needed, len, MAX_SC_STACK_ALLOC); 642 needed, len, MAX_SC_STACK_ALLOC);
715 return 0; 643 return 0;
716 } 644 }
717 if (sizeof(sc_buf) < needed) 645 if (sizeof(sc_buf) < needed)
718 { 646 {
719 DEBUGF("failed to allocate large enough buffer on stack: " 647 DEBUGF("failed to allocate large enough buffer on stack: "
720 "%d needed, only got %d", 648 "%d needed, only got %d",
721 needed, MAX_SC_STACK_ALLOC); 649 needed, MAX_SC_STACK_ALLOC);
722 return 0; 650 return 0;
723 } 651 }
724#else 652#else
725 DEBUGF("unable to allocate required buffer: %d needed, " 653 DEBUGF("unable to allocate required buffer: %d needed, "
726 "%d available\n", needed, len); 654 "%d available\n", needed, len);
727 return 0; 655 return 0;
728#endif 656#endif
729 } 657 }
730 658
731 bool (*h_scaler)(struct bitmap*, struct dim*, 659 struct scaler_context ctx;
732 struct uint32_rgb*, 660 cpu_boost(true);
733 struct scaler_context*, bool); 661 ctx.store_part = store_part;
734 struct scaler_context ctx; 662 ctx.args = args;
735 ctx.last_tick = current_tick;
736 cpu_boost(true);
737#ifdef HAVE_UPSCALER
738 if (sw > dw)
739 {
740#endif
741 h_scaler = scale_h_area;
742 scale_h_area_setup(bm, src, &ctx);
743#ifdef HAVE_UPSCALER
744 } else {
745 h_scaler = scale_h_linear;
746 scale_h_linear_setup(bm, src, &ctx);
747 }
748#endif
749 ctx.store_part = store_part;
750 ctx.args = args;
751#if MAX_SC_STACK_ALLOC 663#if MAX_SC_STACK_ALLOC
752 ctx.buf = needed > len ? sc_buf : buf; 664 ctx.buf = needed > len ? sc_buf : buf;
753#else 665#else
754 ctx.buf = buf; 666 ctx.buf = buf;
755#endif 667#endif
756 ctx.len = len; 668 ctx.len = len;
669 ctx.bm = bm;
670 ctx.src = src;
671 ctx.dither = dither;
672 ctx.output_row = output_row_native;
757#ifdef HAVE_UPSCALER 673#ifdef HAVE_UPSCALER
758 if (sh > dh) 674 if (sw > dw)
675 {
759#endif 676#endif
760 ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx); 677 ctx.h_scaler = scale_h_area;
678 scale_h_area_setup(&ctx);
761#ifdef HAVE_UPSCALER 679#ifdef HAVE_UPSCALER
762 else 680 } else {
763 ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx); 681 ctx.h_scaler = scale_h_linear;
682 scale_h_linear_setup(&ctx);
683 }
764#endif 684#endif
765 cpu_boost(false); 685#ifdef HAVE_UPSCALER
766 if (!ret) 686 if (sh > dh)
767 return 0;
768 }
769#ifdef HAVE_REMOTE_LCD
770 else
771#endif 687#endif
772#endif /* HAVE_LCD_COLOR */ 688 ret = scale_v_area(rset, &ctx);
773#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD) 689#ifdef HAVE_UPSCALER
774 { 690 else
775 if (!scale_nearest(bm, src, rset, remote, dither, store_part, 691 ret = scale_v_linear(rset, &ctx);
776 skip_lines, args)) 692#endif
777 return 0; 693 cpu_boost(false);
778 } 694 if (!ret)
779#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/ 695 return 0;
780 return get_totalsize(bm, remote); 696 return BM_SIZE(bm->width,bm->height,bm->format,0);
781} 697}