[U-Boot] [PATCH 0/7] lcd/video: Add parameter API and compressed bitmaps

This series contains patches to create an API to read lcd/video parameters such as the screen size. It also adds support for displaying compressed bitmaps.
Ultimately it would be nice to unify lcd and video more, and this is a step towards that. Board files still need to decide which to use, but the same parameters are available in both.
Stefan Reinauer (2): video: Provide an API to access video parameters video: Implement additional video API functions in cfb_console
Tom Wai-Hong Tam (3): lcd: Fix BMP decode bug that skips the wrong padded row lcd: Fix fb offset calculation for bpix == 16 in BMP display lcd: Implement RLE8 bitmap decoding
Vadim Bendebury (2): lcd: Provide an API to access LCD parameters video: Skip bitmaps which do not fit into the screen in cfb_console
README | 5 + common/cmd_bmp.c | 4 +- common/lcd.c | 184 +++++++++++++++++++++++++++++++++++++++++-- drivers/video/cfb_console.c | 39 +++++++++ include/lcd.h | 36 +++++++++ include/video.h | 48 +++++++++++ 6 files changed, 307 insertions(+), 9 deletions(-)

From: Stefan Reinauer reinauer@chromium.org
Create a basic API to provide access to video parameters such as screen size, and to position the cursor on the screen. Also add a prototype for video_display_bitmap() which was missing.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- common/cmd_bmp.c | 4 +--- include/video.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c index b8809e3..6ba6d5d 100644 --- a/common/cmd_bmp.c +++ b/common/cmd_bmp.c @@ -238,9 +238,7 @@ int bmp_display(ulong addr, int x, int y) #if defined(CONFIG_LCD) ret = lcd_display_bitmap((ulong)bmp, x, y); #elif defined(CONFIG_VIDEO) - extern int video_display_bitmap (ulong, int, int); - - ret = video_display_bitmap ((unsigned long)bmp, x, y); + ret = video_display_bitmap((unsigned long)bmp, x, y); #else # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO #endif diff --git a/include/video.h b/include/video.h index 9519cea..f7e27f8 100644 --- a/include/video.h +++ b/include/video.h @@ -15,4 +15,52 @@ int video_init (void *videobase); void video_putc (const char c); void video_puts (const char *s);
+/** + * Display a BMP format bitmap on the screen + * + * @param bmp_image Address of BMP image + * @param x X position to draw image + * @param y Y position to draw image + */ +int video_display_bitmap(ulong bmp_image, int x, int y); + +/** + * Get the width of the screen in pixels + * + * @return width of screen in pixels + */ +int video_get_pixel_width(void); + +/** + * Get the height of the screen in pixels + * + * @return height of screen in pixels + */ +int video_get_pixel_height(void); + +/** + * Get the number of text lines/rows on the screen + * + * @return number of rows + */ +int video_get_screen_rows(void); + +/** + * Get the number of text columns on the screen + * + * @return number of columns + */ +int video_get_screen_columns(void); + +/** + * Set the position of the text cursor + * + * @param col Column to place cursor (0 = left side) + * @param row Row to place cursor (0 = top line) + */ +void video_position_cursor(unsigned col, unsigned row); + +/* Clear the display */ +void video_clear(void); + #endif

