From f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 26 Dec 2008 07:03:22 +0000 Subject: [PATCH] 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 --- apps/plugin.h | 1 + apps/plugins/sliding_puzzle.c | 32 +- apps/recorder/bmp.c | 323 ++++++------ apps/recorder/bmp.h | 233 +++++---- apps/recorder/resize.c | 958 ++++++++++++++++------------------ apps/recorder/resize.h | 25 +- firmware/export/lcd-remote.h | 4 + firmware/export/lcd.h | 4 + 8 files changed, 761 insertions(+), 819 deletions(-) diff --git a/apps/plugin.h b/apps/plugin.h index e16d9ebaec..20e3a71595 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -78,6 +78,7 @@ void* plugin_get_buffer(size_t *buffer_size); #include "playlist.h" #ifdef HAVE_LCD_BITMAP #include "scrollbar.h" +#include "../recorder/bmp.h" #endif #include "statusbar.h" #include "menu.h" diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index 85f4d32f68..fa9e093c3c 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -19,7 +19,6 @@ * ****************************************************************************/ #include "plugin.h" -#include "lib/bmp.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER @@ -258,13 +257,9 @@ static int num_font = FONT_UI; static int moves_font = FONT_UI; static int moves_y = 0; -#ifdef HAVE_LCD_COLOR -static unsigned char *img_buf; -static size_t buf_len; -#else -static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)] -__attribute__ ((aligned(16))); -#endif +static unsigned char img_buf + [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)] + __attribute__ ((aligned(16))); #ifdef HAVE_ALBUMART static char albumart_path[MAX_PATH+1]; #endif @@ -343,13 +338,9 @@ static bool load_resize_bitmap(void) main_bitmap.width = IMAGE_WIDTH; main_bitmap.height = IMAGE_HEIGHT; -#ifndef HAVE_LCD_COLOR - size_t buf_len = sizeof(img_buf); -#endif - rc = rb->read_bmp_file( filename, &main_bitmap, - buf_len, - FORMAT_NATIVE|FORMAT_RESIZE ); + sizeof(img_buf), + FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER); if( rc > 0 ) { puzzle_bmp_ptr = (const fb_data *)img_buf; @@ -574,7 +565,8 @@ static int puzzle_loop(void) /* change picture */ picmode = (picmode+1)%PICMODE_LAST_XXX; - /* if load_resize_bitmap fails to load bitmap, try next picmode */ + /* if load_resize_bitmap fails to load bitmap, try next picmode + */ do { load_success = load_resize_bitmap(); @@ -618,7 +610,8 @@ static int puzzle_loop(void) } } -enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) +enum plugin_status plugin_start(const struct plugin_api* api, + const void* parameter) { int i, w, h; @@ -627,13 +620,6 @@ enum plugin_status plugin_start(const struct plugin_api* api, const void* parame initial_bmp_path=(const char *)parameter; picmode = PICMODE_INITIAL_PICTURE; img_buf_path[0] = '\0'; -#ifdef HAVE_LCD_COLOR - unsigned char *img_buf_end; - img_buf = (unsigned char *)(rb->plugin_get_buffer(&buf_len)); - img_buf_end = img_buf + buf_len; - rb->align_buffer(PUN_PTR(void **,&img_buf), buf_len, 16); - buf_len = img_buf_end - img_buf; -#endif /* If launched as a viewer, just go straight to the game without bothering with the splash or instructions page */ diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index cdff8ccb07..cc574649d8 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -124,25 +124,10 @@ static const struct uint8_rgb bitfields[3][3] = { }; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) -/* canonical ordered dither matrix */ -const unsigned char dither_matrix[16][16] = { - { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, - { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, - { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, - { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, - { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, - { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, - { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, - { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, - { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, - { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, - { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, - { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, - { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, - { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, - { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, - { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } -}; +/* the full 16x16 Bayer dither matrix may be calculated quickly with this table +*/ +const unsigned char dither_table[16] = + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }; #endif #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ @@ -194,7 +179,7 @@ struct bmp_args { short read_width; short width; short depth; - unsigned char buf[MAX_WIDTH * 4]; + unsigned char buf[BM_MAX_WIDTH * 4]; struct uint8_rgb *palette; #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) int cur_row; @@ -222,13 +207,14 @@ static unsigned int read_part_line(struct bmp_args *ba) int i, cols, len; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - cols = MIN(width - cur_col,(int)MAX_WIDTH); + cols = MIN(width - cur_col,(int)BM_MAX_WIDTH); + BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH); len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3; #else cols = width; len = read_width; #endif - ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len; + ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len; BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len); ret = read(fd, ibuf, len); if (ret != len) @@ -239,25 +225,25 @@ static unsigned int read_part_line(struct bmp_args *ba) cols, len); return 0; } - for (i = 0; i < cols; i++) + while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) { switch (depth) { case 1: - if ((i & 7) == 0) - data = *ibuf++; - *buf = palette[(data >> 7) & 1]; - data <<= 1; + data = *ibuf++; + for (i = 0; i < 8; i++) + { + *buf++ = palette[data & 0x80 ? 1 : 0]; + data <<= 1; + } break; case 4: - *buf = palette[*ibuf >> 4]; - if (i & 1) - ibuf++; - else - *ibuf <<= 4; + data = *ibuf++; + *buf++ = palette[data >> 4]; + *buf++ = palette[data & 0xf]; break; case 8: - *buf = palette[*ibuf++]; + *buf++ = palette[*ibuf++]; break; case 15: case 16: @@ -280,6 +266,7 @@ static unsigned int read_part_line(struct bmp_args *ba) component = data & 0xf8; component |= component >> 5; buf->red = component; + buf++; ibuf += 2; break; case 32: @@ -289,11 +276,19 @@ static unsigned int read_part_line(struct bmp_args *ba) buf->red = *ibuf++; if (depth == 32) ibuf++; + buf++; break; } - buf++; } +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + ibuf = ba->buf; + buf = (struct uint8_rgb*)ba->buf; + while (ibuf < ba->buf + cols) + *ibuf++ = brightness(*buf++); +#endif + #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) cur_col += cols; if (cur_col == width) @@ -323,58 +318,16 @@ static struct img_part *store_part_bmp(void *args) struct bmp_args *ba = (struct bmp_args *)args; ba->part.len = read_part_line(ba); +#ifdef HAVE_LCD_COLOR ba->part.buf = (struct uint8_rgb *)ba->buf; +#else + ba->part.buf = (uint8_t *)ba->buf; +#endif if (ba->part.len) return &(ba->part); else return NULL; } - -static bool skip_lines_bmp(void *args, unsigned int lines) -{ - struct bmp_args * ba = (struct bmp_args *)args; - - int pad = lines * ba->padded_width + - (ba->cur_col - ? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width - : 0); - if (pad) - { - if(lseek(ba->fd, pad, SEEK_CUR) < 0) - - return false; - } - ba->cur_row += lines + (ba->cur_col ? 1 : 0); - ba->cur_col = 0; - return true; -} -#endif - -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -static inline int recalc_dimension(struct dim *dst, struct dim *src) -{ - int tmp; - if (dst->width <= 0) - dst->width = LCD_WIDTH; - if (dst->height <= 0) - dst->height = LCD_HEIGHT; -#ifndef HAVE_UPSCALER - if (dst->width > src->width || dst->height > src->height) - { - dst->width = src->width; - dst->height = src->height; - } - if (src->width == dst->width && src->height == dst->height) - return 1; -#endif - tmp = (src->width * dst->height + (src->height >> 1)) / src->height; - if (tmp > dst->width) - dst->height = (src->height * dst->width + (src->width >> 1)) - / src->width; - else - dst->width = tmp; - return src->width == dst->width && src->height == dst->height; -} #endif static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) @@ -406,37 +359,32 @@ int read_bmp_fd(int fd, unsigned char *bitmap = bm->data; struct uint8_rgb palette[256]; - bool remote = false; struct rowset rset; struct dim src_dim; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + bool remote = false; unsigned int resize = IMG_NORESIZE; bool dither = false; bool transparent = false; - + #ifdef HAVE_REMOTE_LCD if (format & FORMAT_REMOTE) { remote = true; #if LCD_REMOTE_DEPTH == 1 format = FORMAT_MONO; -#else - format &= ~FORMAT_REMOTE; #endif } #endif /* HAVE_REMOTE_LCD */ if (format & FORMAT_RESIZE) { resize = IMG_RESIZE; - format &= ~FORMAT_RESIZE; } if (format & FORMAT_TRANSPARENT) { transparent = true; - format &= ~FORMAT_TRANSPARENT; } if (format & FORMAT_DITHER) { dither = true; - format &= ~FORMAT_DITHER; } #else @@ -470,23 +418,23 @@ int read_bmp_fd(int fd, BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width, src_dim.height, depth, padded_width); - -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) if ((format & 3) == FORMAT_ANY) { if (depth == 1) format = (format & ~3); else format = (format & ~3) | FORMAT_NATIVE; } - bm->format = format & 3; - if ((format & 3) == FORMAT_MONO) + bm->format = format & 1; + if ((format & 1) == FORMAT_MONO) { resize &= ~IMG_RESIZE; resize |= IMG_NORESIZE; remote = 0; } #else - if (src_dim.width > MAX_WIDTH) + if (src_dim.width > BM_MAX_WIDTH) return -6; #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ @@ -494,7 +442,6 @@ int read_bmp_fd(int fd, if (resize & IMG_RESIZE) { if(format & FORMAT_KEEP_ASPECT) { /* keep aspect ratio.. */ - format &= ~FORMAT_KEEP_ASPECT; struct dim resize_dim = { .width = bm->width, .height = bm->height, @@ -506,6 +453,8 @@ int read_bmp_fd(int fd, } } + format &= 1; + if (!(resize & IMG_RESIZE)) { #endif /* returning image size */ @@ -524,7 +473,7 @@ int read_bmp_fd(int fd, rset.rowstop = -1; } - totalsize = get_totalsize(bm, remote); + totalsize = BM_SIZE(bm->width,bm->height,format,remote); /* Check if this fits the buffer */ if (totalsize > maxsize) { @@ -616,90 +565,146 @@ int read_bmp_fd(int fd, }; #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -#if LCD_DEPTH == 16 -#ifdef HAVE_REMOTE_LCD - if (resize & IMG_RESIZE || remote) -#else - if (resize & IMG_RESIZE) -#endif -#else - if (format == FORMAT_NATIVE) -#endif - return resize_on_load(bm, dither, &src_dim, &rset, remote, -#ifdef HAVE_LCD_COLOR + if (resize) + return resize_on_load(bm, dither, &src_dim, &rset, bitmap + totalsize, maxsize - totalsize, -#endif - store_part_bmp, skip_lines_bmp, &ba); + store_part_bmp, &ba); + + int fb_width = BM_WIDTH(bm->width,bm->format,remote); #endif /* LCD_DEPTH */ - int fb_width = get_fb_width(bm, remote); int col, row; /* loop to read rows and put them to buffer */ for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { - struct uint8_rgb *qp; +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + uint8_t* qp = ba.buf; +#else + struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf; +#endif unsigned mask; unsigned char *p; -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - unsigned int len; - - if (!(len = read_part_line(&ba))) - return -9; -#else if (!read_part_line(&ba)) return -9; -#endif /* Convert to destination format */ - qp = (struct uint8_rgb *) ba.buf; -#if LCD_DEPTH == 16 - if (format == FORMAT_NATIVE) - { - /* iriver h300, colour iPods, X5 */ - fb_data *dest = (fb_data *)bitmap + fb_width * row; - int delta = 127; - unsigned r, g, b; - struct uint8_rgb q0; +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + unsigned char dy = DITHERY(row); + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + /* iAudio X5/M5 remote */ + fb_remote_data *dest = (fb_remote_data *)bitmap + + bm->width * (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; - for (col = 0; col < src_dim.width; col++) { - if (dither) - delta = dither_mat(row & 0xf, col & 0xf); - if (!len) - { - if(!(len = read_part_line(&ba))) - return -9; - else - qp = (struct uint8_rgb *)ba.buf; - } - q0 = *qp++; - len--; - r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; - g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; - b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; - *dest++ = LCD_RGBPACK_LCD(r, g, b); - } - } - else + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + bright = *qp++; +#else + bright = brightness(*qp++); #endif - { - p = bitmap + fb_width * (row >> 3); - mask = 1 << (row & 7); - for (col = 0; col < src_dim.width; col++) + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ { -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - if (!len) - { - if(!(len = read_part_line(&ba))) - return -9; - else - qp = (struct uint8_rgb *)ba.buf; +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + /* greyscale iPods */ + fb_data *dest = (fb_data *)bitmap + fb_width * row; + int shift = 6; + int delta = 127; + unsigned bright; + unsigned data = 0; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + data |= (~bright & 3) << shift; + shift -= 2; + if (shift < 0) { + *dest++ = data; + data = 0; + shift = 6; + } } - len--; -#endif + if (shift < 6) + *dest++ = data; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 2); + int shift = 2 * (row & 3); + int delta = 127; + unsigned bright; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= (~bright & 3) << shift; + } +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + /* iAudio M3 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + /* iriver h300, colour iPods, X5 */ + fb_data *dest = (fb_data *)bitmap + fb_width * row; + int delta = 127; + unsigned r, g, b; + struct uint8_rgb q0; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + q0 = *qp++; + r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; + g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; + b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } +#endif /* LCD_DEPTH */ + } + } else +#endif /* (LCD_DEPTH > 1) || + defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + p = bitmap + bm->width * (row >> 3); + mask = 1 << (row & 7); + + for (col = 0; col < bm->width; col++, p++) +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + if (*qp++ < 128) + *p |= mask; +#else if (brightness(*qp++) < 128) *p |= mask; - p++; - } +#endif } } return totalsize; /* return the used buffer size. */ diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index d1b1d7f3ed..273e178bc9 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h @@ -32,11 +32,7 @@ #define IMG_NORESIZE 0 #define IMG_RESIZE 1 -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -#define MAX_WIDTH 8 -#else -#define MAX_WIDTH LCD_WIDTH -#endif +#define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7) struct uint8_rgb { uint8_t blue; @@ -56,129 +52,144 @@ struct rowset { }; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) -extern const unsigned char dither_matrix[16][16]; -static inline unsigned char dither_mat(unsigned int x, unsigned int y) -{ - return dither_matrix[y][x]; -} +extern const unsigned char dither_table[16]; +#define DITHERY(y) (dither_table[(y) & 15] & 0xAA) +#define DITHERX(x) (dither_table[(x) & 15]) +#define DITHERXDY(x,dy) (DITHERX(x) ^ dy) +#define DITHERDXY(dx,y) (dx ^ DITHERY(y)) +#define DITHERXY(x,y) (DITHERX(x) ^ DITHERY(y)) #endif +/* The /256 version has a mean squared variance from YUV luma of <1 grey level. + The /8 version is a good deal less accurate, but sufficient on mono as we + don't support HQ output or dithering there, yet. +*/ static inline unsigned brightness(struct uint8_rgb color) { - return (3 * (unsigned)color.red + 6 * (unsigned)color.green - + (unsigned)color.blue) / 10; +#if LCD_DEPTH > 1 + return (77 * (unsigned)color.red + 150 * (unsigned)color.green + + 29 * (unsigned)color.blue) / 256; +#else + return (2 * (unsigned)color.red + 5 * (unsigned)color.green + + (unsigned)color.blue) / 8; +#endif } #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) extern const unsigned short vi_pattern[4]; -static inline unsigned short vi_pat(unsigned int bright) -{ - return vi_pattern[bright]; -} #endif -static inline int get_fb_height(struct bitmap *bm, bool remote) -{ - const int height = bm->height; -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - const int format = bm->format; -#endif - int dst_height; +/* Number of rows of data in a mono bitmap height pixels tall */ +#define MONO_BM_HEIGHT(height) (((height) + 7) >> 3) -#if !defined(HAVE_REMOTE_LCD) || \ - (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) - (void) remote; +/* Number of rows of datain a LCD native bitmap height pixels tall */ +#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) +#if LCD_DEPTH == 1 || \ + (LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) +#define LCD_BM_HEIGHT(height) (((height) + 7) >> 3) +#elif LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_PACKING +#define LCD_BM_HEIGHT(height) (((height) + 3) >> 2) +#else +#define LCD_BM_HEIGHT(height) (height) #endif -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - if (format == FORMAT_NATIVE) { -#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - if (remote) { -#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) - dst_height = (height + 7) >> 3; -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - } else -#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ - { -#if LCD_DEPTH == 2 -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dst_height = height; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dst_height = (height + 3) >> 2; -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dst_height = (height + 7) >> 3; -#endif /* LCD_PIXELFORMAT */ -#elif LCD_DEPTH == 16 - dst_height = height; -#endif /* LCD_DEPTH */ - } - } else -#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - { - dst_height = (height + 7) >> 3; - } - - return dst_height; -} - -static inline int get_fb_width(struct bitmap *bm, bool remote) -{ - const int width = bm->width; -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - const int format = bm->format; -#endif - int dst_width; - -#if !defined(HAVE_REMOTE_LCD) || \ - (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) - (void) remote; -#endif - -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - if (format == FORMAT_NATIVE) { -#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - if (remote) { -#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) - dst_width = width; -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - } else -#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ - { -#if LCD_DEPTH == 2 -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dst_width = (width + 3) >> 2; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dst_width = width; -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dst_width = width; -#endif /* LCD_PIXELFORMAT */ -#elif LCD_DEPTH == 16 - dst_width = width; -#endif /* LCD_DEPTH */ - } - } else -#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - { - dst_width = width; - } - - return dst_width; -} - -static inline int get_totalsize(struct bitmap *bm, bool remote) -{ - int sz; +/* Number of rows of data in a remote native bitmap height pixels tall. */ #ifdef HAVE_REMOTE_LCD - if (remote && sizeof(fb_data) != sizeof(fb_remote_data)) - sz = sizeof(fb_remote_data); - else -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - sz = sizeof(fb_data); +#if LCD_REMOTE_DEPTH == 1 || \ + (LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) +#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 7) >> 3) +#elif LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING +#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 3) >> 2) +#else +#define LCD_REMOTE_BM_HEIGHT(height) (height) +#endif +#define NATIVE_BM_HEIGHT(height,remote) ((remote) ? \ + LCD_REMOTE_BM_HEIGHT(height) : LCD_BM_HEIGHT(height)) +#else +#define NATIVE_BM_HEIGHT(height,remote) LCD_BM_HEIGHT(height) +#endif - return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; -} +/* Convenience macro to calculate rows based on height, remote vs main LCD, + and format +*/ +#define BM_HEIGHT(height,format,remote) ((format) == FORMAT_MONO ? \ + MONO_BM_HEIGHT(height) : NATIVE_BM_HEIGHT(height,remote)) +#else +#define BM_HEIGHT(height,format,remote) MONO_BM_HEIGHT(height) +#endif + +/* Number of data elements in a mono bitmap width pixels wide */ +#define MONO_BM_WIDTH(width) (width) + +/* Number of data elements in a LCD native bitmap width pixels wide */ +#if LCD_DEPTH > 1 +#if LCD_DEPTH == 2 && LCD_PIXELFORMAT == HORIZONTAL_PACKING +#define LCD_BM_WIDTH(width) (((width) + 3) >> 2) +#else +#define LCD_BM_WIDTH(width) (width) +#endif + +/* Number of data elements in a remote native bitmap width pixels wide */ +#ifdef HAVE_LCD_REMOTE +#if LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING +#define LCD_REMOTE_BM_WIDTH(width) (((width) + 3) >> 2) +#else +#define LCD_REMOTE_BM_WIDTH(width) (width) +#endif +#define NATIVE_BM_WIDTH(width,remote) ((remote) ? \ + LCD_REMOTE_BM_WIDTH(width) : LCD_BM_WIDTH(width)) +#else +#define NATIVE_BM_WIDTH(width,remote) LCD_BM_WIDTH(width) +#endif + +/* Convenience macro to calculate elements based on height, remote vs native + main LCD, and format +*/ +#define BM_WIDTH(width,format,remote) ((format) == FORMAT_MONO ? \ + MONO_BM_WIDTH(width) : NATIVE_BM_WIDTH(width,remote)) +#else +#define BM_WIDTH(width,format,remote) MONO_BM_WIDTH(width) +#endif + +/* Size in bytes of a mono bitmap of dimensions width*height */ +#define MONO_BM_SIZE(width,height) (MONO_BM_WIDTH(width) * \ + MONO_BM_HEIGHT(height) * FB_DATA_SZ) + +/* Size in bytes of a native bitmap of dimensions width*height */ +#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) +#if defined(HAVE_REMOTE_LCD) && FB_DATA_SZ != FB_RDATA_SZ +#define NATIVE_BM_SIZE(width,height,format,remote) \ + (((remote) ? FB_RDATA_SZ : FB_DATA_SZ) * BM_WIDTH(width,format,remote) \ + * BM_HEIGHT(height,format,remote)) +#else +#define NATIVE_BM_SIZE(width,height,format,remote) \ + (FB_DATA_SZ * BM_WIDTH(width,format,remote) * \ + BM_HEIGHT(height,format,remote)) +#endif + +/* Convenience macro to calculate size in bytes based on height, remote vs + main LCD, and format +*/ +#define BM_SIZE(width,height,format,remote) (((format) == FORMAT_MONO) ? \ + MONO_BM_SIZE(width,height) : NATIVE_BM_SIZE(width,height,format,remote)) +#else +#define BM_SIZE(width,height,format,remote) MONO_BM_SIZE(width,height) +#endif + +/* Size in bytes needed to load and scale a bitmap with target size up to + width*height, including overhead to allow for buffer alignment. +*/ +#ifdef HAVE_LCD_COLOR +#define BM_SCALED_SIZE(width,height,format,remote) \ + (BM_SIZE(width,height,format,remote) + \ + (remote ? 0 : BM_WIDTH(width,format,remote) * sizeof(uint32_t) * 9 + 3)) +#else +#define BM_SCALED_SIZE(width,height,format,remote) \ + (BM_SIZE(width,height,format,remote) + \ + (width * sizeof(uint32_t) * 3 + 3)) +#endif /********************************************************************* * read_bmp_file() 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 @@ #define DEBUGF(...) #endif +/* calculate the maximum dimensions which will preserve the aspect ration of + src while fitting in the constraints passed in dst, and store result in dst, + returning 0 if rounding and 1 if not rounding. +*/ +int recalc_dimension(struct dim *dst, struct dim *src) +{ + int tmp; + if (dst->width <= 0) + dst->width = LCD_WIDTH; + if (dst->height <= 0) + dst->height = LCD_HEIGHT; +#ifndef HAVE_UPSCALER + if (dst->width > src->width || dst->height > src->height) + { + dst->width = src->width; + dst->height = src->height; + } + if (src->width == dst->width && src->height == dst->height) + return 1; +#endif + tmp = (src->width * dst->height + (src->height >> 1)) / src->height; + if (tmp > dst->width) + dst->height = (src->height * dst->width + (src->width >> 1)) + / src->width; + else + dst->width = tmp; + return src->width == dst->width && src->height == dst->height; +} + /* All of these scalers use variations of Bresenham's algorithm to convert from - their input to output coordinates. The color scalers have the error value - shifted so that it is a useful input to the scaling algorithm. + their input to output coordinates. The error value is shifted from the + "classic" version such that it is a useful input to the scaling calculation. */ #ifdef HAVE_LCD_COLOR /* dither + pack on channel of RGB565, R an B share a packing macro */ #define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) #define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) +#endif /* read new img_part unconditionally, return false on failure */ #define FILL_BUF_INIT(img_part, store_part, args) { \ @@ -84,183 +114,204 @@ return false; \ } -struct uint32_rgb { - uint32_t r; - uint32_t g; - uint32_t b; -}; - +/* struct which containers various parameters shared between vertical scaler, + horizontal scaler, and row output +*/ struct scaler_context { - uint32_t divmul; + uint32_t divisor; uint32_t round; - struct img_part* (*store_part)(void *); - long last_tick; + struct bitmap *bm; + struct dim *src; unsigned char *buf; + bool dither; int len; void *args; + struct img_part* (*store_part)(void *); + void (*output_row)(uint32_t,void*,struct scaler_context*); + bool (*h_scaler)(void*,struct scaler_context*, bool); }; /* Set up rounding and scale factors for horizontal area scaler */ -static void scale_h_area_setup(struct bitmap *bm, struct dim *src, - struct scaler_context *ctx) +static inline void scale_h_area_setup(struct scaler_context *ctx) { - (void) bm; /* sum is output value * src->width */ - ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1; - ctx->round = (src->width + 1) >> 1; + SDEBUGF("scale_h_area_setup\n"); + ctx->divisor = ctx->src->width; } /* horizontal area average scaler */ -static bool scale_h_area(struct bitmap *bm, struct dim *src, - struct uint32_rgb *out_line, +static bool scale_h_area(void *out_line_ptr, struct scaler_context *ctx, bool accum) { SDEBUGF("scale_h_area\n"); unsigned int ix, ox, oxe, mul; - struct uint32_rgb rgbvalacc = { 0, 0, 0 }, - rgbvaltmp = { 0, 0, 0 }; +#ifdef HAVE_LCD_COLOR + struct uint32_rgb rgbvalacc = { 0, 0, 0 }, + rgbvaltmp = { 0, 0, 0 }, + *out_line = (struct uint32_rgb *)out_line_ptr; +#else + uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr; +#endif struct img_part *part; FILL_BUF_INIT(part,ctx->store_part,ctx->args); ox = 0; oxe = 0; mul = 0; - for (ix = 0; ix < (unsigned int)src->width; ix++) + /* give other tasks a chance to run */ + yield(); + for (ix = 0; ix < (unsigned int)ctx->src->width; ix++) { - oxe += bm->width; + oxe += ctx->bm->width; /* end of current area has been reached */ - if (oxe >= (unsigned int)src->width) + /* fill buffer if needed */ + FILL_BUF(part,ctx->store_part,ctx->args); +#ifdef HAVE_LCD_COLOR + if (oxe >= (unsigned int)ctx->src->width) { - /* yield if we haven't since last tick */ - if (ctx->last_tick != current_tick) - { - yield(); - ctx->last_tick = current_tick; - } /* "reset" error, which now represents partial coverage of next pixel by the next area */ - oxe -= src->width; + oxe -= ctx->src->width; + /* add saved partial pixel from start of area */ - rgbvalacc.r = rgbvalacc.r * bm->width + rgbvaltmp.r * mul; - rgbvalacc.g = rgbvalacc.g * bm->width + rgbvaltmp.g * mul; - rgbvalacc.b = rgbvalacc.b * bm->width + rgbvaltmp.b * mul; - /* fill buffer if needed */ - FILL_BUF(part,ctx->store_part,ctx->args); + rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul; + rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul; + rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul; + /* get new pixel , then add its partial coverage to this area */ rgbvaltmp.r = part->buf->red; rgbvaltmp.g = part->buf->green; rgbvaltmp.b = part->buf->blue; - part->buf++; - part->len--; - mul = bm->width - oxe; + mul = ctx->bm->width - oxe; rgbvalacc.r += rgbvaltmp.r * mul; rgbvalacc.g += rgbvaltmp.g * mul; rgbvalacc.b += rgbvaltmp.b * mul; - /* round, divide, and either store or accumulate to output row */ - out_line[ox].r = (accum ? out_line[ox].r : 0) + - ((rgbvalacc.r + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].g = (accum ? out_line[ox].g : 0) + - ((rgbvalacc.g + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].b = (accum ? out_line[ox].b : 0) + - ((rgbvalacc.b + ctx->round) * - (uint64_t)ctx->divmul >> 32); + /* store or accumulate to output row */ + if (accum) + { + rgbvalacc.r += out_line[ox].r; + rgbvalacc.g += out_line[ox].g; + rgbvalacc.b += out_line[ox].b; + } + out_line[ox].r = rgbvalacc.r; + out_line[ox].g = rgbvalacc.g; + out_line[ox].b = rgbvalacc.b; /* reset accumulator */ rgbvalacc.r = 0; rgbvalacc.g = 0; rgbvalacc.b = 0; - mul = bm->width - mul; + mul = ctx->bm->width - mul; ox += 1; /* inside an area */ } else { - /* fill buffer if needed */ - FILL_BUF(part,ctx->store_part,ctx->args); /* add pixel value to accumulator */ rgbvalacc.r += part->buf->red; rgbvalacc.g += part->buf->green; rgbvalacc.b += part->buf->blue; - part->buf++; - part->len--; } +#else + if (oxe >= (unsigned int)ctx->src->width) + { + /* "reset" error, which now represents partial coverage of next + pixel by the next area + */ + oxe -= ctx->src->width; + + /* add saved partial pixel from start of area */ + acc = acc * ctx->bm->width + tmp * mul; + + /* get new pixel , then add its partial coverage to this area */ + tmp = *(part->buf); + mul = ctx->bm->width - oxe; + acc += tmp * mul; + /* round, divide, and either store or accumulate to output row */ + if (accum) + { + acc += out_line[ox]; + } + out_line[ox] = acc; + /* reset accumulator */ + acc = 0; + mul = ctx->bm->width - mul; + ox += 1; + /* inside an area */ + } else { + /* add pixel value to accumulator */ + acc += *(part->buf); + } +#endif + part->buf++; + part->len--; } return true; } /* vertical area average scaler */ -static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool), - struct scaler_context *ctx) +static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx) { - uint32_t mul, divmul, x, oy, iy, oye, round; - int delta = 127, r, g, b; - fb_data *row, *pix; + uint32_t mul, x, oy, iy, oye; /* Set up rounding and scale factors */ - divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1; - round = (src->height + 1) >> 1; + ctx->divisor *= ctx->src->height; + ctx->round = ctx->divisor >> 1; + ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1; mul = 0; - oy = 0; + oy = rset->rowstart; oye = 0; - struct uint32_rgb *rowacc = (struct uint32_rgb *)(ctx->buf), - *rowtmp = rowacc + bm->width; - +#ifdef HAVE_LCD_COLOR + uint32_t *rowacc = (uint32_t *) ctx->buf, + *rowtmp = rowacc + 3 * ctx->bm->width; + memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb)); +#else + uint32_t *rowacc = (uint32_t *) ctx->buf, + *rowtmp = rowacc + ctx->bm->width; + memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t)); +#endif SDEBUGF("scale_v_area\n"); /* zero the accumulator and temp rows */ - memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb)); - row = (fb_data *)(bm->data) + bm->width * rset->rowstart; - for (iy = 0; iy < (unsigned int)src->height; iy++) + for (iy = 0; iy < (unsigned int)ctx->src->height; iy++) { - oye += bm->height; + oye += ctx->bm->height; /* end of current area has been reached */ - if (oye >= (unsigned int)src->height) + if (oye >= (unsigned int)ctx->src->height) { /* "reset" error, which now represents partial coverage of the next row by the next area */ - oye -= src->height; + oye -= ctx->src->height; /* add stored partial row to accumulator */ - for (x = 0; x < 3 *(unsigned int)bm->width; x++) - ((uint32_t*)rowacc)[x] = ((uint32_t*)rowacc)[x] * - bm->height + mul * - ((uint32_t*)rowtmp)[x]; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) +#else + for (x = 0; x < (unsigned int)ctx->bm->width; x++) +#endif + rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x]; /* store new scaled row in temp row */ - if(!h_scaler(bm, src, rowtmp, ctx, false)) + if(!ctx->h_scaler(rowtmp, ctx, false)) return false; /* add partial coverage by new row to this area, then round and scale to final value */ - mul = bm->height - oye; - for (x = 0; x < 3 *(unsigned int)bm->width; x++) - { - ((uint32_t*)rowacc)[x] += mul * ((uint32_t*)rowtmp)[x]; - ((uint32_t*)rowacc)[x] = (round + - ((uint32_t*)rowacc)[x]) * - (uint64_t)divmul >> 32; - } - /* convert to RGB565 in output bitmap */ - pix = row; - for (x = 0; x < (unsigned int)bm->width; x++) - { - if (dither) - delta = dither_mat(x & 0xf, oy & 0xf); - r = PACKRB(rowacc[x].r,delta); - g = PACKG(rowacc[x].g,delta); - b = PACKRB(rowacc[x].b,delta); - *pix++ = LCD_RGBPACK_LCD(r, g, b); - } + mul = ctx->bm->height - oye; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) +#else + for (x = 0; x < (unsigned int)ctx->bm->width; x++) +#endif + rowacc[x] += mul * rowtmp[x]; + ctx->output_row(oy, (void*)rowacc, ctx); /* clear accumulator row, store partial coverage for next row */ - memset((void *)rowacc, 0, bm->width * sizeof(struct uint32_rgb)); +#ifdef HAVE_LCD_COLOR + memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3); +#else + memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t)); +#endif mul = oye; - row += bm->width * rset->rowstep; - oy += 1; + oy += rset->rowstep; /* inside an area */ } else { /* accumulate new scaled row to rowacc */ - if (!h_scaler(bm, src, rowacc, ctx, true)) + if (!ctx->h_scaler(rowacc, ctx, true)) return false; } } @@ -272,53 +323,52 @@ static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, is bm->width - 1, so that the first and last pixels in the row align exactly between input and output */ -static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, - struct scaler_context *ctx) +static inline void scale_h_linear_setup(struct scaler_context *ctx) { - (void) src; - ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1; - ctx->round = bm->width >> 1; + ctx->divisor = ctx->bm->width - 1; } /* horizontal linear scaler */ -static bool scale_h_linear(struct bitmap *bm, struct dim *src, - struct uint32_rgb *out_line, - struct scaler_context *ctx, bool accum) +static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx, + bool accum) { unsigned int ix, ox, ixe; /* type x = x is an ugly hack for hiding an unitialized data warning. The values are conditionally initialized before use, but other values are set such that this will occur before these are used. */ - struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc; +#ifdef HAVE_LCD_COLOR + struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc, + *out_line = (struct uint32_rgb*)out_line_ptr; +#else + uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr; +#endif struct img_part *part; SDEBUGF("scale_h_linear\n"); FILL_BUF_INIT(part,ctx->store_part,ctx->args); ix = 0; /* The error is set so that values are initialized on the first pass. */ - ixe = bm->width - 1; - for (ox = 0; ox < (uint32_t)bm->width; ox++) { - if (ixe >= ((uint32_t)bm->width - 1)) + ixe = ctx->bm->width - 1; + /* give other tasks a chance to run */ + yield(); + for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++) + { +#ifdef HAVE_LCD_COLOR + if (ixe >= ((uint32_t)ctx->bm->width - 1)) { - /* yield once each tick */ - if (ctx->last_tick != current_tick) - { - yield(); - ctx->last_tick = current_tick; - } - /* Store the new "current" pixel value in rgbval, and the color + /* Store the new "current" pixel value in rgbval, and the color step value in rgbinc. */ - ixe -= (bm->width - 1); + ixe -= (ctx->bm->width - 1); rgbinc.r = -(part->buf->red); rgbinc.g = -(part->buf->green); rgbinc.b = -(part->buf->blue); - rgbval.r = (part->buf->red) * (bm->width - 1); - rgbval.g = (part->buf->green) * (bm->width - 1); - rgbval.b = (part->buf->blue) * (bm->width - 1); + rgbval.r = (part->buf->red) * (ctx->bm->width - 1); + rgbval.g = (part->buf->green) * (ctx->bm->width - 1); + rgbval.b = (part->buf->blue) * (ctx->bm->width - 1); ix += 1; /* If this wasn't the last pixel, add the next one to rgbinc. */ - if (ix < (uint32_t)src->width) { + if (ix < (uint32_t)ctx->src->width) { part->buf++; part->len--; /* Fetch new pixels if needed */ @@ -334,448 +384,314 @@ static bool scale_h_linear(struct bitmap *bm, struct dim *src, rgbval.b += rgbinc.b * ixe; } /* Now multiple the color increment to its proper value */ - rgbinc.r *= src->width - 1; - rgbinc.g *= src->width - 1; - rgbinc.b *= src->width - 1; + rgbinc.r *= ctx->src->width - 1; + rgbinc.g *= ctx->src->width - 1; + rgbinc.b *= ctx->src->width - 1; + } else { + rgbval.r += rgbinc.r; + rgbval.g += rgbinc.g; + rgbval.b += rgbinc.b; } /* round and scale values, and accumulate or store to output */ - out_line[ox].r = (accum ? out_line[ox].r : 0) + - ((rgbval.r + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].g = (accum ? out_line[ox].g : 0) + - ((rgbval.g + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].b = (accum ? out_line[ox].b : 0) + - ((rgbval.b + ctx->round) * - (uint64_t)ctx->divmul >> 32); - rgbval.r += rgbinc.r; - rgbval.g += rgbinc.g; - rgbval.b += rgbinc.b; - ixe += src->width - 1; + if (accum) + { + out_line[ox].r += rgbval.r; + out_line[ox].g += rgbval.g; + out_line[ox].b += rgbval.b; + } else { + out_line[ox].r = rgbval.r; + out_line[ox].g = rgbval.g; + out_line[ox].b = rgbval.b; + } +#else + if (ixe >= ((uint32_t)ctx->bm->width - 1)) + { + /* Store the new "current" pixel value in rgbval, and the color + step value in rgbinc. + */ + ixe -= (ctx->bm->width - 1); + val = *(part->buf); + inc = -val; + val *= (ctx->bm->width - 1); + ix += 1; + /* If this wasn't the last pixel, add the next one to rgbinc. */ + if (ix < (uint32_t)ctx->src->width) { + part->buf++; + part->len--; + /* Fetch new pixels if needed */ + FILL_BUF(part,ctx->store_part,ctx->args); + inc += *(part->buf); + /* Add a partial step to rgbval, in this pixel isn't precisely + aligned with the new source pixel + */ + val += inc * ixe; + } + /* Now multiply the color increment to its proper value */ + inc *= ctx->src->width - 1; + } else + val += inc; + /* round and scale values, and accumulate or store to output */ + if (accum) + { + out_line[ox] += val; + } else { + out_line[ox] = val; + } +#endif + ixe += ctx->src->width - 1; } return true; } /* vertical linear scaler */ -static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool), - struct scaler_context *ctx) +static inline bool scale_v_linear(struct rowset *rset, + struct scaler_context *ctx) { - uint32_t mul, divmul, x, oy, iy, iye, round; - int delta = 127; - struct uint32_rgb p; - fb_data *row, *pix; + uint32_t mul, x, iy, iye; + int32_t oy; /* Set up scale and rounding factors, the divisor is bm->height - 1 */ - divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1; - round = bm->height >> 1; - mul = 0; - iy = 0; - iye = bm->height - 1; + ctx->divisor *= (ctx->bm->height - 1); + ctx->round = ctx->divisor >> 1; + ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1; /* Set up our two temp buffers. The names are generic because they'll be swapped each time a new input row is read */ - struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), - *crow2 = crow1 + bm->width, - *t; +#ifdef HAVE_LCD_COLOR + uint32_t *rowinc = (uint32_t *)(ctx->buf), + *rowval = rowinc + 3 * ctx->bm->width, + *rowtmp = rowval + 3 * ctx->bm->width; +#else + uint32_t *rowinc = (uint32_t *)(ctx->buf), + *rowval = rowinc + ctx->bm->width, + *rowtmp = rowval + ctx->bm->width; +#endif SDEBUGF("scale_v_linear\n"); - row = (fb_data *)(bm->data) + bm->width * rset->rowstart; - /* get first scaled row in crow2 */ - if(!h_scaler(bm, src, crow2, ctx, false)) + mul = 0; + iy = 0; + iye = ctx->bm->height - 1; + /* get first scaled row in rowtmp */ + if(!ctx->h_scaler((void*)rowtmp, ctx, false)) return false; - for (oy = 0; oy < (uint32_t)bm->height; oy++) + for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep) { - if (iye >= (uint32_t)bm->height - 1) + if (iye >= (uint32_t)ctx->bm->height - 1) { - /* swap temp rows, then read another row into crow2 */ - t = crow2; - crow2 = crow1; - crow1 = t; - iye -= bm->height - 1; + iye -= ctx->bm->height - 1; iy += 1; - if (iy < (uint32_t)src->height) +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif { - if (!h_scaler(bm, src, crow2, ctx, false)) - return false; + rowinc[x] = -rowtmp[x]; + rowval[x] = rowtmp[x] * (ctx->bm->height - 1); } - } - pix = row; - for (x = 0; x < (uint32_t)bm->width; x++) - { - /* iye and bm-height - 1 - iye represent the contribution of each - row to the output. Calculate their weighted sum, then round and - scale it. - */ - p.r = (crow1[x].r * (bm->height - 1 - iye) + - crow2[x].r * iye + round) * (uint64_t)divmul >> 32; - p.g = (crow1[x].g * (bm->height - 1 - iye) + - crow2[x].g * iye + round) * (uint64_t)divmul >> 32; - p.b = (crow1[x].b * (bm->height - 1 - iye) + - crow2[x].b * iye + round) * (uint64_t)divmul >> 32; - /* dither and pack pixels to output */ - if (dither) - delta = dither_mat(x & 0xf, oy & 0xf); - p.r = PACKRB(p.r,delta); - p.g = PACKG(p.g,delta); - p.b = PACKRB(p.b,delta); - *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b); - } - row += bm->width * rset->rowstep; - iye += src->height - 1; + if (iy < (uint32_t)ctx->src->height) + { + if (!ctx->h_scaler((void*)rowtmp, ctx, false)) + return false; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif + { + rowinc[x] += rowtmp[x]; + rowval[x] += rowinc[x] * iye; + rowinc[x] *= ctx->src->height - 1; + } + } + } else +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif + rowval[x] += rowinc[x]; + ctx->output_row(oy, (void*)rowval, ctx); + iye += ctx->src->height - 1; } return true; } #endif /* HAVE_UPSCALER */ -#endif /* HAVE_LCD_COLOR */ -/* docs for this are still TODO, but it's Bresenham's again, used to skip or - repeat input pixels, and with the *ls values being used for "long steps" - that skip all the way, or nearly all the way, to the next transition of - the associated value. -*/ -#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8) -/* nearest-neighbor up/down/non-scaler */ -static inline bool scale_nearest(struct bitmap *bm, - struct dim *src, - struct rowset *rset, - bool remote, bool dither, - struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int), - void *args) +void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx) { + int col; + int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0); + uint8_t dy = DITHERY(row); +#ifdef HAVE_LCD_COLOR + struct uint32_rgb *qp = (struct uint32_rgb*)row_in; +#else + uint32_t *qp = (uint32_t*)row_in; +#endif + SDEBUGF("output_row: y: %d in: %p\n",row, row_in); +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + /* greyscale iPods */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; + int shift = 6; + int delta = 127; + unsigned bright; + unsigned data = 0; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + data |= (~bright & 3) << shift; + shift -= 2; + if (shift < 0) { + *dest++ = data; + data = 0; + shift = 6; + } + } + if (shift < 6) + *dest++ = data; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * + (row >> 2); + int shift = 2 * (row & 3); + int delta = 127; + unsigned bright; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= (~bright & 3) << shift; + } +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + /* iAudio M3 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * + (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + /* iriver h300, colour iPods, X5 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; + int delta = 127; + unsigned r, g, b; + struct uint32_rgb q0; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + q0 = *qp++; + r = (q0.r + ctx->round) * (uint64_t)ctx->divisor >> 32; + g = (q0.g + ctx->round) * (uint64_t)ctx->divisor >> 32; + b = (q0.b + ctx->round) * (uint64_t)ctx->divisor >> 32; + r = (31 * r + (r >> 3) + delta) >> 8; + g = (63 * g + (g >> 2) + delta) >> 8; + b = (31 * b + (b >> 3) + delta) >> 8; + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } +#endif /* LCD_DEPTH */ +} + +int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, unsigned char *buf, unsigned int len, + struct img_part* (*store_part)(void *args), + void *args) +{ + +#ifdef HAVE_UPSCALER const int sw = src->width; const int sh = src->height; const int dw = bm->width; const int dh = bm->height; - unsigned char *bitmap = bm->data; - const int rowstep = rset->rowstep; - const int rowstart = rset->rowstart; - const int rowstop = rset->rowstop; - const int fb_width = get_fb_width(bm, false); - long last_tick = current_tick; - /* yet/oyt will always be initialized before use, since they are set in the - inside loop, and not used elsewhere until the end of the outside loop. - */ - int ix, ox, lx, xe, iy, oy, ly, ye, yet = yet, oyt = oyt; - int xelim, ixls, xels, yelim, iyls, yels, p; - struct img_part *cur_part; -#ifndef HAVE_LCD_COLOR - fb_data *dest = dest, *dest_t; #endif -#ifdef HAVE_REMOTE_LCD - fb_remote_data *rdest = rdest, *rdest_t; -#endif - - SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw, - dh, remote); - ly = 0; - iy = 0; - ye = 0; - xelim = sw == dw - 1 ? dw : dw - 1; - ixls = xelim ? sw / xelim : 1; - xels = sw - ixls * (xelim ? xelim : 1); - yelim = sh == dh - 1 ? dh : dh - 1; - iyls = yelim ? sh / yelim : 1; - yels = iyls * (yelim ? yelim : 1); - int delta = 127; -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \ - (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING) - uint8_t buf[4]; - int data, oxt; -#endif -#if LCD_PIXELFORMAT == VERTICAL_PACKING || \ - LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \ - (defined(HAVE_REMOTE_LCD) && \ - (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \ - LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING)) - int bright, shift; -#endif - for (oy = rowstart; oy != rowstop;) { - SDEBUGF("oy=%d iy=%d\n", oy, iy); - if (last_tick != current_tick) - { - yield(); - last_tick = current_tick; - } - if (iy > ly && !skip_lines(args, iy - ly - 1)) - return false; - ly = iy; - - cur_part = store_part(args); - if (cur_part == NULL) - return false; - - lx = 0; - ix = 0; - xe = 0; -#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) - if(!remote) + int ret; +#ifdef HAVE_LCD_COLOR + unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width; #else - (void)remote; + unsigned int needed = sizeof(uint32_t) * 3 * bm->width; #endif -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dest = (fb_data *)bitmap + fb_width * oy; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dest = (fb_data *)bitmap + fb_width * (oy >> 2); -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dest = (fb_data *)bitmap + fb_width * (oy >> 3); +#if MAX_SC_STACK_ALLOC + uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? + 0 : needed]; #endif -#ifdef HAVE_REMOTE_LCD -#ifndef HAVE_LCD_COLOR - else -#endif - rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3); -#endif - for (ox = 0; ox < dw; ox++) { - while (cur_part->len <= ix - lx) - { - lx += cur_part->len; - cur_part = store_part(args); - if (cur_part == NULL) - return false; - } - cur_part->len -= ix - lx; - cur_part->buf += ix - lx; - lx = ix; -#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) - if(!remote) - { -#endif -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - /* greyscale iPods */ - buf[ox & 3] = brightness(*(cur_part->buf)); - if ((ox & 3) == 3 || ox == dw - 1) - { - dest_t = dest++; - oyt = oy; - yet = ye; - int xo = ox & ~3; - while(yet < dh) - { - data = 0; - for (oxt = 0; oxt < (ox & 3) + 1; oxt++) - { - if (dither) - delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf); - p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8; - data |= (~p & 3) << ((3 - oxt) << 1); - } - *dest_t = data; - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } - } -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - /* iriver H1x0 */ - bright = brightness(*(cur_part->buf)); - dest_t = dest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = (oyt & 3) << 1; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *dest_t |= (~p & 3) << shift; - if ((rowstep > 0 && shift == 6) || shift == 0) - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - bright = brightness(*(cur_part->buf)); - dest_t = dest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *dest_t |= vi_pat(p) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#endif /* LCD_PIXELFORMAT */ -#ifdef HAVE_REMOTE_LCD -#ifndef HAVE_LCD_COLOR - } else -#endif - { -#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED - bright = brightness(*(cur_part->buf)); - rdest_t = rdest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *rdest_t |= vi_pat(p) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - rdest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#else - bright = brightness(*(cur_part->buf)); - rdest_t = rdest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - p = (bright + delta) >> 8; - *rdest_t |= (~p & 1) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - rdest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#endif - } -#endif - xe += xels; - ix += ixls; - while (xe > xelim) - { - xe -= xelim; - ix += 1; - } - } - oy = oyt; - ye = yet - yels; - iy += iyls; - while (ye > yelim) + len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, + sizeof(uint32_t)); + if (needed > len) + { +#if MAX_SC_STACK_ALLOC + if (needed > MAX_SC_STACK_ALLOC) { - ye -= yelim; - iy += 1; + DEBUGF("unable to allocate required buffer: %d needed, " + "%d available, %d permitted from stack\n", + needed, len, MAX_SC_STACK_ALLOC); + return 0; } + if (sizeof(sc_buf) < needed) + { + DEBUGF("failed to allocate large enough buffer on stack: " + "%d needed, only got %d", + needed, MAX_SC_STACK_ALLOC); + return 0; + } +#else + DEBUGF("unable to allocate required buffer: %d needed, " + "%d available\n", needed, len); + return 0; +#endif } - return true; -} -#endif -int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, bool remote, -#ifdef HAVE_LCD_COLOR - unsigned char *buf, unsigned int len, -#endif - struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int lines), - void *args) -{ - -#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD) - (void)skip_lines; -#endif -#ifdef HAVE_LCD_COLOR -#ifdef HAVE_REMOTE_LCD - if (!remote) -#endif - { -#ifdef HAVE_UPSCALER - const int sw = src->width; - const int sh = src->height; - const int dw = bm->width; - const int dh = bm->height; -#endif - int ret; - unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width; + struct scaler_context ctx; + cpu_boost(true); + ctx.store_part = store_part; + ctx.args = args; #if MAX_SC_STACK_ALLOC - uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? - 0 : needed]; - if (len && buf) -#endif - len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, - sizeof(uint32_t)); - if (needed > len) - { -#if MAX_SC_STACK_ALLOC - if (needed > MAX_SC_STACK_ALLOC) - { - DEBUGF("unable to allocate required buffer: %d needed, " - "%d available, %d permitted from stack\n", - needed, len, MAX_SC_STACK_ALLOC); - return 0; - } - if (sizeof(sc_buf) < needed) - { - DEBUGF("failed to allocate large enough buffer on stack: " - "%d needed, only got %d", - needed, MAX_SC_STACK_ALLOC); - return 0; - } + ctx.buf = needed > len ? sc_buf : buf; #else - DEBUGF("unable to allocate required buffer: %d needed, " - "%d available\n", needed, len); - return 0; + ctx.buf = buf; #endif - } - - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool); - struct scaler_context ctx; - ctx.last_tick = current_tick; - cpu_boost(true); + ctx.len = len; + ctx.bm = bm; + ctx.src = src; + ctx.dither = dither; + ctx.output_row = output_row_native; #ifdef HAVE_UPSCALER - if (sw > dw) - { + if (sw > dw) + { #endif - h_scaler = scale_h_area; - scale_h_area_setup(bm, src, &ctx); + ctx.h_scaler = scale_h_area; + scale_h_area_setup(&ctx); #ifdef HAVE_UPSCALER - } else { - h_scaler = scale_h_linear; - scale_h_linear_setup(bm, src, &ctx); - } + } else { + ctx.h_scaler = scale_h_linear; + scale_h_linear_setup(&ctx); + } #endif - ctx.store_part = store_part; - ctx.args = args; -#if MAX_SC_STACK_ALLOC - ctx.buf = needed > len ? sc_buf : buf; -#else - ctx.buf = buf; -#endif - ctx.len = len; #ifdef HAVE_UPSCALER - if (sh > dh) + if (sh > dh) #endif - ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx); + ret = scale_v_area(rset, &ctx); #ifdef HAVE_UPSCALER - else - ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx); + else + ret = scale_v_linear(rset, &ctx); #endif - cpu_boost(false); - if (!ret) - return 0; - } -#ifdef HAVE_REMOTE_LCD - else -#endif -#endif /* HAVE_LCD_COLOR */ -#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD) - { - if (!scale_nearest(bm, src, rset, remote, dither, store_part, - skip_lines, args)) - return 0; - } -#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/ - return get_totalsize(bm, remote); + cpu_boost(false); + if (!ret) + return 0; + return BM_SIZE(bm->width,bm->height,bm->format,0); } diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h index 8a39db503a..451830742e 100644 --- a/apps/recorder/resize.h +++ b/apps/recorder/resize.h @@ -23,6 +23,7 @@ #include "config.h" #include "lcd.h" +#include "inttypes.h" /**************************************************************** * resize_on_load() @@ -45,16 +46,30 @@ struct img_part { int len; +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + uint8_t *buf; +#else struct uint8_rgb* buf; +#endif }; -int resize_on_load(struct bitmap *bm, bool dither, - struct dim *src, - struct rowset *tmp_row, bool remote, #ifdef HAVE_LCD_COLOR - unsigned char *buf, unsigned int len, +/* intermediate type used by the scaler for color output. greyscale version + uses uint32_t +*/ +struct uint32_rgb { + uint32_t r; + uint32_t g; + uint32_t b; +}; #endif + +int recalc_dimension(struct dim *dst, struct dim *src); + +int resize_on_load(struct bitmap *bm, bool dither, + struct dim *src, struct rowset *tmp_row, + unsigned char *buf, unsigned int len, struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int lines), void *args); #endif /* _RESIZE_H_ */ diff --git a/firmware/export/lcd-remote.h b/firmware/export/lcd-remote.h index 3c013d657a..01df5a7eab 100644 --- a/firmware/export/lcd-remote.h +++ b/firmware/export/lcd-remote.h @@ -48,13 +48,17 @@ int remote_type(void); #if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \ || (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED) typedef unsigned short fb_remote_data; +#define FB_RDATA_SZ 2 #else typedef unsigned char fb_remote_data; +#define FB_RDATA_SZ 1 #endif #elif LCD_DEPTH <= 16 typedef unsigned short fb_remote_data; +#define FB_RDATA_SZ 2 #else typedef unsigned long fb_remote_data; +#define FB_RDATA_SZ 4 #endif /* common functions */ diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index ea5851e736..e435d174f2 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -75,13 +75,17 @@ struct viewport { #if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \ || (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED) typedef unsigned short fb_data; +#define FB_DATA_SZ 2 #else typedef unsigned char fb_data; +#define FB_DATA_SZ 1 #endif #elif LCD_DEPTH <= 16 typedef unsigned short fb_data; +#define FB_DATA_SZ 2 #else /* LCD_DEPTH > 16 */ typedef unsigned long fb_data; +#define FB_DATA_SZ 4 #endif /* LCD_DEPTH */ #else /* LCD_CHARCELLS */