Split 8-bit-to-native conversion in bmp.c into a function, add support for plugging unscaled output in BMP and JPEG loaders, use output_row_8_native in JPEG decoder when possible.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20884 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/plugins/bench_mem_jpeg.c b/apps/plugins/bench_mem_jpeg.c
index 958e520..cd7dea3 100644
--- a/apps/plugins/bench_mem_jpeg.c
+++ b/apps/plugins/bench_mem_jpeg.c
@@ -42,13 +42,14 @@
 }
 
 const struct custom_format format_null = {
+    .output_row_8 = output_row_null,
 #ifdef HAVE_LCD_COLOR
-    .output_row = {
+    .output_row_32 = {
         output_row_null,
         output_row_null
     },
 #else
-    .output_row = output_row_null,
+    .output_row_32 = output_row_null,
 #endif
     .get_size = get_size_null
 };
diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c
index 65f2211..6315ad9 100644
--- a/apps/plugins/lib/grey_draw.c
+++ b/apps/plugins/lib/grey_draw.c
@@ -719,7 +719,15 @@
     grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
 }
 
-static void output_row_grey(uint32_t row, void * row_in, struct scaler_context *ctx)
+static void output_row_grey_8(uint32_t row, void * row_in,
+                              struct scaler_context *ctx)
+{
+    uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
+    rb->memcpy(dest, row_in, ctx->bm->width);
+}
+
+static void output_row_grey_32(uint32_t row, void * row_in,
+                               struct scaler_context *ctx)
 {
     int col;
     uint32_t *qp = (uint32_t*)row_in;
@@ -734,6 +742,7 @@
 }
 
 const struct custom_format format_grey = {
-    .output_row = output_row_grey,
+    .output_row_8 = output_row_grey_8,
+    .output_row_32 = output_row_grey_32,
     .get_size = get_size_grey
 };
diff --git a/apps/plugins/lib/pluginlib_bmp.c b/apps/plugins/lib/pluginlib_bmp.c
index 110e534..6b1a542 100644
--- a/apps/plugins/lib/pluginlib_bmp.c
+++ b/apps/plugins/lib/pluginlib_bmp.c
@@ -124,14 +124,7 @@
 
 #endif /* LCD_DEPTH > 1 */
 
-#ifndef HAVE_BMP_SCALING
 #include "wrappers.h"
 
 /* import the core bmp loader */
 #include "recorder/bmp.c"
-#else
-/* 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
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index 82dc974..6dd034c 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -607,7 +607,29 @@
 
 #define SCALE_VAL(val,out) div255((val) * (out) + 127)
 
-static void output_row_transposed(uint32_t row, void * row_in,
+static void output_row_8_transposed(uint32_t row, void * row_in,
+                                       struct scaler_context *ctx)
+{
+    pix_t *dest = (pix_t*)ctx->bm->data + row;
+    pix_t *end = dest + ctx->bm->height * ctx->bm->width;
+#ifdef USEGSLIB
+    uint8_t *qp = (uint8_t*)row_in;
+    for (; dest < end; dest += ctx->bm->height)
+        *dest = *qp++;
+#else
+    struct uint8_rgb *qp = (struct uint8_rgb*)row_in;
+    unsigned r, g, b;
+    for (; dest < end; dest += ctx->bm->height)
+    {
+        r = qp->red;
+        g = qp->green;
+        b = (qp++)->blue;
+        *dest = LCD_RGBPACK_LCD(r,g,b);
+    }
+#endif
+}
+
+static void output_row_32_transposed(uint32_t row, void * row_in,
                                        struct scaler_context *ctx)
 {
     pix_t *dest = (pix_t*)ctx->bm->data + row;
@@ -635,7 +657,7 @@
 }
 
 #ifdef HAVE_LCD_COLOR
-static void output_row_transposed_fromyuv(uint32_t row, void * row_in,
+static void output_row_32_transposed_fromyuv(uint32_t row, void * row_in,
                                        struct scaler_context *ctx)
 {
     pix_t *dest = (pix_t*)ctx->bm->data + row;
@@ -663,13 +685,14 @@
 }
 
 const struct custom_format format_transposed = {
+    .output_row_8 = output_row_8_transposed,
 #ifdef HAVE_LCD_COLOR
-    .output_row = {
-        output_row_transposed,
-        output_row_transposed_fromyuv
+    .output_row_32 = {
+        output_row_32_transposed,
+        output_row_32_transposed_fromyuv
     },
 #else
-    .output_row = output_row_transposed,
+    .output_row_32 = output_row_32_transposed,
 #endif
     .get_size = get_size
 };
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index f1fc1f8..4897b2d 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -351,6 +351,93 @@
     else
         return 1;
 }
+#if LCD_DEPTH > 1
+void output_row_8_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 uint8_rgb *qp = (struct uint8_rgb*)row_in;
+#else
+    uint8_t *qp = (uint8_t*)row_in;
+#endif
+    BDEBUGF("output_row: y: %lu 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++;
+                    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++;
+                    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++;
+                    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;
+                for (col = 0; col < ctx->bm->width; col++) {
+                    if (ctx->dither)
+                        delta = DITHERXDY(col,dy);
+                    r = qp->red;
+                    g = qp->green;
+                    b = (qp++)->blue;
+                    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 */
+}
+#endif
 
 /******************************************************************************
  * read_bmp_fd()
@@ -598,7 +685,7 @@
 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
     defined(HAVE_BMP_SCALING) || defined(PLUGIN)
 #if LCD_DEPTH > 1 && defined(HAVE_BMP_SCALING)
-    if (resize || cformat)
+    if (resize)
 #endif
     {
         if (resize_on_load(bm, dither, &src_dim, &rset,
@@ -610,31 +697,43 @@
     }
 #endif /* LCD_DEPTH */
 
