Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
Michael Sevakis | 441fca1 | 2008-12-10 21:10:34 +0000 | [diff] [blame] | 8 | * $Id$ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 9 | * |
| 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 Mahone | 2fbf097 | 2009-01-13 13:48:26 +0000 | [diff] [blame] | 34 | #include <system.h> |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 35 | #include <stdio.h> |
| 36 | #include <stdlib.h> |
| 37 | #include <string.h> |
Andrew Mahone | 524c540 | 2008-12-14 17:58:04 +0000 | [diff] [blame] | 38 | #include <general.h> |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 39 | #include "inttypes.h" |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 40 | #ifndef PLUGIN |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 41 | #include "debug.h" |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 42 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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" |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 56 | #include <bmp.h> |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 57 | #include "resize.h" |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 58 | #else |
| 59 | #undef DEBUGF |
| 60 | #define DEBUGF(...) |
| 61 | #endif |
| 62 | |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 63 | /* calculate the maximum dimensions which will preserve the aspect ration of |
| 64 | src while fitting in the constraints passed in dst, and store result in dst, |
| 65 | returning 0 if rounding and 1 if not rounding. |
| 66 | */ |
| 67 | int recalc_dimension(struct dim *dst, struct dim *src) |
| 68 | { |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 69 | /* This only looks backwards. The input image size is being pre-scaled by |
| 70 | * the inverse of the pixel aspect ratio, so that once the size it scaled |
| 71 | * to meet the output constraints, the scaled image will have appropriate |
| 72 | * proportions. |
| 73 | */ |
| 74 | int sw = src->width * LCD_PIXEL_ASPECT_HEIGHT; |
| 75 | int sh = src->height * LCD_PIXEL_ASPECT_WIDTH; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 76 | int tmp; |
| 77 | if (dst->width <= 0) |
| 78 | dst->width = LCD_WIDTH; |
| 79 | if (dst->height <= 0) |
| 80 | dst->height = LCD_HEIGHT; |
| 81 | #ifndef HAVE_UPSCALER |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 82 | if (dst->width > sw || dst->height > sh) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 83 | { |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 84 | dst->width = sw; |
| 85 | dst->height = sh; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 86 | } |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 87 | if (sw == dst->width && sh == dst->height) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 88 | return 1; |
| 89 | #endif |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 90 | tmp = (sw * dst->height + (sh >> 1)) / sh; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 91 | if (tmp > dst->width) |
Andrew Mahone | 738a564 | 2009-01-13 14:41:29 +0000 | [diff] [blame] | 92 | dst->height = (sh * dst->width + (sw >> 1)) / sw; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 93 | else |
| 94 | dst->width = tmp; |
| 95 | return src->width == dst->width && src->height == dst->height; |
| 96 | } |
| 97 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 98 | /* All of these scalers use variations of Bresenham's algorithm to convert from |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 99 | their input to output coordinates. The error value is shifted from the |
| 100 | "classic" version such that it is a useful input to the scaling calculation. |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 101 | */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 102 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 103 | #ifdef HAVE_LCD_COLOR |
| 104 | /* dither + pack on channel of RGB565, R an B share a packing macro */ |
| 105 | #define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) |
| 106 | #define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 107 | #endif |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 108 | |
| 109 | /* read new img_part unconditionally, return false on failure */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 110 | #define FILL_BUF_INIT(img_part, store_part, args) { \ |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 111 | img_part = store_part(args); \ |
| 112 | if (img_part == NULL) \ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 113 | return false; \ |
| 114 | } |
| 115 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 116 | /* read new img_part if current one is empty, return false on failure */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 117 | #define FILL_BUF(img_part, store_part, args) { \ |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 118 | if (img_part->len == 0) \ |
| 119 | img_part = store_part(args); \ |
| 120 | if (img_part == NULL) \ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 121 | return false; \ |
| 122 | } |
| 123 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 124 | /* Set up rounding and scale factors for horizontal area scaler */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 125 | static inline void scale_h_area_setup(struct scaler_context *ctx) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 126 | { |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 127 | /* sum is output value * src->width */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 128 | SDEBUGF("scale_h_area_setup\n"); |
| 129 | ctx->divisor = ctx->src->width; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | /* horizontal area average scaler */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 133 | static bool scale_h_area(void *out_line_ptr, |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 134 | struct scaler_context *ctx, bool accum) |
| 135 | { |
| 136 | SDEBUGF("scale_h_area\n"); |
| 137 | unsigned int ix, ox, oxe, mul; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 138 | #ifdef HAVE_LCD_COLOR |
| 139 | struct uint32_rgb rgbvalacc = { 0, 0, 0 }, |
| 140 | rgbvaltmp = { 0, 0, 0 }, |
| 141 | *out_line = (struct uint32_rgb *)out_line_ptr; |
| 142 | #else |
| 143 | uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr; |
| 144 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 145 | struct img_part *part; |
| 146 | FILL_BUF_INIT(part,ctx->store_part,ctx->args); |
| 147 | ox = 0; |
| 148 | oxe = 0; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 149 | mul = 0; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 150 | /* give other tasks a chance to run */ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 151 | yield(); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 152 | for (ix = 0; ix < (unsigned int)ctx->src->width; ix++) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 153 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 154 | oxe += ctx->bm->width; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 155 | /* end of current area has been reached */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 156 | /* fill buffer if needed */ |
| 157 | FILL_BUF(part,ctx->store_part,ctx->args); |
| 158 | #ifdef HAVE_LCD_COLOR |
| 159 | if (oxe >= (unsigned int)ctx->src->width) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 160 | { |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 161 | /* "reset" error, which now represents partial coverage of next |
| 162 | pixel by the next area |
| 163 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 164 | oxe -= ctx->src->width; |
| 165 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 166 | /* add saved partial pixel from start of area */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 167 | rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul; |
| 168 | rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul; |
| 169 | rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul; |
| 170 | |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 171 | /* get new pixel , then add its partial coverage to this area */ |
| 172 | rgbvaltmp.r = part->buf->red; |
| 173 | rgbvaltmp.g = part->buf->green; |
| 174 | rgbvaltmp.b = part->buf->blue; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 175 | mul = ctx->bm->width - oxe; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 176 | rgbvalacc.r += rgbvaltmp.r * mul; |
| 177 | rgbvalacc.g += rgbvaltmp.g * mul; |
| 178 | rgbvalacc.b += rgbvaltmp.b * mul; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 179 | /* store or accumulate to output row */ |
| 180 | if (accum) |
| 181 | { |
| 182 | rgbvalacc.r += out_line[ox].r; |
| 183 | rgbvalacc.g += out_line[ox].g; |
| 184 | rgbvalacc.b += out_line[ox].b; |
| 185 | } |
| 186 | out_line[ox].r = rgbvalacc.r; |
| 187 | out_line[ox].g = rgbvalacc.g; |
| 188 | out_line[ox].b = rgbvalacc.b; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 189 | /* reset accumulator */ |
| 190 | rgbvalacc.r = 0; |
| 191 | rgbvalacc.g = 0; |
| 192 | rgbvalacc.b = 0; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 193 | mul = ctx->bm->width - mul; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 194 | ox += 1; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 195 | /* inside an area */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 196 | } else { |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 197 | /* add pixel value to accumulator */ |
| 198 | rgbvalacc.r += part->buf->red; |
| 199 | rgbvalacc.g += part->buf->green; |
| 200 | rgbvalacc.b += part->buf->blue; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 201 | } |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 202 | #else |
| 203 | if (oxe >= (unsigned int)ctx->src->width) |
| 204 | { |
| 205 | /* "reset" error, which now represents partial coverage of next |
| 206 | pixel by the next area |
| 207 | */ |
| 208 | oxe -= ctx->src->width; |
| 209 | |
| 210 | /* add saved partial pixel from start of area */ |
| 211 | acc = acc * ctx->bm->width + tmp * mul; |
| 212 | |
| 213 | /* get new pixel , then add its partial coverage to this area */ |
| 214 | tmp = *(part->buf); |
| 215 | mul = ctx->bm->width - oxe; |
| 216 | acc += tmp * mul; |
| 217 | /* round, divide, and either store or accumulate to output row */ |
| 218 | if (accum) |
| 219 | { |
| 220 | acc += out_line[ox]; |
| 221 | } |
| 222 | out_line[ox] = acc; |
| 223 | /* reset accumulator */ |
| 224 | acc = 0; |
| 225 | mul = ctx->bm->width - mul; |
| 226 | ox += 1; |
| 227 | /* inside an area */ |
| 228 | } else { |
| 229 | /* add pixel value to accumulator */ |
| 230 | acc += *(part->buf); |
| 231 | } |
| 232 | #endif |
| 233 | part->buf++; |
| 234 | part->len--; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 235 | } |
| 236 | return true; |
| 237 | } |
| 238 | |
| 239 | /* vertical area average scaler */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 240 | static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 241 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 242 | uint32_t mul, x, oy, iy, oye; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 243 | |
| 244 | /* Set up rounding and scale factors */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 245 | ctx->divisor *= ctx->src->height; |
| 246 | ctx->round = ctx->divisor >> 1; |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 247 | ctx->divisor = (((ctx->divisor >> 1) + SC_NUM) / ctx->divisor) << SC_FIX; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 248 | mul = 0; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 249 | oy = rset->rowstart; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 250 | oye = 0; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 251 | #ifdef HAVE_LCD_COLOR |
| 252 | uint32_t *rowacc = (uint32_t *) ctx->buf, |
| 253 | *rowtmp = rowacc + 3 * ctx->bm->width; |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 254 | memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb)); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 255 | #else |
| 256 | uint32_t *rowacc = (uint32_t *) ctx->buf, |
| 257 | *rowtmp = rowacc + ctx->bm->width; |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 258 | memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t)); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 259 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 260 | SDEBUGF("scale_v_area\n"); |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 261 | /* zero the accumulator and temp rows */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 262 | for (iy = 0; iy < (unsigned int)ctx->src->height; iy++) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 263 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 264 | oye += ctx->bm->height; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 265 | /* end of current area has been reached */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 266 | if (oye >= (unsigned int)ctx->src->height) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 267 | { |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 268 | /* "reset" error, which now represents partial coverage of the next |
| 269 | row by the next area |
| 270 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 271 | oye -= ctx->src->height; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 272 | /* add stored partial row to accumulator */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 273 | #ifdef HAVE_LCD_COLOR |
| 274 | for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) |
| 275 | #else |
| 276 | for (x = 0; x < (unsigned int)ctx->bm->width; x++) |
| 277 | #endif |
| 278 | rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x]; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 279 | /* store new scaled row in temp row */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 280 | if(!ctx->h_scaler(rowtmp, ctx, false)) |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 281 | return false; |
| 282 | /* add partial coverage by new row to this area, then round and |
| 283 | scale to final value |
| 284 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 285 | mul = ctx->bm->height - oye; |
| 286 | #ifdef HAVE_LCD_COLOR |
| 287 | for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) |
| 288 | #else |
| 289 | for (x = 0; x < (unsigned int)ctx->bm->width; x++) |
| 290 | #endif |
| 291 | rowacc[x] += mul * rowtmp[x]; |
| 292 | ctx->output_row(oy, (void*)rowacc, ctx); |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 293 | /* clear accumulator row, store partial coverage for next row */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 294 | #ifdef HAVE_LCD_COLOR |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 295 | memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 296 | #else |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 297 | memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t)); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 298 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 299 | mul = oye; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 300 | oy += rset->rowstep; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 301 | /* inside an area */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 302 | } else { |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 303 | /* accumulate new scaled row to rowacc */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 304 | if (!ctx->h_scaler(rowacc, ctx, true)) |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 305 | return false; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 306 | } |
| 307 | } |
| 308 | return true; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 309 | } |
| 310 | |
| 311 | #ifdef HAVE_UPSCALER |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 312 | /* Set up rounding and scale factors for the horizontal scaler. The divisor |
| 313 | is bm->width - 1, so that the first and last pixels in the row align |
| 314 | exactly between input and output |
| 315 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 316 | static inline void scale_h_linear_setup(struct scaler_context *ctx) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 317 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 318 | ctx->divisor = ctx->bm->width - 1; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | /* horizontal linear scaler */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 322 | static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx, |
| 323 | bool accum) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 324 | { |
| 325 | unsigned int ix, ox, ixe; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 326 | /* type x = x is an ugly hack for hiding an unitialized data warning. The |
| 327 | values are conditionally initialized before use, but other values are |
| 328 | set such that this will occur before these are used. |
| 329 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 330 | #ifdef HAVE_LCD_COLOR |
| 331 | struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc, |
| 332 | *out_line = (struct uint32_rgb*)out_line_ptr; |
| 333 | #else |
| 334 | uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr; |
| 335 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 336 | struct img_part *part; |
| 337 | SDEBUGF("scale_h_linear\n"); |
| 338 | FILL_BUF_INIT(part,ctx->store_part,ctx->args); |
| 339 | ix = 0; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 340 | /* The error is set so that values are initialized on the first pass. */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 341 | ixe = ctx->bm->width - 1; |
| 342 | /* give other tasks a chance to run */ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 343 | yield(); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 344 | for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++) |
| 345 | { |
| 346 | #ifdef HAVE_LCD_COLOR |
| 347 | if (ixe >= ((uint32_t)ctx->bm->width - 1)) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 348 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 349 | /* Store the new "current" pixel value in rgbval, and the color |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 350 | step value in rgbinc. |
| 351 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 352 | ixe -= (ctx->bm->width - 1); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 353 | rgbinc.r = -(part->buf->red); |
| 354 | rgbinc.g = -(part->buf->green); |
| 355 | rgbinc.b = -(part->buf->blue); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 356 | rgbval.r = (part->buf->red) * (ctx->bm->width - 1); |
| 357 | rgbval.g = (part->buf->green) * (ctx->bm->width - 1); |
| 358 | rgbval.b = (part->buf->blue) * (ctx->bm->width - 1); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 359 | ix += 1; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 360 | /* If this wasn't the last pixel, add the next one to rgbinc. */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 361 | if (ix < (uint32_t)ctx->src->width) { |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 362 | part->buf++; |
| 363 | part->len--; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 364 | /* Fetch new pixels if needed */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 365 | FILL_BUF(part,ctx->store_part,ctx->args); |
| 366 | rgbinc.r += part->buf->red; |
| 367 | rgbinc.g += part->buf->green; |
| 368 | rgbinc.b += part->buf->blue; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 369 | /* Add a partial step to rgbval, in this pixel isn't precisely |
| 370 | aligned with the new source pixel |
| 371 | */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 372 | rgbval.r += rgbinc.r * ixe; |
| 373 | rgbval.g += rgbinc.g * ixe; |
| 374 | rgbval.b += rgbinc.b * ixe; |
| 375 | } |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 376 | /* Now multiple the color increment to its proper value */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 377 | rgbinc.r *= ctx->src->width - 1; |
| 378 | rgbinc.g *= ctx->src->width - 1; |
| 379 | rgbinc.b *= ctx->src->width - 1; |
| 380 | } else { |
| 381 | rgbval.r += rgbinc.r; |
| 382 | rgbval.g += rgbinc.g; |
| 383 | rgbval.b += rgbinc.b; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 384 | } |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 385 | /* round and scale values, and accumulate or store to output */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 386 | if (accum) |
| 387 | { |
| 388 | out_line[ox].r += rgbval.r; |
| 389 | out_line[ox].g += rgbval.g; |
| 390 | out_line[ox].b += rgbval.b; |
| 391 | } else { |
| 392 | out_line[ox].r = rgbval.r; |
| 393 | out_line[ox].g = rgbval.g; |
| 394 | out_line[ox].b = rgbval.b; |
| 395 | } |
| 396 | #else |
| 397 | if (ixe >= ((uint32_t)ctx->bm->width - 1)) |
| 398 | { |
| 399 | /* Store the new "current" pixel value in rgbval, and the color |
| 400 | step value in rgbinc. |
| 401 | */ |
| 402 | ixe -= (ctx->bm->width - 1); |
| 403 | val = *(part->buf); |
| 404 | inc = -val; |
| 405 | val *= (ctx->bm->width - 1); |
| 406 | ix += 1; |
| 407 | /* If this wasn't the last pixel, add the next one to rgbinc. */ |
| 408 | if (ix < (uint32_t)ctx->src->width) { |
| 409 | part->buf++; |
| 410 | part->len--; |
| 411 | /* Fetch new pixels if needed */ |
| 412 | FILL_BUF(part,ctx->store_part,ctx->args); |
| 413 | inc += *(part->buf); |
| 414 | /* Add a partial step to rgbval, in this pixel isn't precisely |
| 415 | aligned with the new source pixel |
| 416 | */ |
| 417 | val += inc * ixe; |
| 418 | } |
| 419 | /* Now multiply the color increment to its proper value */ |
| 420 | inc *= ctx->src->width - 1; |
| 421 | } else |
| 422 | val += inc; |
| 423 | /* round and scale values, and accumulate or store to output */ |
| 424 | if (accum) |
| 425 | { |
| 426 | out_line[ox] += val; |
| 427 | } else { |
| 428 | out_line[ox] = val; |
| 429 | } |
| 430 | #endif |
| 431 | ixe += ctx->src->width - 1; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 432 | } |
| 433 | return true; |
| 434 | } |
| 435 | |
| 436 | /* vertical linear scaler */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 437 | static inline bool scale_v_linear(struct rowset *rset, |
| 438 | struct scaler_context *ctx) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 439 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 440 | uint32_t mul, x, iy, iye; |
| 441 | int32_t oy; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 442 | /* Set up scale and rounding factors, the divisor is bm->height - 1 */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 443 | ctx->divisor *= (ctx->bm->height - 1); |
| 444 | ctx->round = ctx->divisor >> 1; |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 445 | ctx->divisor = (((ctx->divisor >> 1) + SC_NUM) / ctx->divisor) << SC_FIX; |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 446 | /* Set up our two temp buffers. The names are generic because they'll be |
| 447 | swapped each time a new input row is read |
| 448 | */ |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 449 | #ifdef HAVE_LCD_COLOR |
| 450 | uint32_t *rowinc = (uint32_t *)(ctx->buf), |
| 451 | *rowval = rowinc + 3 * ctx->bm->width, |
| 452 | *rowtmp = rowval + 3 * ctx->bm->width; |
| 453 | #else |
| 454 | uint32_t *rowinc = (uint32_t *)(ctx->buf), |
| 455 | *rowval = rowinc + ctx->bm->width, |
| 456 | *rowtmp = rowval + ctx->bm->width; |
| 457 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 458 | |
| 459 | SDEBUGF("scale_v_linear\n"); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 460 | mul = 0; |
| 461 | iy = 0; |
| 462 | iye = ctx->bm->height - 1; |
| 463 | /* get first scaled row in rowtmp */ |
| 464 | if(!ctx->h_scaler((void*)rowtmp, ctx, false)) |
Andrew Mahone | 995c89c | 2008-12-10 12:09:03 +0000 | [diff] [blame] | 465 | return false; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 466 | for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 467 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 468 | if (iye >= (uint32_t)ctx->bm->height - 1) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 469 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 470 | iye -= ctx->bm->height - 1; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 471 | iy += 1; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 472 | #ifdef HAVE_LCD_COLOR |
| 473 | for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) |
| 474 | #else |
| 475 | for (x = 0; x < (uint32_t)ctx->bm->width; x++) |
| 476 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 477 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 478 | rowinc[x] = -rowtmp[x]; |
| 479 | rowval[x] = rowtmp[x] * (ctx->bm->height - 1); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 480 | } |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 481 | if (iy < (uint32_t)ctx->src->height) |
| 482 | { |
| 483 | if (!ctx->h_scaler((void*)rowtmp, ctx, false)) |
| 484 | return false; |
| 485 | #ifdef HAVE_LCD_COLOR |
| 486 | for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) |
| 487 | #else |
| 488 | for (x = 0; x < (uint32_t)ctx->bm->width; x++) |
| 489 | #endif |
| 490 | { |
| 491 | rowinc[x] += rowtmp[x]; |
| 492 | rowval[x] += rowinc[x] * iye; |
| 493 | rowinc[x] *= ctx->src->height - 1; |
| 494 | } |
| 495 | } |
| 496 | } else |
| 497 | #ifdef HAVE_LCD_COLOR |
| 498 | for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) |
| 499 | #else |
| 500 | for (x = 0; x < (uint32_t)ctx->bm->width; x++) |
| 501 | #endif |
| 502 | rowval[x] += rowinc[x]; |
| 503 | ctx->output_row(oy, (void*)rowval, ctx); |
| 504 | iye += ctx->src->height - 1; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 505 | } |
| 506 | return true; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 507 | } |
| 508 | #endif /* HAVE_UPSCALER */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 509 | |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 510 | #ifndef PLUGIN |
| 511 | void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 512 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 513 | int col; |
| 514 | int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0); |
| 515 | uint8_t dy = DITHERY(row); |
| 516 | #ifdef HAVE_LCD_COLOR |
| 517 | struct uint32_rgb *qp = (struct uint32_rgb*)row_in; |
| 518 | #else |
| 519 | uint32_t *qp = (uint32_t*)row_in; |
| 520 | #endif |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 521 | SDEBUGF("output_row: y: %lu in: %p\n",row, row_in); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 522 | #if LCD_DEPTH == 2 |
| 523 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING |
| 524 | /* greyscale iPods */ |
| 525 | fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; |
| 526 | int shift = 6; |
| 527 | int delta = 127; |
| 528 | unsigned bright; |
| 529 | unsigned data = 0; |
| 530 | |
| 531 | for (col = 0; col < ctx->bm->width; col++) { |
| 532 | if (ctx->dither) |
| 533 | delta = DITHERXDY(col,dy); |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 534 | bright = SC_MUL((*qp++) + ctx->round,ctx->divisor); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 535 | bright = (3 * bright + (bright >> 6) + delta) >> 8; |
| 536 | data |= (~bright & 3) << shift; |
| 537 | shift -= 2; |
| 538 | if (shift < 0) { |
| 539 | *dest++ = data; |
| 540 | data = 0; |
| 541 | shift = 6; |
| 542 | } |
| 543 | } |
| 544 | if (shift < 6) |
| 545 | *dest++ = data; |
| 546 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING |
| 547 | /* iriver H1x0 */ |
| 548 | fb_data *dest = (fb_data *)ctx->bm->data + fb_width * |
| 549 | (row >> 2); |
| 550 | int shift = 2 * (row & 3); |
| 551 | int delta = 127; |
| 552 | unsigned bright; |
| 553 | |
| 554 | for (col = 0; col < ctx->bm->width; col++) { |
| 555 | if (ctx->dither) |
| 556 | delta = DITHERXDY(col,dy); |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 557 | bright = SC_MUL((*qp++) + ctx->round, ctx->divisor); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 558 | bright = (3 * bright + (bright >> 6) + delta) >> 8; |
| 559 | *dest++ |= (~bright & 3) << shift; |
| 560 | } |
| 561 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED |
| 562 | /* iAudio M3 */ |
| 563 | fb_data *dest = (fb_data *)ctx->bm->data + fb_width * |
| 564 | (row >> 3); |
| 565 | int shift = row & 7; |
| 566 | int delta = 127; |
| 567 | unsigned bright; |
| 568 | |
| 569 | for (col = 0; col < ctx->bm->width; col++) { |
| 570 | if (ctx->dither) |
| 571 | delta = DITHERXDY(col,dy); |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 572 | bright = SC_MUL((*qp++) + ctx->round, ctx->divisor); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 573 | bright = (3 * bright + (bright >> 6) + delta) >> 8; |
| 574 | *dest++ |= vi_pattern[bright] << shift; |
| 575 | } |
| 576 | #endif /* LCD_PIXELFORMAT */ |
| 577 | #elif LCD_DEPTH == 16 |
| 578 | /* iriver h300, colour iPods, X5 */ |
| 579 | fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; |
| 580 | int delta = 127; |
| 581 | unsigned r, g, b; |
| 582 | struct uint32_rgb q0; |
| 583 | |
| 584 | for (col = 0; col < ctx->bm->width; col++) { |
| 585 | if (ctx->dither) |
| 586 | delta = DITHERXDY(col,dy); |
| 587 | q0 = *qp++; |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 588 | r = SC_MUL(q0.r + ctx->round, ctx->divisor); |
| 589 | g = SC_MUL(q0.g + ctx->round, ctx->divisor); |
| 590 | b = SC_MUL(q0.b + ctx->round, ctx->divisor); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 591 | r = (31 * r + (r >> 3) + delta) >> 8; |
| 592 | g = (63 * g + (g >> 2) + delta) >> 8; |
| 593 | b = (31 * b + (b >> 3) + delta) >> 8; |
| 594 | *dest++ = LCD_RGBPACK_LCD(r, g, b); |
| 595 | } |
| 596 | #endif /* LCD_DEPTH */ |
| 597 | } |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 598 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 599 | |
| 600 | int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, |
| 601 | struct rowset *rset, unsigned char *buf, unsigned int len, |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 602 | const struct custom_format *format, |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 603 | struct img_part* (*store_part)(void *args), |
| 604 | void *args) |
| 605 | { |
| 606 | |
| 607 | #ifdef HAVE_UPSCALER |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 608 | const int sw = src->width; |
| 609 | const int sh = src->height; |
| 610 | const int dw = bm->width; |
| 611 | const int dh = bm->height; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 612 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 613 | int ret; |
| 614 | #ifdef HAVE_LCD_COLOR |
| 615 | unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 616 | #else |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 617 | unsigned int needed = sizeof(uint32_t) * 3 * bm->width; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 618 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 619 | #if MAX_SC_STACK_ALLOC |
| 620 | uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? |
| 621 | 0 : needed]; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 622 | #endif |
Andrew Mahone | 2fbf097 | 2009-01-13 13:48:26 +0000 | [diff] [blame] | 623 | ALIGN_BUFFER(buf, len, sizeof(uint32_t)); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 624 | if (needed > len) |
| 625 | { |
| 626 | #if MAX_SC_STACK_ALLOC |
| 627 | if (needed > MAX_SC_STACK_ALLOC) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 628 | { |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 629 | DEBUGF("unable to allocate required buffer: %d needed, " |
| 630 | "%d available, %d permitted from stack\n", |
| 631 | needed, len, MAX_SC_STACK_ALLOC); |
| 632 | return 0; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 633 | } |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 634 | if (sizeof(sc_buf) < needed) |
| 635 | { |
| 636 | DEBUGF("failed to allocate large enough buffer on stack: " |
| 637 | "%d needed, only got %d", |
| 638 | needed, MAX_SC_STACK_ALLOC); |
| 639 | return 0; |
| 640 | } |
| 641 | #else |
| 642 | DEBUGF("unable to allocate required buffer: %d needed, " |
| 643 | "%d available\n", needed, len); |
| 644 | return 0; |
| 645 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 646 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 647 | |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 648 | struct scaler_context ctx; |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 649 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 650 | cpu_boost(true); |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 651 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 652 | ctx.store_part = store_part; |
| 653 | ctx.args = args; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 654 | #if MAX_SC_STACK_ALLOC |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 655 | ctx.buf = needed > len ? sc_buf : buf; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 656 | #else |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 657 | ctx.buf = buf; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 658 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 659 | ctx.len = len; |
| 660 | ctx.bm = bm; |
| 661 | ctx.src = src; |
| 662 | ctx.dither = dither; |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 663 | #ifndef PLUGIN |
| 664 | ctx.output_row = output_row_native; |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 665 | if (format) |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 666 | #endif |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 667 | ctx.output_row = format->output_row; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 668 | #ifdef HAVE_UPSCALER |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 669 | if (sw > dw) |
| 670 | { |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 671 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 672 | ctx.h_scaler = scale_h_area; |
| 673 | scale_h_area_setup(&ctx); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 674 | #ifdef HAVE_UPSCALER |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 675 | } else { |
| 676 | ctx.h_scaler = scale_h_linear; |
| 677 | scale_h_linear_setup(&ctx); |
| 678 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 679 | #endif |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 680 | SC_MUL_INIT; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 681 | #ifdef HAVE_UPSCALER |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 682 | if (sh > dh) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 683 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 684 | ret = scale_v_area(rset, &ctx); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 685 | #ifdef HAVE_UPSCALER |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 686 | else |
| 687 | ret = scale_v_linear(rset, &ctx); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 688 | #endif |
Andrew Mahone | 1b13299 | 2009-01-20 17:24:49 +0000 | [diff] [blame^] | 689 | SC_MUL_END; |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 690 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 691 | cpu_boost(false); |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 692 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 693 | if (!ret) |
| 694 | return 0; |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 695 | return 1; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 696 | } |