From a1842c04f9cb73210d4cacde61a9e4b115050765 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 18 Jun 2014 07:15:00 +0200 Subject: lcd-24bit: Introduce a 24-bit mid-level LCD driver With LCD driver all calculation will be performed on RGB888 and the hardware/OS can display from our 24bit framebuffer. It is not yet as performance optimized as the existing drivers but should be good enough.The vast number of small changes is due to the fact that fb_data can be a struct type now, while most of the code expected a scalar type. lcd-as-memframe ASM code does not work with 24bit currently so the with 24bit it enforces the generic C code. All plugins are ported over. Except for rockpaint. It uses so much memory that it wouldnt fit into the 512k plugin buffer anymore (patches welcome). Change-Id: Ibb1964545028ce0d8ff9833ccc3ab66be3ee0754 --- firmware/SOURCES | 2 + firmware/asm/SOURCES | 4 + firmware/asm/lcd-as-memframe-24bit.c | 3 + firmware/asm/lcd-as-memframe.c | 8 +- firmware/drivers/lcd-24bit.c | 1129 +++++++++++++++++++++++++++++++ firmware/drivers/lcd-color-common.c | 8 +- firmware/export/config.h | 1 + firmware/export/config/samsungypr0.h | 2 +- firmware/export/config/samsungypr1.h | 4 +- firmware/export/config/sansae200v2.h | 4 +- firmware/export/config/sdlapp.h | 4 +- firmware/export/lcd.h | 85 ++- firmware/screendump.c | 14 + firmware/target/hosted/sdl/lcd-bitmap.c | 4 +- 14 files changed, 1255 insertions(+), 17 deletions(-) create mode 100644 firmware/asm/lcd-as-memframe-24bit.c create mode 100644 firmware/drivers/lcd-24bit.c (limited to 'firmware') diff --git a/firmware/SOURCES b/firmware/SOURCES index ef71a2b048..b8471dc37d 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -218,6 +218,8 @@ drivers/lcd-16bit-vert.c #else drivers/lcd-16bit.c #endif +#elif LCD_DEPTH == 24 +drivers/lcd-24bit.c #endif /* LCD_DEPTH */ common/diacritic.c #endif /* HAVE_LCD_BITMAP */ diff --git a/firmware/asm/SOURCES b/firmware/asm/SOURCES index 0cd351efdd..d74d4d3c60 100644 --- a/firmware/asm/SOURCES +++ b/firmware/asm/SOURCES @@ -12,5 +12,9 @@ strlen.c defined(COWON_D2) || defined(MINI2440) || defined(SAMSUNG_YPR0) || \ defined(SAMSUNG_YPR1) || (defined(MROBE_500) && !defined(LCD_USE_DMA))) && \ !defined(SIMULATOR) +#if LCD_DEPTH == 24 +lcd-as-memframe-24bit.c +#else lcd-as-memframe.c #endif +#endif diff --git a/firmware/asm/lcd-as-memframe-24bit.c b/firmware/asm/lcd-as-memframe-24bit.c new file mode 100644 index 0000000000..2cca575799 --- /dev/null +++ b/firmware/asm/lcd-as-memframe-24bit.c @@ -0,0 +1,3 @@ + +/* The ASM version of lcd-as-memframe.c isn't 24bit capable */ +#include "lcd-as-memframe.c" diff --git a/firmware/asm/lcd-as-memframe.c b/firmware/asm/lcd-as-memframe.c index 5f4917b721..032022d7ec 100644 --- a/firmware/asm/lcd-as-memframe.c +++ b/firmware/asm/lcd-as-memframe.c @@ -78,7 +78,7 @@ extern void lcd_write_yuv420_lines(fb_data *dst, b = clamp(b, 0, 64*256-1); } - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -98,7 +98,7 @@ extern void lcd_write_yuv420_lines(fb_data *dst, b = clamp(b, 0, 64*256-1); } - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -143,7 +143,7 @@ extern void lcd_write_yuv420_lines(fb_data *dst, b = clamp(b, 0, 64*256-1); } - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -163,7 +163,7 @@ extern void lcd_write_yuv420_lines(fb_data *dst, b = clamp(b, 0, 64*256-1); } - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); #if LCD_WIDTH >= LCD_HEIGHT dst++; diff --git a/firmware/drivers/lcd-24bit.c b/firmware/drivers/lcd-24bit.c new file mode 100644 index 0000000000..f87d63aaa3 --- /dev/null +++ b/firmware/drivers/lcd-24bit.c @@ -0,0 +1,1129 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * Copyright (C) 2009 by Karl Kurbjun + * + * Rockbox driver for 16-bit colour LCDs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "config.h" + +#include "cpu.h" +#include "lcd.h" +#include "kernel.h" +#include "thread.h" +#include +#include "string-extra.h" /* mem*() */ +#include "file.h" +#include "debug.h" +#include "system.h" +#include "font.h" +#include "rbunicode.h" +#include "bidi.h" +#include "scroll_engine.h" + +#define ROW_INC LCD_WIDTH +#define COL_INC 1 + +extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[]; +extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[]; + +static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, + const unsigned char *src, int src_x, + int src_y, int x, int y, + int width, int height, + int stride_image, int stride_src); + +#include "lcd-color-common.c" +#include "lcd-bitmap-common.c" + + +/* Clear the current viewport */ +void lcd_clear_viewport(void) +{ + fb_data *dst, *dst_end; + int x, y, width, height; + int len, step; + + x = current_vp->x; + y = current_vp->y; + width = current_vp->width; + height = current_vp->height; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + len = STRIDE_MAIN(width, height); + step = STRIDE_MAIN(ROW_INC, COL_INC); + + dst = FBADDR(x, y); + dst_end = FBADDR(x + width - 1 , y + height - 1); + + if (current_vp->drawmode & DRMODE_INVERSEVID) + { + fb_data px = FB_SCALARPACK(current_vp->fg_pattern); + do + { + fb_data *end = dst + len; + do { + *dst++ = px; + } while (dst < end); + dst += step - len; + } + while (dst <= dst_end); + } + else + { + if (!lcd_backdrop) + { + fb_data px = FB_SCALARPACK(current_vp->bg_pattern); + do + { + fb_data *end = dst + len; + do { + *dst++ = px; + } while (dst < end); + dst += step - len; + } + while (dst <= dst_end); + } + else + { + do + { + memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), + len * sizeof(fb_data)); + dst += step; + } + while (dst <= dst_end); + } + } + + if (current_vp == &default_vp) + lcd_scroll_stop(); + else + lcd_scroll_stop_viewport(current_vp); +} + +/*** low-level drawing functions ***/ + +static void ICODE_ATTR setpixel(fb_data *address) +{ + *address = FB_SCALARPACK(current_vp->fg_pattern); +} + +static void ICODE_ATTR clearpixel(fb_data *address) +{ + *address = FB_SCALARPACK(current_vp->bg_pattern); +} + +static void ICODE_ATTR clearimgpixel(fb_data *address) +{ + *address = *(fb_data *)((long)address + lcd_backdrop_offset); +} + +static void ICODE_ATTR flippixel(fb_data *address) +{ + unsigned px = FB_UNPACK_SCALAR_LCD(*address); + *address = FB_SCALARPACK(~px); +} + +static void ICODE_ATTR nopixel(fb_data *address) +{ + (void)address; +} + +lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[8] = { + flippixel, nopixel, setpixel, setpixel, + nopixel, clearpixel, nopixel, clearpixel +}; + +lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = { + flippixel, nopixel, setpixel, setpixel, + nopixel, clearimgpixel, nopixel, clearimgpixel +}; + +lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; + +/* Fill a rectangular area */ +void lcd_fillrect(int x, int y, int width, int height) +{ + enum fill_opt fillopt = OPT_NONE; + fb_data *dst, *dst_end; + int len, step; + fb_data bits = { 0 }; + + /******************** In viewport clipping **********************/ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + /* drawmode and optimisation */ + if (current_vp->drawmode & DRMODE_INVERSEVID) + { + if (current_vp->drawmode & DRMODE_BG) + { + if (!lcd_backdrop) + { + fillopt = OPT_SET; + bits = FB_SCALARPACK(current_vp->bg_pattern); + } + else + fillopt = OPT_COPY; + } + } + else + { + if (current_vp->drawmode & DRMODE_FG) + { + fillopt = OPT_SET; + bits = FB_SCALARPACK(current_vp->fg_pattern); + } + } + if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT) + return; + + dst = FBADDR(x, y); + dst_end = FBADDR(x + width - 1, y + height - 1); + + len = STRIDE_MAIN(width, height); + step = STRIDE_MAIN(ROW_INC, COL_INC); + + do + { + switch (fillopt) + { + case OPT_SET: + { + fb_data *start = dst; + fb_data *end = start + len; + do { + *start = bits; + } while (++start < end); + break; + } + + case OPT_COPY: + memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), + len * sizeof(fb_data)); + break; + + case OPT_NONE: /* DRMODE_COMPLEMENT */ + { + fb_data *start = dst; + fb_data *end = start + len; + do { + flippixel(start); + } while (++start < end); + break; + } + } + dst += step; + } + while (dst <= dst_end); +} + +/* About Rockbox' internal monochrome bitmap format: + * + * A bitmap contains one bit for every pixel that defines if that pixel is + * black (1) or white (0). Bits within a byte are arranged vertically, LSB + * at top. + * The bytes are stored in row-major order, with byte 0 being top left, + * byte 1 2nd from left etc. The first row of bytes defines pixel rows + * 0..7, the second row defines pixel row 8..15 etc. + * + * This is the mono bitmap format used on all other targets so far; the + * pixel packing doesn't really matter on a 8bit+ target. */ + +/* Draw a partial monochrome bitmap */ + +void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x, + int src_y, int stride, int x, int y, + int width, int height) +{ + const unsigned char *src_end; + fb_data *dst, *dst_col; + unsigned dmask = 0x100; /* bit 8 == sentinel */ + int drmode = current_vp->drawmode; + int row; + + /******************** Image in viewport clipping **********************/ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + src += stride * (src_y >> 3) + src_x; /* move starting point */ + src_y &= 7; + src_end = src + width; + dst_col = FBADDR(x, y); + + + if (drmode & DRMODE_INVERSEVID) + { + dmask = 0x1ff; /* bit 8 == sentinel */ + drmode &= DRMODE_SOLID; /* mask out inversevid */ + } + + /* Use extra bit to avoid if () in the switch-cases below */ + if ((drmode & DRMODE_BG) && lcd_backdrop) + drmode |= DRMODE_INT_BD; + + /* go through each column and update each pixel */ + do + { + const unsigned char *src_col = src++; + unsigned data = (*src_col ^ dmask) >> src_y; + fb_data fg, bg; + uintptr_t bo; + + dst = dst_col; + dst_col += COL_INC; + row = height; + +#define UPDATE_SRC do { \ + data >>= 1; \ + if (data == 0x001) { \ + src_col += stride; \ + data = *src_col ^ dmask; \ + } \ + } while (0) + + switch (drmode) + { + case DRMODE_COMPLEMENT: + do + { + if (data & 0x01) + flippixel(dst); + + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + + case DRMODE_BG|DRMODE_INT_BD: + bo = lcd_backdrop_offset; + do + { + if (!(data & 0x01)) + *dst = *(fb_data *)((long)dst + bo); + + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + + case DRMODE_BG: + bg = FB_SCALARPACK(current_vp->bg_pattern); + do + { + if (!(data & 0x01)) + *dst = bg; + + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + + case DRMODE_FG: + fg = FB_SCALARPACK(current_vp->fg_pattern); + do + { + if (data & 0x01) + *dst = fg; + + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + + case DRMODE_SOLID|DRMODE_INT_BD: + fg = FB_SCALARPACK(current_vp->fg_pattern); + bo = lcd_backdrop_offset; + do + { + *dst = (data & 0x01) ? fg + : *(fb_data *)((long)dst + bo); + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + + case DRMODE_SOLID: + fg = FB_SCALARPACK(current_vp->fg_pattern); + bg = FB_SCALARPACK(current_vp->bg_pattern); + do + { + *dst = (data & 0x01) ? fg : bg; + dst += ROW_INC; + UPDATE_SRC; + } + while (--row); + break; + } + } + while (src < src_end); +} +/* Draw a full monochrome bitmap */ +void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) +{ + lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); +} + + +/* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2) + * + * For each pixel, 4bit of alpha information is stored in a byte-stream, + * so two pixels are packed into one byte. + * The lower nibble is the first pixel, the upper one the second. The stride is + * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],... + * The format is independant of the internal display orientation and color + * representation, as to support the same font files on all displays. + * The values go linear from 0 (fully opaque) to 15 (fully transparent) + * (note how this is the opposite of the alpha channel in the ARGB format). + * + * This might suggest that rows need to have an even number of pixels. + * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal + * with uneven colums (i.e. two rows can share one byte). And font files do + * exploit this. + * However, this is difficult to do for image files, especially bottom-up bitmaps, + * so lcd_bmp() do expect even rows. + */ + +#define ALPHA_COLOR_FONT_DEPTH 2 +#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) +#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) +#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) +#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH) + +/* This is based on SDL (src/video/SDL_RLEaccel.c) ALPHA_BLIT32_888() macro */ +static inline fb_data blend_two_colors(unsigned c1, unsigned c2, unsigned a) +{ + unsigned s = c1; + unsigned d = c2; + unsigned s1 = s & 0xff00ff; + unsigned d1 = d & 0xff00ff; + a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); + d1 = (d1 + ((s1 - d1) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00ff; + s &= 0xff00; + d &= 0xff00; + d = (d + ((s - d) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00; + + return FB_SCALARPACK(d1 | d); +} + +/* Blend an image with an alpha channel + * if image is NULL, drawing will happen according to the drawmode + * src is the alpha channel (4bit per pixel) */ +static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, + const unsigned char *src, int src_x, + int src_y, int x, int y, + int width, int height, + int stride_image, int stride_src) +{ + fb_data *dst, *dst_row; + unsigned dmask = 0x00000000; + int drmode = current_vp->drawmode; + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + /* the following drawmode combinations are possible: + * 1) COMPLEMENT: just negates the framebuffer contents + * 2) BG and BG+backdrop: draws _only_ background pixels with either + * the background color or the backdrop (if any). The backdrop + * is an image in native lcd format + * 3) FG and FG+image: draws _only_ foreground pixels with either + * the foreground color or an image buffer. The image is in + * native lcd format + * 4) SOLID, SOLID+backdrop, SOLID+image, SOLID+backdrop+image, i.e. all + * possible combinations of 2) and 3). Draws both, fore- and background, + * pixels. The rules of 2) and 3) apply. + * + * INVERSEVID swaps fore- and background pixels, i.e. background pixels + * become foreground ones and vice versa. + */ + if (drmode & DRMODE_INVERSEVID) + { + dmask = 0xffffffff; + drmode &= DRMODE_SOLID; /* mask out inversevid */ + } + + /* Use extra bits to avoid if () in the switch-cases below */ + if (image != NULL) + drmode |= DRMODE_INT_IMG; + + if ((drmode & DRMODE_BG) && lcd_backdrop) + drmode |= DRMODE_INT_BD; + + dst_row = FBADDR(x, y); + + int col, row = height; + unsigned data, pixels; + unsigned skip_end = (stride_src - width); + unsigned skip_start = src_y * stride_src + src_x; + unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x, + src_x * stride_image + src_y); + +#ifdef ALPHA_BITMAP_READ_WORDS + uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); + skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3); + src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD; + data = letoh32(*src_w++) ^ dmask; + pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; +#else + src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; + data = *src ^ dmask; + pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE; +#endif + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; +#ifdef ALPHA_BITMAP_READ_WORDS + pixels = 8 - pixels; +#endif + + /* image is only accessed in DRMODE_INT_IMG cases, i.e. when non-NULL. + * Therefore NULL accesses are impossible and we can increment + * unconditionally (applies for stride at the end of the loop as well) */ + image += skip_start_image; + /* go through the rows and update each pixel */ + do + { + /* saving current_vp->fg/bg_pattern and lcd_backdrop_offset into these + * temp vars just before the loop helps gcc to opimize the loop better + * (testing showed ~15% speedup) */ + unsigned fg, bg; + ptrdiff_t bo, img_offset; + col = width; + dst = dst_row; + dst_row += ROW_INC; +#ifdef ALPHA_BITMAP_READ_WORDS +#define UPDATE_SRC_ALPHA do { \ + if (--pixels) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + { \ + data = letoh32(*src_w++) ^ dmask; \ + pixels = ALPHA_COLOR_PIXEL_PER_WORD; \ + } \ + } while (0) +#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2 +#define UPDATE_SRC_ALPHA do { \ + if (pixels ^= 1) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + data = *(++src) ^ dmask; \ + } while (0) +#else +#define UPDATE_SRC_ALPHA do { \ + if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \ + data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ + else \ + data = *(++src) ^ dmask; \ + } while (0) +#endif + + switch (drmode) + { + case DRMODE_COMPLEMENT: + do + { + unsigned px = FB_UNPACK_SCALAR_LCD(*dst); + *dst = blend_two_colors(px, ~px, + data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_BG|DRMODE_INT_BD: + bo = lcd_backdrop_offset; + do + { + unsigned px = FB_UNPACK_SCALAR_LCD(*dst); + unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); + *dst = blend_two_colors(c, px, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + image += STRIDE_MAIN(1, stride_image); + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_BG: + bg = current_vp->bg_pattern; + do + { + unsigned px = FB_UNPACK_SCALAR_LCD(*dst); + *dst = blend_two_colors(bg, px, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_FG|DRMODE_INT_IMG: + img_offset = image - dst; + do + { + unsigned px1 = FB_UNPACK_SCALAR_LCD(*dst); + unsigned px2 = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); + *dst = blend_two_colors(px1, px2, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_FG: + fg = current_vp->fg_pattern; + do + { + unsigned px = FB_UNPACK_SCALAR_LCD(*dst); + *dst = blend_two_colors(px, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_SOLID|DRMODE_INT_BD: + bo = lcd_backdrop_offset; + fg = current_vp->fg_pattern; + do + { + unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); + *dst = blend_two_colors(c, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_SOLID|DRMODE_INT_IMG: + bg = current_vp->bg_pattern; + img_offset = image - dst; + do + { + unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); + *dst = blend_two_colors(bg, c, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_SOLID|DRMODE_INT_BD|DRMODE_INT_IMG: + bo = lcd_backdrop_offset; + img_offset = image - dst; + do + { + unsigned px = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); + unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); + *dst = blend_two_colors(px, c, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + case DRMODE_SOLID: + bg = current_vp->bg_pattern; + fg = current_vp->fg_pattern; + do + { + *dst = blend_two_colors(bg, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); + dst += COL_INC; + UPDATE_SRC_ALPHA; + } + while (--col); + break; + } +#ifdef ALPHA_BITMAP_READ_WORDS + if (skip_end < pixels) + { + pixels -= skip_end; + data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; + } else { + pixels = skip_end - pixels; + src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD; + pixels %= ALPHA_COLOR_PIXEL_PER_WORD; + data = letoh32(*src_w++) ^ dmask; + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; + pixels = 8 - pixels; + } +#else + if (skip_end) + { + pixels += skip_end; + if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE) + { + src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE; + pixels %= ALPHA_COLOR_PIXEL_PER_BYTE; + data = *src ^ dmask; + data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; + } else + data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; + } +#endif + + image += STRIDE_MAIN(stride_image,1); + } while (--row); +} + +/*** drawing functions ***/ + +/* Draw a horizontal line (optimised) */ +void lcd_hline(int x1, int x2, int y) +{ + int x, width; + fb_data *dst, *dst_end; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; + + /* direction flip */ + if (x2 < x1) + { + x = x1; + x1 = x2; + x2 = x; + } + + /******************** In viewport clipping **********************/ + /* nothing to draw? */ + if (((unsigned)y >= (unsigned)current_vp->height) || + (x1 >= current_vp->width) || + (x2 < 0)) + return; + + if (x1 < 0) + x1 = 0; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; + + /* Adjust x1 and y to viewport */ + x1 += current_vp->x; + x2 += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH) + || (x2 < 0)) + return; + + /* clipping */ + if (x1 < 0) + x1 = 0; + if (x2 >= LCD_WIDTH) + x2 = LCD_WIDTH-1; +#endif + + width = x2 - x1 + 1; + + dst = FBADDR(x1 , y); + dst_end = dst + width; + do + { + pfunc(dst); + } + while (++dst < dst_end); +} + +/* Draw a vertical line (optimised) */ +void lcd_vline(int x, int y1, int y2) +{ + int y; + fb_data *dst, *dst_end; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; + + /* direction flip */ + if (y2 < y1) + { + y = y1; + y1 = y2; + y2 = y; + } + + /******************** In viewport clipping **********************/ + /* nothing to draw? */ + if (((unsigned)x >= (unsigned)current_vp->width) || + (y1 >= current_vp->height) || + (y2 < 0)) + return; + + if (y1 < 0) + y1 = 0; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; + + /* adjust for viewport */ + x += current_vp->x; + y1 += current_vp->y; + y2 += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT) + || (y2 < 0)) + return; + + /* clipping */ + if (y1 < 0) + y1 = 0; + if (y2 >= LCD_HEIGHT) + y2 = LCD_HEIGHT-1; +#endif + + dst = FBADDR(x , y1); + dst_end = dst + (y2 - y1) * LCD_WIDTH; + + do + { + pfunc(dst); + dst += LCD_WIDTH; + } + while (dst <= dst_end); +} + +/* Draw a partial native bitmap */ +void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y, + int stride, int x, int y, int width, + int height) +{ + fb_data *dst; + + /******************** Image in viewport clipping **********************/ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + src += stride * src_y + src_x; /* move starting point */ + dst = FBADDR(x, y); + + do + { + memcpy(dst, src, width * sizeof(fb_data)); + src += stride; + dst += LCD_WIDTH; + } + while (--height > 0); +} + +/* Draw a partial native bitmap with transparency and foreground colors */ +void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x, + int src_y, int stride, int x, + int y, int width, int height) +{ + fb_data *dst; + fb_data fg, transparent, replacewithfg; + + /******************** Image in viewport clipping **********************/ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) + return; + + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + +#if defined(HAVE_VIEWPORT_CLIP) + /********************* Viewport on screen clipping ********************/ + /* nothing to draw? */ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clip image in viewport in screen */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; +#endif + + src += stride * src_y + src_x; /* move starting point */ + dst = FBADDR(x, y); + + transparent = FB_SCALARPACK(TRANSPARENT_COLOR); + replacewithfg = FB_SCALARPACK(REPLACEWITHFG_COLOR); + fg = FB_SCALARPACK(current_vp->fg_pattern); +#define CMP(c1, c2) (c1.r == c2.r && c1.g == c2.g && c1.b == c2.b) + + do + { + const fb_data *src_row = src; + fb_data *dst_row = dst; + fb_data *row_end = dst_row + width; + do + { + fb_data data = *src_row++; + if (!CMP(data, transparent)) + { + if (CMP(data, replacewithfg)) + data = fg; + *dst_row = data; + } + } + while (++dst_row < row_end); + src += stride; + dst += LCD_WIDTH; + } + while (--height > 0); +} diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c index e171f08465..b5b0f58eb3 100644 --- a/firmware/drivers/lcd-color-common.c +++ b/firmware/drivers/lcd-color-common.c @@ -422,7 +422,7 @@ void lcd_blit_yuv(unsigned char * const src[3], b = clamp(b, 0, 64*256-1); } - *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -442,7 +442,7 @@ void lcd_blit_yuv(unsigned char * const src[3], b = clamp(b, 0, 64*256-1); } - *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -487,7 +487,7 @@ void lcd_blit_yuv(unsigned char * const src[3], b = clamp(b, 0, 64*256-1); } - *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; @@ -507,7 +507,7 @@ void lcd_blit_yuv(unsigned char * const src[3], b = clamp(b, 0, 64*256-1); } - *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6); #if LCD_WIDTH >= LCD_HEIGHT dst++; diff --git a/firmware/export/config.h b/firmware/export/config.h index 9c1a8dbf57..5e4178cd4c 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -275,6 +275,7 @@ #define VERTICAL_INTERLEAVED 4 #define RGB565 565 #define RGB565SWAPPED 3553 +#define RGB888 888 /* LCD_STRIDEFORMAT */ #define VERTICAL_STRIDE 1 diff --git a/firmware/export/config/samsungypr0.h b/firmware/export/config/samsungypr0.h index 049caa01b6..0fce70e1fe 100644 --- a/firmware/export/config/samsungypr0.h +++ b/firmware/export/config/samsungypr0.h @@ -47,7 +47,7 @@ /* sqrt(240^2 + 320^2) / 2.6 = 153.8 */ #define LCD_DPI 154 -#define LCD_DEPTH 16 +#define LCD_DEPTH 24 /* Check that but should not matter */ #define LCD_PIXELFORMAT RGB565 diff --git a/firmware/export/config/samsungypr1.h b/firmware/export/config/samsungypr1.h index 1aaf85dcb5..42b46e0699 100644 --- a/firmware/export/config/samsungypr1.h +++ b/firmware/export/config/samsungypr1.h @@ -53,11 +53,11 @@ #define LCD_HEIGHT 240 #endif -#define LCD_DEPTH 16 +#define LCD_DEPTH 24 /* Calculated value, important for touch sensor */ #define LCD_DPI 180 /* Check that but should not matter */ -#define LCD_PIXELFORMAT RGB565 +#define LCD_PIXELFORMAT RGB888 /* Capacitive touchscreen */ #define HAVE_TOUCHSCREEN diff --git a/firmware/export/config/sansae200v2.h b/firmware/export/config/sansae200v2.h index c703439e7f..e70b409d51 100644 --- a/firmware/export/config/sansae200v2.h +++ b/firmware/export/config/sansae200v2.h @@ -53,8 +53,8 @@ #define LCD_HEIGHT 220 /* sqrt(176^2 + 220^2) / 1.8 = 156.5 */ #define LCD_DPI 157 -#define LCD_DEPTH 16 /* 65536 colours */ -#define LCD_PIXELFORMAT RGB565 /* rgb565 */ +#define LCD_DEPTH 24 /* 65536 colours */ +#define LCD_PIXELFORMAT RGB888 /* rgb565 */ #ifndef BOOTLOADER /* define this if you have LCD enable function */ diff --git a/firmware/export/config/sdlapp.h b/firmware/export/config/sdlapp.h index cd973fcf73..626bd5c99f 100644 --- a/firmware/export/config/sdlapp.h +++ b/firmware/export/config/sdlapp.h @@ -44,8 +44,8 @@ #define LCD_HEIGHT 480 #endif -#define LCD_DEPTH 16 -#define LCD_PIXELFORMAT RGB565 +#define LCD_DEPTH 24 +#define LCD_PIXELFORMAT RGB888 /* define this to indicate your device's keypad */ #define HAVE_TOUCHSCREEN diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 673ce069af..cf6a16572a 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -127,7 +127,13 @@ typedef unsigned char fb_data; #elif LCD_DEPTH <= 16 typedef unsigned short fb_data; #define FB_DATA_SZ 2 -#else /* LCD_DEPTH > 16 */ +#elif LCD_DEPTH <= 24 +struct _fb_pixel { + unsigned char b, g, r; +}; +typedef struct _fb_pixel fb_data; +#define FB_DATA_SZ 3 +#else /* LCD_DEPTH > 24 */ typedef unsigned long fb_data; #define FB_DATA_SZ 4 #endif /* LCD_DEPTH */ @@ -341,6 +347,31 @@ static inline unsigned lcd_color_to_native(unsigned color) #define RGB_UNPACK_GREEN_LCD(x) _RGB_UNPACK_GREEN_LCD(x) #define RGB_UNPACK_BLUE_LCD(x) _RGB_UNPACK_BLUE_LCD(x) #endif /* RGB565* */ + +#elif LCD_PIXELFORMAT == RGB888 +#define LCD_MAX_RED 255 +#define LCD_MAX_GREEN 255 +#define LCD_MAX_BLUE 255 +#define LCD_RED_BITS 8 +#define LCD_GREEN_BITS 8 +#define LCD_BLUE_BITS 8 + +/* pack/unpack native RGB values */ +#define _RGBPACK(r, g, b) ( r << 16 | g << 8 | b ) +#define _RGB_UNPACK_RED(x) ((x >> 16) & 0xff) +#define _RGB_UNPACK_GREEN(x) ((x >> 8) & 0xff) +#define _RGB_UNPACK_BLUE(x) ((x >> 0) & 0xff) + +#define _LCD_UNSWAP_COLOR(x) (x) +#define LCD_RGBPACK(r, g, b) _RGBPACK((r), (g), (b)) +#define LCD_RGBPACK_LCD(r, g, b) _RGBPACK((r), (g), (b)) +#define RGB_UNPACK_RED(x) _RGB_UNPACK_RED(x) +#define RGB_UNPACK_GREEN(x) _RGB_UNPACK_GREEN(x) +#define RGB_UNPACK_BLUE(x) _RGB_UNPACK_BLUE(x) +#define RGB_UNPACK_RED_LCD(x) _RGB_UNPACK_RED(x) +#define RGB_UNPACK_GREEN_LCD(x) _RGB_UNPACK_GREEN(x) +#define RGB_UNPACK_BLUE_LCD(x) _RGB_UNPACK_BLUE(x) + #else /* other colour depths */ #endif @@ -367,6 +398,58 @@ static inline unsigned lcd_color_to_native(unsigned color) #endif /* HAVE_LCD_COLOR */ +/* Framebuffer conversion macros: Convert from and to the native display data + * format (fb_data). + * + * FB_RGBPACK: Convert the three r,g,b values to fb_data. r,g,b are + * assumed to in 8-bit format. + * FB_RGBPACK_LCD Like FB_RGBPACK, except r,g,b shall be in display-native + * bit format (e.g. 5-bit r for RGB565) + * FB_UNPACK_RED Extract the red component of fb_data into 8-bit red value. + * FB_UNPACK_GREEN Like FB_UNPACK_RED, just for the green component. + * FB_UNPACK_BLIE Like FB_UNPACK_RED, just for the green component. + * FB_SCALARPACK Similar to FB_RGBPACK, except that the channels are already + * combined into a single scalar value. Again, 8-bit per channel. + * FB_SCALARPACK_LCD Like FB_SCALARPACK, except the channels shall be in + * display-native format (i.e. the scalar is 16bits on RGB565) + * FB_UNPACK_SCALAR_LCD Converts an fb_data to a scalar value in display-native + * format, so it's the reverse of FB_SCALARPACK_LCD + */ +#if LCD_DEPTH >= 24 +static inline fb_data scalar_to_fb(unsigned p) +{ + union { fb_data st; unsigned sc; } convert; + convert.sc = p; return convert.st; +} +static inline unsigned fb_to_scalar(fb_data p) +{ + union { fb_data st; unsigned sc; } convert; + convert.st = p; return convert.sc; +} +#define FB_RGBPACK(r_, g_, b_) ((fb_data){.r = r_, .g = g_, .b = b_}) +#define FB_RGBPACK_LCD(r_, g_, b_) FB_RGBPACK(r_, g_, b_) +#define FB_UNPACK_RED(fb) ((fb).r) +#define FB_UNPACK_GREEN(fb) ((fb).g) +#define FB_UNPACK_BLUE(fb) ((fb).b) +#define FB_SCALARPACK(c) scalar_to_fb(c) +#define FB_SCALARPACK_LCD(c) scalar_to_fb(c) +#define FB_UNPACK_SCALAR_LCD(fb) fb_to_scalar(fb) +#elif defined(HAVE_LCD_COLOR) +#define FB_RGBPACK(r_, g_, b_) LCD_RGBPACK(r_, g_, b_) +#define FB_RGBPACK_LCD(r_, g_, b_) LCD_RGBPACK_LCD(r_, g_, b_) +#define FB_UNPACK_RED(fb) RGB_UNPACK_RED(fb) +#define FB_UNPACK_GREEN(fb) RGB_UNPACK_GREEN(fb) +#define FB_UNPACK_BLUE(fb) RGB_UNPACK_BLUE(fb) +#define FB_SCALARPACK(c) LCD_RGBPACK(RGB_UNPACK_RED(c), RGB_UNPACK_GREEN(c), RGB_UNPACK_BLUE(c)) +#define FB_SCALARPACK_LCD(c) (c) +#define FB_UNPACK_SCALAR_LCD(fb) (fb) +#else +#define FB_SCALARPACK(c) (c) +#define FB_SCALARPACK_LCD(c) (c) +#define FB_UNPACK_SCALAR_LCD(fb) (fb) +#endif + + /* Frame buffer dimensions */ #if LCD_DEPTH == 1 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING diff --git a/firmware/screendump.c b/firmware/screendump.c index 28c37610af..2916cc1c9f 100644 --- a/firmware/screendump.c +++ b/firmware/screendump.c @@ -118,6 +118,9 @@ void screen_dump(void) #elif LCD_DEPTH <= 16 unsigned short *dst, *dst_end; unsigned short linebuf[DUMP_BMP_LINESIZE/2]; +#else /* 24bit */ + unsigned char *dst, *dst_end; + unsigned char linebuf[DUMP_BMP_LINESIZE * 3]; #endif #if CONFIG_RTC @@ -227,6 +230,17 @@ void screen_dump(void) #endif } while (dst < dst_end); +#elif LCD_DEPTH == 24 + dst_end = dst + LCD_WIDTH*3; + src = FBADDR(0, y); + do + { + *dst++ = src->b; + *dst++ = src->g; + *dst++ = src->r; + ++src; + } + while (dst < dst_end); #endif /* LCD_DEPTH */ write(fd, linebuf, DUMP_BMP_LINESIZE); diff --git a/firmware/target/hosted/sdl/lcd-bitmap.c b/firmware/target/hosted/sdl/lcd-bitmap.c index 7e9bc297ef..5add2367a0 100644 --- a/firmware/target/hosted/sdl/lcd-bitmap.c +++ b/firmware/target/hosted/sdl/lcd-bitmap.c @@ -112,6 +112,8 @@ static unsigned long get_lcd_pixel(int x, int y) #else return *FBADDR(x, y); #endif +#elif LCD_DEPTH == 24 + return FB_UNPACK_SCALAR_LCD(*FBADDR(x, y)); #endif } @@ -172,7 +174,7 @@ void sim_backlight(int value) /* initialise simulator lcd driver */ void lcd_init_device(void) { -#if LCD_DEPTH == 16 +#if LCD_DEPTH >= 16 lcd_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, SIM_LCD_WIDTH * display_zoom, SIM_LCD_HEIGHT * display_zoom, -- cgit v1.2.3