diff options
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 | } |