From: Stefan Reinauer reinauer@chromium.org
Create a basic API to provide access to video parameters such as screen size, and to position the cursor on the screen. Also add a prototype for video_display_bitmap() which was missing.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Anatolij Gustschin agust@denx.de --- Changes in v2: - include video.h in cmd_bmp.c to fix compiler warning: cmd_bmp.c:242:2: warning: implicit declaration of function 'video_display_bitmap' [-Wimplicit-function-declaration]
common/cmd_bmp.c | 5 ++--- include/video.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c index b8809e3..5a52edd 100644 --- a/common/cmd_bmp.c +++ b/common/cmd_bmp.c @@ -31,6 +31,7 @@ #include <command.h> #include <asm/byteorder.h> #include <malloc.h> +#include <video.h>
static int bmp_info (ulong addr);
@@ -238,9 +239,7 @@ int bmp_display(ulong addr, int x, int y) #if defined(CONFIG_LCD) ret = lcd_display_bitmap((ulong)bmp, x, y); #elif defined(CONFIG_VIDEO) - extern int video_display_bitmap (ulong, int, int); - - ret = video_display_bitmap ((unsigned long)bmp, x, y); + ret = video_display_bitmap((unsigned long)bmp, x, y); #else # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO #endif diff --git a/include/video.h b/include/video.h index 9519cea..f7e27f8 100644 --- a/include/video.h +++ b/include/video.h @@ -15,4 +15,52 @@ int video_init (void *videobase); void video_putc (const char c); void video_puts (const char *s);
+/** + * Display a BMP format bitmap on the screen + * + * @param bmp_image Address of BMP image + * @param x X position to draw image + * @param y Y position to draw image + */ +int video_display_bitmap(ulong bmp_image, int x, int y); + +/** + * Get the width of the screen in pixels + * + * @return width of screen in pixels + */ +int video_get_pixel_width(void); + +/** + * Get the height of the screen in pixels + * + * @return height of screen in pixels + */ +int video_get_pixel_height(void); + +/** + * Get the number of text lines/rows on the screen + * + * @return number of rows + */ +int video_get_screen_rows(void); + +/** + * Get the number of text columns on the screen + * + * @return number of columns + */ +int video_get_screen_columns(void); + +/** + * Set the position of the text cursor + * + * @param col Column to place cursor (0 = left side) + * @param row Row to place cursor (0 = top line) + */ +void video_position_cursor(unsigned col, unsigned row); + +/* Clear the display */ +void video_clear(void); + #endif

From: Stefan Reinauer reinauer@chromium.org
Implement the new video API functions to provide access to screen size, etc.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- drivers/video/cfb_console.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 19d061f..c39d896 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -1865,3 +1865,35 @@ int drv_video_init(void) /* Return success */ return 1; } + +void video_position_cursor(unsigned col, unsigned row) +{ + console_col = min(col, CONSOLE_COLS - 1); + console_row = min(row, CONSOLE_ROWS - 1); +} + +int video_get_pixel_width(void) +{ + return VIDEO_VISIBLE_COLS; +} + +int video_get_pixel_height(void) +{ + return VIDEO_VISIBLE_ROWS; +} + +int video_get_screen_rows(void) +{ + return CONSOLE_ROWS; +} + +int video_get_screen_columns(void) +{ + return CONSOLE_COLS; +} + +void video_clear(void) +{ + memsetl(video_fb_address, + (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), 0); +}

