diff options
| author | Tom Wai-Hong Tam <waihong@google.com> | 2012-09-28 15:11:16 +0000 | 
|---|---|---|
| committer | Anatolij Gustschin <agust@denx.de> | 2012-11-07 00:57:25 +0100 | 
| commit | 45d7f52511f43b71b623a502fdf31feb905f70a1 (patch) | |
| tree | 194655130bc8927197f15a6d09b85e69d45a140c /common/lcd.c | |
| parent | fecac46cf8757dc4f00a7812310e060f3b0c6eb4 (diff) | |
| download | olio-uboot-2014.01-45d7f52511f43b71b623a502fdf31feb905f70a1.tar.xz olio-uboot-2014.01-45d7f52511f43b71b623a502fdf31feb905f70a1.zip | |
lcd: Implement RLE8 bitmap decoding
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>
Acked-by: Che-Liang Chiou <clchiou@chromium.org>
[agust: fix some minor style issues and build warnings]
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'common/lcd.c')
| -rw-r--r-- | common/lcd.c | 144 | 
1 files changed, 144 insertions, 0 deletions
| diff --git a/common/lcd.c b/common/lcd.c index 7c6cb096f..4c83a8bf0 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -642,6 +642,138 @@ 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 @@ -781,6 +913,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 (le32_to_cpu(bmp->header.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 |