-#ifndef PLUGIN
-#if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
-    int fb_width = BM_WIDTH(bm->width,bm->format,remote);
+#if LCD_DEPTH > 1 || defined(PLUGIN)
+    struct scaler_context ctx = {
+        .bm = bm,
+        .dither = dither,
+    };
 #endif
-    int col, row;
+#if LCD_DEPTH > 1
+    void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
+        output_row_8_native;
+#elif defined(PLUGIN)
+    void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
+#endif
+#if LCD_DEPTH > 1 || defined(PLUGIN)
+    if (cformat)
+        output_row_8 = cformat->output_row_8;
+#endif
 
+    int row;
     /* loop to read rows and put them to buffer */
     for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
+        if (!read_part_line(&ba))
+            return -9;
+#ifndef PLUGIN
 #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 (!read_part_line(&ba))
-           return -9;
-
+#endif
         /* Convert to destination format */
-#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
-        unsigned char dy = DITHERY(row);
+#if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
+    !defined(PLUGIN)
         if (format == FORMAT_NATIVE) {
 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
             if (remote) {
+                unsigned char dy = DITHERY(row);
 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
                 /* iAudio X5/M5 remote */
                 fb_remote_data *dest = (fb_remote_data *)bitmap
@@ -643,6 +742,7 @@
                 int delta = 127;
                 unsigned bright;
 
+                int col;
                 for (col = 0; col < bm->width; col++) {
                     if (dither)
                         delta = DITHERXDY(col,dy);
@@ -658,85 +758,25 @@
 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
             } else
 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
+#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
+    (LCD_REMOTE_DEPTH > 1) */
+#if LCD_DEPTH > 1 || defined(PLUGIN)
             {
-#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;
-                    }
-                }
-                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 */
+                output_row_8(row, ba.buf, &ctx);
             }
-        } else
-#endif /* (LCD_DEPTH > 1) ||
-          defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
+#endif
+#if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
+    !defined(PLUGIN)
+        }
+#ifndef PLUGIN
+        else
+#endif
+#endif
+#ifndef PLUGIN
         {
-            p = bitmap + bm->width * (row >> 3);
-            mask = 1 << (row & 7);
-
+            unsigned char *p = bitmap + bm->width * (row >> 3);
+            unsigned char mask = 1 << (row & 7);
+            int col;
             for (col = 0; col < bm->width; col++, p++)
 #if !defined(HAVE_LCD_COLOR) && \
         (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
@@ -747,7 +787,7 @@
                     *p |= mask;
 #endif
         }
+#endif
     }
     return totalsize; /* return the used buffer size. */
-#endif
 }
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h
index c570a3d..6437e42 100644
--- a/apps/recorder/bmp.h
+++ b/apps/recorder/bmp.h
@@ -212,4 +212,8 @@
                 int format,
                 const struct custom_format *cformat);
 
+#if LCD_DEPTH > 1
+void output_row_8_native(uint32_t row, void * row_in,
+                         struct scaler_context *ctx);
+#endif
 #endif
diff --git a/apps/recorder/jpeg_load.c b/apps/recorder/jpeg_load.c
index 555f60d..9393e60 100644
--- a/apps/recorder/jpeg_load.c
+++ b/apps/recorder/jpeg_load.c
@@ -109,6 +109,7 @@
     int tab_membership[6];
     int subsample_x[3]; /* info per component */
     int subsample_y[3];
+    bool resize;
     unsigned char buf[JPEG_READ_BUF_SIZE];
     struct img_part part;
 };
@@ -2025,14 +2026,15 @@
             recalc_dimension(&resize_dim, &src_dim);
         bm->width = resize_dim.width;
         bm->height = resize_dim.height;
-        if (bm->width == src_dim.width && bm->height == src_dim.height)
-            resize = false;
     } else {
         bm->width = p_jpeg->x_size;
         bm->height = p_jpeg->y_size;
     }
     p_jpeg->h_scale[0] = calc_scale(p_jpeg->x_size, bm->width);
     p_jpeg->v_scale[0] = calc_scale(p_jpeg->y_size, bm->height);
+    if ((p_jpeg->x_size << p_jpeg->h_scale[0]) >> 3 &&
+        (p_jpeg->y_size << p_jpeg->v_scale[0]) >> 3)
+        resize = false;
 #ifdef HAVE_LCD_COLOR
     p_jpeg->h_scale[1] = p_jpeg->h_scale[0] +
         p_jpeg->frameheader[0].horizontal_sampling - 1;