From: Stefan Reinauer reinauer@chromium.org
Implement the new video API functions to provide access to screen size, etc.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Anatolij Gustschin agust@denx.de --- Changes in v2: - fix compiler warning for some boards (ipek01, lwmon5, etc): cfb_console.c:2296:2: warning: implicit declaration of function 'memsetl' [-Wimplicit-function-declaration] - use background color in video_clear()
drivers/video/cfb_console.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-)
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 9c67b63..6f5d4f2 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -2257,3 +2257,45 @@ int drv_video_init(void) /* Return success */ return 1; } + +void video_position_cursor(unsigned col, unsigned row) +{ + console_col = min(col, CONSOLE_COLS - 1); + console_row = min(row, CONSOLE_ROWS - 1); +} + +int video_get_pixel_width(void) +{ + return VIDEO_VISIBLE_COLS; +} + +int video_get_pixel_height(void) +{ + return VIDEO_VISIBLE_ROWS; +} + +int video_get_screen_rows(void) +{ + return CONSOLE_ROWS; +} + +int video_get_screen_columns(void) +{ + return CONSOLE_COLS; +} + +void video_clear(void) +{ +#ifdef VIDEO_HW_RECTFILL + video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ + 0, /* dest pos x */ + 0, /* dest pos y */ + VIDEO_VISIBLE_COLS, /* frame width */ + VIDEO_VISIBLE_ROWS, /* frame height */ + bgx /* fill color */ + ); +#else + memsetl(video_fb_address, + (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx); +#endif +}

From: Vadim Bendebury vbendeb@chromium.org
Create a basic API to provide access to lcd parameters such as screen size, and to position the cursor on the screen.
This matches up with the video API for the same purpose. Unfortunately they are not yet combined.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- common/lcd.c | 26 ++++++++++++++++++++++++++ include/lcd.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index b6be800..4cea04e 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -885,5 +885,31 @@ static void *lcd_logo(void) #endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */ }
+void lcd_position_cursor(unsigned col, unsigned row) +{ + console_col = min(col, CONSOLE_COLS - 1); + console_row = min(row, CONSOLE_ROWS - 1); +} + +int lcd_get_pixel_width(void) +{ + return panel_info.vl_col; +} + +int lcd_get_pixel_height(void) +{ + return panel_info.vl_row; +} + +int lcd_get_screen_rows(void) +{ + return CONSOLE_ROWS; +} + +int lcd_get_screen_columns(void) +{ + return CONSOLE_COLS; +} + /************************************************************************/ /************************************************************************/ diff --git a/include/lcd.h b/include/lcd.h index 42070d7..2517d39 100644 --- a/include/lcd.h +++ b/include/lcd.h @@ -294,6 +294,42 @@ void lcd_printf (const char *fmt, ...); void lcd_clear(void); int lcd_display_bitmap(ulong bmp_image, int x, int y);
+/** + * Get the width of the LCD in pixels + * + * @return width of LCD in pixels + */ +int lcd_get_pixel_width(void); + +/** + * Get the height of the LCD in pixels + * + * @return height of LCD in pixels + */ +int lcd_get_pixel_height(void); + +/** + * Get the number of text lines/rows on the LCD + * + * @return number of rows + */ +int lcd_get_screen_rows(void); + +/** + * Get the number of text columns on the LCD + * + * @return number of columns + */ +int lcd_get_screen_columns(void); + +/** + * Set the position of the text cursor + * + * @param col Column to place cursor (0 = left side) + * @param row Row to place cursor (0 = top line) + */ +void lcd_position_cursor(unsigned col, unsigned row); + /* Allow boards to customize the information displayed */ void lcd_show_board_info(void);

From: Tom Wai-Hong Tam waihong@chromium.org
This change fixed 2 things: - Rename padded_line to padded_width since it is (width + padded_row) not line. - When finished a line, should skip the padded_row that is (padded_width - width) instead of (width - padded_width).
Reference: http://en.wikipedia.org/wiki/BMP_file_format Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- common/lcd.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index 4cea04e..7c6cb09 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -675,7 +675,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) uchar *fb; bmp_image_t *bmp=(bmp_image_t *)bmp_image; uchar *bmap; - ushort padded_line; + ushort padded_width; unsigned long width, height, byte_width; unsigned long pwidth = panel_info.vl_col; unsigned colors, bpix, bmp_bpix; @@ -762,7 +762,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) } #endif
- padded_line = (width&0x3) ? ((width&~0x3)+4) : (width); + padded_width = (width&0x3) ? ((width&~0x3)+4) : (width);
#ifdef CONFIG_SPLASH_SCREEN_ALIGN splash_align_axis(&x, pwidth, width); @@ -796,7 +796,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) fb += sizeof(uint16_t) / sizeof(*fb); } } - bmap += (width - padded_line); + bmap += (padded_width - width); fb -= (byte_width + lcd_line_length); } break; @@ -808,7 +808,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) for (j = 0; j < width; j++) fb_put_word(&fb, &bmap);
- bmap += (padded_line - width) * 2; + bmap += (padded_width - width) * 2; fb -= (width * 2 + lcd_line_length); } break;

