diff options
author | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
---|---|---|
committer | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
commit | f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04 (patch) | |
tree | ea469e428a756e4f4979be1b6f5a84179a2cc80f /apps/recorder/resize.c | |
parent | 7428c7cc5b8462ed95683f707fe78609ce8208bf (diff) | |
download | rockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.tar.gz rockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.zip |
Latest work on the bmp on-load scaler:
Macros for calculating size needed for bitmap load and scaling, so that
these can be compile-time constant when their inputs are.
Reduce size of bayer dither by chopping all but first row of dither
matrix, and replacing 2D lookup with 1D lookup and small calculation.
Move some functions not related to actual bmp file loading out of bmp.c.
A smaller brightness() for mono targets, and a higher-quality one for
greyscale targets, both replacing the division by 10 with a shift.
Port of the linear and area scalers to greyscale targets, this costs
some binsize but produces better output even when dithered to 2bpp.
Move duplicated row output code from inside vertical scalers to a
separate row output function.
Move some multiplies out of the line scaler, for a small speedup and
code size reduction, as well as a small improvement in accuracy for the
upscaling case.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19592 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/resize.c')
-rw-r--r-- | apps/recorder/resize.c | 920 |
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 | */ | ||
66 | int 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 | ||
87 | struct 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 | |||
93 | struct scaler_context { | 120 | struct 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 */ |
104 | static void scale_h_area_setup(struct bitmap *bm, struct dim *src, | 135 | static 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 */ |
114 | static bool scale_h_area(struct bitmap *bm, struct dim *src, | 143 | static 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 */ |
191 | static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, | 250 | static 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 | */ |
275 | static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, | 326 | static 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 */ |
284 | static bool scale_h_linear(struct bitmap *bm, struct dim *src, | 332 | static 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 */ |
360 | static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, | 447 | static 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 | 520 | void 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 */ | ||
441 | static 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 | ||
674 | int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, | 611 | int 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 | } |