@@ -2092,11 +2094,54 @@
     rset.rowstart = 0;
     rset.rowstop = bm->height;
     rset.rowstep = 1;
-    if (resize_on_load(bm, dither, &src_dim, &rset, buf_start, maxsize, cformat,
-        IF_PIX_FMT(p_jpeg->blocks == 1 ? 0 : 1,) store_row_jpeg, p_jpeg))
+    p_jpeg->resize = resize;
+    if (resize)
+    {
+        if (resize_on_load(bm, dither, &src_dim, &rset, buf_start, maxsize,
+            cformat, IF_PIX_FMT(p_jpeg->blocks == 1 ? 0 : 1,) store_row_jpeg,
+            p_jpeg))
+            return bm_size;
+    } else {
+        int row;
+        struct scaler_context ctx = {
+            .bm = bm,
+            .dither = dither,
+        };
+#if LCD_DEPTH > 1
+        void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
+            output_row_8_native;
+#elif defined(PLUGIN)
+        void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
+#endif
+#if LCD_DEPTH > 1 || defined(PLUGIN)
+        if (cformat)
+            output_row_8 = cformat->output_row_8;
+#endif
+        struct img_part *part;
+        for (row = 0; row < bm->height; row++)
+        {
+            part = store_row_jpeg(p_jpeg);
+#ifdef HAVE_LCD_COLOR
+            struct uint8_rgb *qp = part->buf;
+            struct uint8_rgb *end = qp + bm->width;
+            uint8_t y, u, v;
+            unsigned r, g, b;
+            for (; qp < end; qp++)
+            {
+                y = qp->blue;
+                u = qp->green;
+                v = qp->red;
+                yuv_to_rgb(y, u, v, &r, &g, &b);
+                qp->red = r;
+                qp->blue = b;
+                qp->green = g;
+            }
+#endif
+            output_row_8(row, part->buf, &ctx);
+        }
         return bm_size;
-    else
-        return 0;
+    }
+    return 0;
 }
 
 /**************** end JPEG code ********************/
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index 5ecb5c2..1e9210e 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -518,7 +518,7 @@
 #endif /* HAVE_UPSCALER */
 
 #if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
-void output_row_native_fromyuv(uint32_t row, void * row_in,
+static void output_row_32_native_fromyuv(uint32_t row, void * row_in,
                                struct scaler_context *ctx)
 {
     int col;
@@ -547,7 +547,7 @@
 #endif
 
 #if !defined(PLUGIN) || LCD_DEPTH > 1
-void output_row_native(uint32_t row, void * row_in,
+static void output_row_32_native(uint32_t row, void * row_in,
                               struct scaler_context *ctx)
 {
     int col;
@@ -644,13 +644,14 @@
 }
 
 const struct custom_format format_native = {
+    .output_row_8 = output_row_8_native,
 #if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
-    .output_row = {
-        output_row_native,
-        output_row_native_fromyuv
+    .output_row_32 = {
+        output_row_32_native,
+        output_row_32_native_fromyuv
     },
 #else
-    .output_row = output_row_native,
+    .output_row_32 = output_row_32_native,
 #endif
     .get_size = get_size_native
 };
@@ -722,17 +723,17 @@
     ctx.dither = dither;
 #if !defined(PLUGIN)
 #if defined(HAVE_LCD_COLOR) && defined(HAVE_JPEG)
-    ctx.output_row = format_index ? output_row_native_fromyuv
-                                  : output_row_native;
+    ctx.output_row = format_index ? output_row_32_native_fromyuv
+                                  : output_row_32_native;
 #else
-    ctx.output_row = output_row_native;
+    ctx.output_row = output_row_32_native;
 #endif
     if (format)
 #endif
 #if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
-        ctx.output_row = format->output_row[format_index];
+        ctx.output_row = format->output_row_32[format_index];
 #else
-        ctx.output_row = format->output_row;
+        ctx.output_row = format->output_row_32;
 #endif
 #ifdef HAVE_UPSCALER
     if (sw > dw)
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h
index f7cda15..2964fcd 100644
--- a/apps/recorder/resize.h
+++ b/apps/recorder/resize.h
@@ -150,19 +150,17 @@
 #endif
 
 struct custom_format {
+    void (*output_row_8)(uint32_t,void*, struct scaler_context*);
 #if defined(HAVE_LCD_COLOR)
-    void (*output_row[2])(uint32_t,void*,struct scaler_context*);
+    void (*output_row_32[2])(uint32_t,void*, struct scaler_context*);
 #else
-    void (*output_row)(uint32_t,void*,struct scaler_context*);
+    void (*output_row_32)(uint32_t,void*, struct scaler_context*);
 #endif
     unsigned int (*get_size)(struct bitmap *bm);
 };
 
 struct rowset;
 
-void output_row_native(uint32_t row, void * row_in,
-                              struct scaler_context *ctx);
-
 extern const struct custom_format format_native;
 
 int recalc_dimension(struct dim *dst, struct dim *src);