From: Tom Wai-Hong Tam waihong@chromium.org
For bpix == 16, each pixel is 2-byte. fb offset should shift more x bytes.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- common/lcd.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index 7c6cb09..004a6be 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -775,8 +775,10 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) height = panel_info.vl_row - y;
bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset); - fb = (uchar *) (lcd_base + - (y + height - 1) * lcd_line_length + x * bpix / 8); + fb = (uchar *) (lcd_base + (y + height - 1) * lcd_line_length + x); + /* additional fb shift for bpix == 16 since each pixel is 2-byte */ + if (bpix == 16) + fb += x;
switch (bmp_bpix) { case 1: /* pass through */

Hi Simon,
On 09/29/2012 03:11 AM, Simon Glass wrote:
From: Tom Wai-Hong Tam waihong@chromium.org
For bpix == 16, each pixel is 2-byte. fb offset should shift more x bytes.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
common/lcd.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index 7c6cb09..004a6be 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -775,8 +775,10 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) height = panel_info.vl_row - y;
bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
- fb = (uchar *) (lcd_base +
(y + height - 1) * lcd_line_length + x * bpix / 8);
- fb = (uchar *) (lcd_base + (y + height - 1) * lcd_line_length + x);
- /* additional fb shift for bpix == 16 since each pixel is 2-byte */
- if (bpix == 16)
fb += x;
Why is this change necessary? if bpix == 16 then x * bpix / 8 == 2 * x anyway.
switch (bmp_bpix) { case 1: /* pass through */

Hi Nikita,
On Thu, Oct 4, 2012 at 1:48 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Simon,
On 09/29/2012 03:11 AM, Simon Glass wrote:
From: Tom Wai-Hong Tam waihong@chromium.org
For bpix == 16, each pixel is 2-byte. fb offset should shift more x bytes.
Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
common/lcd.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/common/lcd.c b/common/lcd.c index 7c6cb09..004a6be 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -775,8 +775,10 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) height = panel_info.vl_row - y;
bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
fb = (uchar *) (lcd_base +
(y + height - 1) * lcd_line_length + x * bpix / 8);
fb = (uchar *) (lcd_base + (y + height - 1) * lcd_line_length +
x);
/* additional fb shift for bpix == 16 since each pixel is 2-byte
*/
if (bpix == 16)
fb += x;
Why is this change necessary? if bpix == 16 then x * bpix / 8 == 2 * x anyway.
Yes I agree, I can't see what the difference might me. Tom, do you have any idea on this please?
Regards, Simon
switch (bmp_bpix) { case 1: /* pass through */

From: Tom Wai-Hong Tam waihong@google.com
Add support for drawing compressed RLE8 bitmaps.
Reference: http://www.digicamsoft.com/bmp/bmp.html
Signed-off-by: Che-Liang Chiou clchiou@chromium.org Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- README | 5 ++ common/lcd.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/README b/README index 5793b0a..40899d9 100644 --- a/README +++ b/README @@ -1440,6 +1440,11 @@ The following options need to be configured: Normally display is black on white background; define CONFIG_SYS_WHITE_ON_BLACK to get it inverted.
+ CONFIG_LCD_BMP_RLE8 + + Support drawing of RLE8-compressed bitmaps on the LCD. + + - Splash Screen Support: CONFIG_SPLASH_SCREEN
If this option is set, the environment is checked for diff --git a/common/lcd.c b/common/lcd.c index 004a6be..68df6d0 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -642,6 +642,136 @@ static void splash_align_axis(int *axis, unsigned long panel_size, } #endif
+ +#ifdef CONFIG_LCD_BMP_RLE8 + +#define BMP_RLE8_ESCAPE 0 +#define BMP_RLE8_EOL 0 +#define BMP_RLE8_EOBMP 1 +#define BMP_RLE8_DELTA 2 + +static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap, + int cnt) +{ + while (cnt > 0) { + *(*fbp)++ = cmap[*bmap++]; + cnt--; + } +} + +static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) +{ + ushort *fb = *fbp; + int cnt_8copy = cnt >> 3; + cnt -= cnt_8copy << 3; + while (cnt_8copy > 0) { + *fb++ = c; + *fb++ = c; + *fb++ = c; + *fb++ = c; + *fb++ = c; + *fb++ = c; + *fb++ = c; + *fb++ = c; + cnt_8copy--; + } + while (cnt > 0) { + *fb++ = c; + cnt--; + } + (*fbp) = fb; +} + +/* Do not call this function directly, must be called from + * lcd_display_bitmap. + */ +static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb, + int x_off, int y_off) +{ + uchar *bmap; + ulong width, height; + ulong cnt, runlen; + int x, y; + int decode = 1; + + width = le32_to_cpu(bmp->header.width); + height = le32_to_cpu(bmp->header.height); + bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset); + + x = 0; + y = height - 1; + + while (decode) { + if (bmap[0] == BMP_RLE8_ESCAPE) { + switch (bmap[1]) { + case BMP_RLE8_EOL: + /* end of line */ + bmap += 2; + x = 0; + y--; + /* 16bpix, 2-byte per pixel, width should *2 */ + fb -= (width * 2 + lcd_line_length); + break; + case BMP_RLE8_EOBMP: + /* end of bitmap */ + decode = 0; + break; + case BMP_RLE8_DELTA: + /* delta run */ + x += bmap[2]; + y -= bmap[3]; + /* 16bpix, 2-byte per pixel, x should *2 */ + fb = (uchar *) (lcd_base + (y + y_off - 1) + * lcd_line_length + (x + x_off) * 2); + bmap += 4; + break; + default: + /* unencoded run */ + runlen = bmap[1]; + bmap += 2; + if (y < height) { + if (x < width) { + if (x + runlen > width) + cnt = width - x; + else + cnt = runlen; + draw_unencoded_bitmap( + (ushort **)&fb, + bmap, cmap, cnt); + } + x += runlen; + } + bmap += runlen; + if (runlen & 1) + bmap++; + } + } else { + /* encoded run */ + if (y < height) { + runlen = bmap[0]; + if (x < width) { + /* aggregate the same code */ + while (bmap[0] == 0xff && + bmap[2] != BMP_RLE8_ESCAPE && + bmap[1] == bmap[3]) { + runlen += bmap[2]; + bmap += 2; + } + if (x + runlen > width) + cnt = width - x; + else + cnt = runlen; + draw_encoded_bitmap((ushort **)&fb, + cmap[bmap[1]], cnt); + } + x += runlen; + } + bmap += 2; + } + } +} +#endif + #if defined(CONFIG_MPC823) || defined(CONFIG_MCC200) #define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++) #else @@ -679,6 +809,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) unsigned long width, height, byte_width; unsigned long pwidth = panel_info.vl_col; unsigned colors, bpix, bmp_bpix; + unsigned long compression;
if (!bmp || !((bmp->header.signature[0] == 'B') && (bmp->header.signature[1] == 'M'))) { @@ -691,6 +822,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) height = le32_to_cpu(bmp->header.height); bmp_bpix = le16_to_cpu(bmp->header.bit_count); colors = 1 << bmp_bpix; + compression = le32_to_cpu(bmp->header.compression);
bpix = NBITS(panel_info.vl_bpix);
@@ -783,6 +915,18 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) switch (bmp_bpix) { case 1: /* pass through */ case 8: +#ifdef CONFIG_LCD_BMP_RLE8 + if (compression == BMP_BI_RLE8) { + if (bpix != 16) { + /* TODO implement render code for bpix != 16 */ + printf("Error: only support 16 bpix"); + return 1; + } + lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y); + break; + } +#endif + if (bpix != 16) byte_width = width; else

Acked-by: Che-Liang Chiou clchiou@chromium.org
On Fri, Sep 28, 2012 at 6:11 PM, Simon Glass sjg@chromium.org wrote:
From: Tom Wai-Hong Tam waihong@google.com
Add support for drawing compressed RLE8 bitmaps.
Reference: http://www.digicamsoft.com/bmp/bmp.html
Signed-off-by: Che-Liang Chiou clchiou@chromium.org Signed-off-by: Tom Wai-Hong Tam waihong@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
README | 5 ++ common/lcd.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/README b/README index 5793b0a..40899d9 100644 --- a/README +++ b/README @@ -1440,6 +1440,11 @@ The following options need to be configured: Normally display is black on white background; define CONFIG_SYS_WHITE_ON_BLACK to get it inverted.
CONFIG_LCD_BMP_RLE8
Support drawing of RLE8-compressed bitmaps on the LCD.
Splash Screen Support: CONFIG_SPLASH_SCREEN
If this option is set, the environment is checked for
diff --git a/common/lcd.c b/common/lcd.c index 004a6be..68df6d0 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -642,6 +642,136 @@ static void splash_align_axis(int *axis, unsigned long panel_size, } #endif
+#ifdef CONFIG_LCD_BMP_RLE8
+#define BMP_RLE8_ESCAPE 0 +#define BMP_RLE8_EOL 0 +#define BMP_RLE8_EOBMP 1 +#define BMP_RLE8_DELTA 2
+static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
int cnt)
+{
while (cnt > 0) {
*(*fbp)++ = cmap[*bmap++];
cnt--;
}
+}
+static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) +{
ushort *fb = *fbp;
int cnt_8copy = cnt >> 3;
cnt -= cnt_8copy << 3;
while (cnt_8copy > 0) {
*fb++ = c;
*fb++ = c;
*fb++ = c;
*fb++ = c;
*fb++ = c;
*fb++ = c;
*fb++ = c;
*fb++ = c;
cnt_8copy--;
}
while (cnt > 0) {
*fb++ = c;
cnt--;
}
(*fbp) = fb;
+}
+/* Do not call this function directly, must be called from
- lcd_display_bitmap.
- */
+static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb,
int x_off, int y_off)
+{
uchar *bmap;
ulong width, height;
ulong cnt, runlen;
int x, y;
int decode = 1;
width = le32_to_cpu(bmp->header.width);
height = le32_to_cpu(bmp->header.height);
bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
x = 0;
y = height - 1;
while (decode) {
if (bmap[0] == BMP_RLE8_ESCAPE) {
switch (bmap[1]) {
case BMP_RLE8_EOL:
/* end of line */
bmap += 2;
x = 0;
y--;
/* 16bpix, 2-byte per pixel, width should *2 */
fb -= (width * 2 + lcd_line_length);
break;
case BMP_RLE8_EOBMP:
/* end of bitmap */
decode = 0;
break;
case BMP_RLE8_DELTA:
/* delta run */
x += bmap[2];
y -= bmap[3];
/* 16bpix, 2-byte per pixel, x should *2 */
fb = (uchar *) (lcd_base + (y + y_off - 1)
* lcd_line_length + (x + x_off) * 2);
bmap += 4;
break;
default:
/* unencoded run */
runlen = bmap[1];
bmap += 2;
if (y < height) {
if (x < width) {
if (x + runlen > width)
cnt = width - x;
else
cnt = runlen;
draw_unencoded_bitmap(
(ushort **)&fb,
bmap, cmap, cnt);
}
x += runlen;
}
bmap += runlen;
if (runlen & 1)
bmap++;
}
} else {
/* encoded run */
if (y < height) {
runlen = bmap[0];
if (x < width) {
/* aggregate the same code */
while (bmap[0] == 0xff &&
bmap[2] != BMP_RLE8_ESCAPE &&
bmap[1] == bmap[3]) {
runlen += bmap[2];
bmap += 2;
}
if (x + runlen > width)
cnt = width - x;
else
cnt = runlen;
draw_encoded_bitmap((ushort **)&fb,
cmap[bmap[1]], cnt);
}
x += runlen;
}
bmap += 2;
}
}
+} +#endif
#if defined(CONFIG_MPC823) || defined(CONFIG_MCC200) #define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++) #else @@ -679,6 +809,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) unsigned long width, height, byte_width; unsigned long pwidth = panel_info.vl_col; unsigned colors, bpix, bmp_bpix;
unsigned long compression; if (!bmp || !((bmp->header.signature[0] == 'B') && (bmp->header.signature[1] == 'M'))) {
@@ -691,6 +822,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) height = le32_to_cpu(bmp->header.height); bmp_bpix = le16_to_cpu(bmp->header.bit_count); colors = 1 << bmp_bpix;
compression = le32_to_cpu(bmp->header.compression); bpix = NBITS(panel_info.vl_bpix);
@@ -783,6 +915,18 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) switch (bmp_bpix) { case 1: /* pass through */ case 8: +#ifdef CONFIG_LCD_BMP_RLE8
if (compression == BMP_BI_RLE8) {
if (bpix != 16) {
/* TODO implement render code for bpix != 16 */
printf("Error: only support 16 bpix");
return 1;
}
lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
break;
}
+#endif
if (bpix != 16) byte_width = width; else
-- 1.7.7.3

From: Vadim Bendebury vbendeb@chromium.org
The cfb console driver is trying to prevent bitmaps to spill over the screen, but the calculations assume that at least part of the bitmap fits into the screen area. In reality there could be bitmap elements which are completely out of the screen area, they just need to be discarded.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org
Signed-off-by: Simon Glass sjg@chromium.org --- drivers/video/cfb_console.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index c39d896..62ae4ee 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -1201,6 +1201,13 @@ int video_display_bitmap(ulong bmp_image, int x, int y)
padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
+ /* + * Just ignore elements which are completely beyond screen + * dimensions. + */ + if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS)) + return 0; + #ifdef CONFIG_SPLASH_SCREEN_ALIGN if (x == BMP_ALIGN_CENTER) x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);

