xref: /rk3399_rockchip-uboot/drivers/video/drm/bmp_helper.c (revision 859836bc0c771109e88026ba2bba8ce55afc90f1)
1186f8572SMark Yao /*
2186f8572SMark Yao  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3186f8572SMark Yao  * Author: Mark Yao <mark.yao@rock-chips.com>
4186f8572SMark Yao  *
5186f8572SMark Yao  * SPDX-License-Identifier:	GPL-2.0+
6186f8572SMark Yao  */
7186f8572SMark Yao #include <config.h>
8186f8572SMark Yao #include <common.h>
9186f8572SMark Yao #include <malloc.h>
10186f8572SMark Yao #include <asm/unaligned.h>
11186f8572SMark Yao #include <bmp_layout.h>
12186f8572SMark Yao 
13186f8572SMark Yao #define BMP_RLE8_ESCAPE		0
14186f8572SMark Yao #define BMP_RLE8_EOL		0
15186f8572SMark Yao #define BMP_RLE8_EOBMP		1
16186f8572SMark Yao #define BMP_RLE8_DELTA		2
17186f8572SMark Yao 
draw_unencoded_bitmap(uint16_t ** dst,uint8_t * bmap,uint16_t * cmap,uint32_t cnt)18186f8572SMark Yao static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
19186f8572SMark Yao 				  uint32_t cnt)
20186f8572SMark Yao {
21186f8572SMark Yao 	while (cnt > 0) {
22186f8572SMark Yao 		*(*dst)++ = cmap[*bmap++];
23186f8572SMark Yao 		cnt--;
24186f8572SMark Yao 	}
25186f8572SMark Yao }
26186f8572SMark Yao 
draw_encoded_bitmap(uint16_t ** dst,uint16_t c,uint32_t cnt)27186f8572SMark Yao static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
28186f8572SMark Yao {
29186f8572SMark Yao 	uint16_t *fb = *dst;
30186f8572SMark Yao 	int cnt_8copy = cnt >> 3;
31186f8572SMark Yao 
32186f8572SMark Yao 	cnt -= cnt_8copy << 3;
33186f8572SMark Yao 	while (cnt_8copy > 0) {
34186f8572SMark Yao 		*fb++ = c;
35186f8572SMark Yao 		*fb++ = c;
36186f8572SMark Yao 		*fb++ = c;
37186f8572SMark Yao 		*fb++ = c;
38186f8572SMark Yao 		*fb++ = c;
39186f8572SMark Yao 		*fb++ = c;
40186f8572SMark Yao 		*fb++ = c;
41186f8572SMark Yao 		*fb++ = c;
42186f8572SMark Yao 		cnt_8copy--;
43186f8572SMark Yao 	}
44186f8572SMark Yao 	while (cnt > 0) {
45186f8572SMark Yao 		*fb++ = c;
46186f8572SMark Yao 		cnt--;
47186f8572SMark Yao 	}
48186f8572SMark Yao 	*dst = fb;
49186f8572SMark Yao }
50186f8572SMark Yao 
decode_rle8_bitmap(void * psrc,void * pdst,uint16_t * cmap,int width,int height,int bits,int x_off,int y_off,bool flip)51186f8572SMark Yao static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap,
52186f8572SMark Yao 			       int width, int height, int bits, int x_off,
53186f8572SMark Yao 			       int y_off, bool flip)
54186f8572SMark Yao {
55186f8572SMark Yao 	uint32_t cnt, runlen;
56186f8572SMark Yao 	int x = 0, y = 0;
57186f8572SMark Yao 	int decode = 1;
58186f8572SMark Yao 	int linesize = width * 2;
59186f8572SMark Yao 	uint8_t *bmap = psrc;
60186f8572SMark Yao 	uint8_t *dst = pdst;
61186f8572SMark Yao 
62186f8572SMark Yao 	if (flip) {
63186f8572SMark Yao 		y = height - 1;
64186f8572SMark Yao 		dst = pdst + y * linesize;
65186f8572SMark Yao 	}
66186f8572SMark Yao 
67186f8572SMark Yao 	while (decode) {
68186f8572SMark Yao 		if (bmap[0] == BMP_RLE8_ESCAPE) {
69186f8572SMark Yao 			switch (bmap[1]) {
70186f8572SMark Yao 			case BMP_RLE8_EOL:
71186f8572SMark Yao 				/* end of line */
72186f8572SMark Yao 				bmap += 2;
73186f8572SMark Yao 				x = 0;
74186f8572SMark Yao 				if (flip) {
75186f8572SMark Yao 					y--;
76186f8572SMark Yao 					dst -= linesize * 2;
77186f8572SMark Yao 				} else {
78186f8572SMark Yao 					y++;
79186f8572SMark Yao 				}
80186f8572SMark Yao 				break;
81186f8572SMark Yao 			case BMP_RLE8_EOBMP:
82186f8572SMark Yao 				/* end of bitmap */
83186f8572SMark Yao 				decode = 0;
84186f8572SMark Yao 				break;
85186f8572SMark Yao 			case BMP_RLE8_DELTA:
86186f8572SMark Yao 				/* delta run */
87186f8572SMark Yao 				x += bmap[2];
88186f8572SMark Yao 				if (flip) {
89186f8572SMark Yao 					y -= bmap[3];
90186f8572SMark Yao 					dst -= bmap[3] * linesize;
91186f8572SMark Yao 					dst += bmap[2] * 2;
92186f8572SMark Yao 				} else {
93186f8572SMark Yao 					y += bmap[3];
94186f8572SMark Yao 					dst += bmap[3] * linesize;
95186f8572SMark Yao 					dst += bmap[2] * 2;
96186f8572SMark Yao 				}
97186f8572SMark Yao 				bmap += 4;
98186f8572SMark Yao 				break;
99186f8572SMark Yao 			default:
100186f8572SMark Yao 				/* unencoded run */
101186f8572SMark Yao 				runlen = bmap[1];
102186f8572SMark Yao 				bmap += 2;
103186f8572SMark Yao 				if (y >= height || x >= width) {
104186f8572SMark Yao 					decode = 0;
105186f8572SMark Yao 					break;
106186f8572SMark Yao 				}
107186f8572SMark Yao 				if (x + runlen > width)
108186f8572SMark Yao 					cnt = width - x;
109186f8572SMark Yao 				else
110186f8572SMark Yao 					cnt = runlen;
111186f8572SMark Yao 				draw_unencoded_bitmap((uint16_t **)&dst, bmap,
112186f8572SMark Yao 						      cmap, cnt);
113186f8572SMark Yao 				x += runlen;
114186f8572SMark Yao 				bmap += runlen;
115186f8572SMark Yao 				if (runlen & 1)
116186f8572SMark Yao 					bmap++;
117186f8572SMark Yao 			}
118186f8572SMark Yao 		} else {
119186f8572SMark Yao 			/* encoded run */
120186f8572SMark Yao 			if (y < height) {
121186f8572SMark Yao 				runlen = bmap[0];
122186f8572SMark Yao 				if (x < width) {
123186f8572SMark Yao 					/* aggregate the same code */
124186f8572SMark Yao 					while (bmap[0] == 0xff &&
125186f8572SMark Yao 					       bmap[2] != BMP_RLE8_ESCAPE &&
126186f8572SMark Yao 					       bmap[1] == bmap[3]) {
127186f8572SMark Yao 						runlen += bmap[2];
128186f8572SMark Yao 						bmap += 2;
129186f8572SMark Yao 					}
130186f8572SMark Yao 					if (x + runlen > width)
131186f8572SMark Yao 						cnt = width - x;
132186f8572SMark Yao 					else
133186f8572SMark Yao 						cnt = runlen;
134186f8572SMark Yao 					draw_encoded_bitmap((uint16_t **)&dst,
135186f8572SMark Yao 							    cmap[bmap[1]], cnt);
136186f8572SMark Yao 				}
137186f8572SMark Yao 				x += runlen;
138186f8572SMark Yao 			}
139186f8572SMark Yao 			bmap += 2;
140186f8572SMark Yao 		}
141186f8572SMark Yao 	}
142186f8572SMark Yao }
143186f8572SMark Yao 
bmpdecoder(void * bmp_addr,void * pdst,int dst_bpp)14455e2f86dSSandy Huang int bmpdecoder(void *bmp_addr, void *pdst, int dst_bpp)
145186f8572SMark Yao {
146861ce1a0SSandy Huang 	int stride, padded_width, bpp, i, width, height;
147186f8572SMark Yao 	struct bmp_image *bmp = bmp_addr;
148186f8572SMark Yao 	uint8_t *src = bmp_addr;
149186f8572SMark Yao 	uint8_t *dst = pdst;
15055e2f86dSSandy Huang 	bool flip = false;
151186f8572SMark Yao 	uint16_t *cmap;
152186f8572SMark Yao 	uint8_t *cmap_base;
153186f8572SMark Yao 
154186f8572SMark Yao 	if (!bmp || !(bmp->header.signature[0] == 'B' &&
155186f8572SMark Yao 	    bmp->header.signature[1] == 'M')) {
156861ce1a0SSandy Huang 		printf("cat not find bmp file\n");
157186f8572SMark Yao 		return -1;
158186f8572SMark Yao 	}
159186f8572SMark Yao 	width = get_unaligned_le32(&bmp->header.width);
160186f8572SMark Yao 	height = get_unaligned_le32(&bmp->header.height);
161186f8572SMark Yao 	bpp = get_unaligned_le16(&bmp->header.bit_count);
162186f8572SMark Yao 	padded_width = width & 0x3 ? (width & ~0x3) + 4 : width;
163186f8572SMark Yao 
16455e2f86dSSandy Huang 	if (height < 0)
165186f8572SMark Yao 		height = 0 - height;
16655e2f86dSSandy Huang 	else
16755e2f86dSSandy Huang 		flip = true;
16855e2f86dSSandy Huang 
169186f8572SMark Yao 	cmap_base = src + sizeof(bmp->header);
170186f8572SMark Yao 	src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset);
171186f8572SMark Yao 
172186f8572SMark Yao 	switch (bpp) {
173186f8572SMark Yao 	case 8:
174186f8572SMark Yao 		if (dst_bpp != 16) {
175861ce1a0SSandy Huang 			printf("can't support covert bmap to bit[%d]\n",
176861ce1a0SSandy Huang 			       dst_bpp);
177186f8572SMark Yao 			return -1;
178186f8572SMark Yao 		}
179186f8572SMark Yao 		cmap = malloc(sizeof(cmap) * 256);
180186f8572SMark Yao 
181186f8572SMark Yao 		/* Set color map */
182186f8572SMark Yao 		for (i = 0; i < 256; i++) {
183*859836bcSSandy Huang 			ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
184186f8572SMark Yao 					((cmap_base[1] << 3) & 0x07e0) |
185*859836bcSSandy Huang 					((cmap_base[0] >> 3) & 0x001f) ;
186186f8572SMark Yao 			cmap_base += 4;
187186f8572SMark Yao 			cmap[i] = colreg;
188186f8572SMark Yao 		}
189186f8572SMark Yao 		/*
190186f8572SMark Yao 		 * only support convert 8bit bmap file to RGB565.
191186f8572SMark Yao 		 */
192186f8572SMark Yao 		if (get_unaligned_le32(&bmp->header.compression)) {
193186f8572SMark Yao 			decode_rle8_bitmap(src, dst, cmap, width, height,
194186f8572SMark Yao 					   bpp, 0, 0, flip);
195186f8572SMark Yao 		} else {
196861ce1a0SSandy Huang 			int j;
197186f8572SMark Yao 			stride = width * 2;
198186f8572SMark Yao 
199186f8572SMark Yao 			if (flip)
200186f8572SMark Yao 				dst += stride * (height - 1);
201186f8572SMark Yao 
202186f8572SMark Yao 			for (i = 0; i < height; ++i) {
203186f8572SMark Yao 				for (j = 0; j < width; j++) {
204186f8572SMark Yao 					*(uint16_t *)dst = cmap[*(src++)];
205186f8572SMark Yao 					dst += sizeof(uint16_t) / sizeof(*dst);
206186f8572SMark Yao 				}
207186f8572SMark Yao 				src += (padded_width - width);
208186f8572SMark Yao 				if (flip)
209186f8572SMark Yao 					dst -= stride * 2;
210186f8572SMark Yao 			}
211186f8572SMark Yao 		}
212186f8572SMark Yao 		free(cmap);
213186f8572SMark Yao 		break;
214186f8572SMark Yao 	case 24:
215186f8572SMark Yao 		if (get_unaligned_le32(&bmp->header.compression)) {
216861ce1a0SSandy Huang 			printf("can't not support compression for 24bit bmap");
217186f8572SMark Yao 			return -1;
218186f8572SMark Yao 		}
219186f8572SMark Yao 		stride = ALIGN(width * 3, 4);
220186f8572SMark Yao 		if (flip)
221186f8572SMark Yao 			src += stride * (height - 1);
222186f8572SMark Yao 
223186f8572SMark Yao 		for (i = 0; i < height; i++) {
224186f8572SMark Yao 			memcpy(dst, src, 3 * width);
225186f8572SMark Yao 			dst += stride;
226186f8572SMark Yao 			src += stride;
227186f8572SMark Yao 			if (flip)
228186f8572SMark Yao 				src -= stride * 2;
229186f8572SMark Yao 		}
230186f8572SMark Yao 		break;
231861ce1a0SSandy Huang 	case 16:
232186f8572SMark Yao 	case 32:
233186f8572SMark Yao 	default:
234861ce1a0SSandy Huang 		printf("unsupport bit=%d now\n", bpp);
235186f8572SMark Yao 		return -1;
236186f8572SMark Yao 	}
237186f8572SMark Yao 
238186f8572SMark Yao 	return 0;
239186f8572SMark Yao }
240