Hi Simon,
On Fri, 28 Sep 2012 18:11:10 -0700 Simon Glass sjg@chromium.org wrote:
This series contains patches to create an API to read lcd/video parameters such as the screen size. It also adds support for displaying compressed bitmaps.
Ultimately it would be nice to unify lcd and video more, and this is a step towards that. Board files still need to decide which to use, but the same parameters are available in both.
Stefan Reinauer (2): video: Provide an API to access video parameters video: Implement additional video API functions in cfb_console
Tom Wai-Hong Tam (3): lcd: Fix BMP decode bug that skips the wrong padded row lcd: Fix fb offset calculation for bpix == 16 in BMP display lcd: Implement RLE8 bitmap decoding
Vadim Bendebury (2): lcd: Provide an API to access LCD parameters video: Skip bitmaps which do not fit into the screen in cfb_console
Applied this series to u-boot-video/master, except patch 5/7 which shouldn't be needed. Thanks!
Anatolij

Hi Anatolij,
On Tue, Nov 6, 2012 at 4:15 PM, Anatolij Gustschin agust@denx.de wrote:
Hi Simon,
On Fri, 28 Sep 2012 18:11:10 -0700 Simon Glass sjg@chromium.org wrote:
This series contains patches to create an API to read lcd/video parameters such as the screen size. It also adds support for displaying compressed bitmaps.
Ultimately it would be nice to unify lcd and video more, and this is a step towards that. Board files still need to decide which to use, but the same parameters are available in both.
Stefan Reinauer (2): video: Provide an API to access video parameters video: Implement additional video API functions in cfb_console
Tom Wai-Hong Tam (3): lcd: Fix BMP decode bug that skips the wrong padded row lcd: Fix fb offset calculation for bpix == 16 in BMP display lcd: Implement RLE8 bitmap decoding
Vadim Bendebury (2): lcd: Provide an API to access LCD parameters video: Skip bitmaps which do not fit into the screen in cfb_console
Applied this series to u-boot-video/master, except patch 5/7 which shouldn't be needed. Thanks!
Thanks, and thanks for the fixes.
Regards, Simon
Anatolij
participants (4)
-
Anatolij Gustschin
-
Che-liang Chiou
-
Nikita Kiryanov
-
Simon Glass