xref: /OK3568_Linux_fs/u-boot/drivers/video/drm/bmp_helper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  * Author: Mark Yao <mark.yao@rock-chips.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <config.h>
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <malloc.h>
10*4882a593Smuzhiyun #include <asm/unaligned.h>
11*4882a593Smuzhiyun #include <bmp_layout.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define BMP_RLE8_ESCAPE		0
14*4882a593Smuzhiyun #define BMP_RLE8_EOL		0
15*4882a593Smuzhiyun #define BMP_RLE8_EOBMP		1
16*4882a593Smuzhiyun #define BMP_RLE8_DELTA		2
17*4882a593Smuzhiyun 
draw_unencoded_bitmap(uint16_t ** dst,uint8_t * bmap,uint16_t * cmap,uint32_t cnt)18*4882a593Smuzhiyun static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
19*4882a593Smuzhiyun 				  uint32_t cnt)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	while (cnt > 0) {
22*4882a593Smuzhiyun 		*(*dst)++ = cmap[*bmap++];
23*4882a593Smuzhiyun 		cnt--;
24*4882a593Smuzhiyun 	}
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun 
draw_encoded_bitmap(uint16_t ** dst,uint16_t c,uint32_t cnt)27*4882a593Smuzhiyun static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	uint16_t *fb = *dst;
30*4882a593Smuzhiyun 	int cnt_8copy = cnt >> 3;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	cnt -= cnt_8copy << 3;
33*4882a593Smuzhiyun 	while (cnt_8copy > 0) {
34*4882a593Smuzhiyun 		*fb++ = c;
35*4882a593Smuzhiyun 		*fb++ = c;
36*4882a593Smuzhiyun 		*fb++ = c;
37*4882a593Smuzhiyun 		*fb++ = c;
38*4882a593Smuzhiyun 		*fb++ = c;
39*4882a593Smuzhiyun 		*fb++ = c;
40*4882a593Smuzhiyun 		*fb++ = c;
41*4882a593Smuzhiyun 		*fb++ = c;
42*4882a593Smuzhiyun 		cnt_8copy--;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 	while (cnt > 0) {
45*4882a593Smuzhiyun 		*fb++ = c;
46*4882a593Smuzhiyun 		cnt--;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 	*dst = fb;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
decode_rle8_bitmap(void * psrc,void * pdst,uint16_t * cmap,int width,int height,int bits,int x_off,int y_off,bool flip)51*4882a593Smuzhiyun static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap,
52*4882a593Smuzhiyun 			       int width, int height, int bits, int x_off,
53*4882a593Smuzhiyun 			       int y_off, bool flip)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	uint32_t cnt, runlen;
56*4882a593Smuzhiyun 	int x = 0, y = 0;
57*4882a593Smuzhiyun 	int decode = 1;
58*4882a593Smuzhiyun 	int linesize = width * 2;
59*4882a593Smuzhiyun 	uint8_t *bmap = psrc;
60*4882a593Smuzhiyun 	uint8_t *dst = pdst;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	if (flip) {
63*4882a593Smuzhiyun 		y = height - 1;
64*4882a593Smuzhiyun 		dst = pdst + y * linesize;
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	while (decode) {
68*4882a593Smuzhiyun 		if (bmap[0] == BMP_RLE8_ESCAPE) {
69*4882a593Smuzhiyun 			switch (bmap[1]) {
70*4882a593Smuzhiyun 			case BMP_RLE8_EOL:
71*4882a593Smuzhiyun 				/* end of line */
72*4882a593Smuzhiyun 				bmap += 2;
73*4882a593Smuzhiyun 				x = 0;
74*4882a593Smuzhiyun 				if (flip) {
75*4882a593Smuzhiyun 					y--;
76*4882a593Smuzhiyun 					dst -= linesize * 2;
77*4882a593Smuzhiyun 				} else {
78*4882a593Smuzhiyun 					y++;
79*4882a593Smuzhiyun 				}
80*4882a593Smuzhiyun 				break;
81*4882a593Smuzhiyun 			case BMP_RLE8_EOBMP:
82*4882a593Smuzhiyun 				/* end of bitmap */
83*4882a593Smuzhiyun 				decode = 0;
84*4882a593Smuzhiyun 				break;
85*4882a593Smuzhiyun 			case BMP_RLE8_DELTA:
86*4882a593Smuzhiyun 				/* delta run */
87*4882a593Smuzhiyun 				x += bmap[2];
88*4882a593Smuzhiyun 				if (flip) {
89*4882a593Smuzhiyun 					y -= bmap[3];
90*4882a593Smuzhiyun 					dst -= bmap[3] * linesize;
91*4882a593Smuzhiyun 					dst += bmap[2] * 2;
92*4882a593Smuzhiyun 				} else {
93*4882a593Smuzhiyun 					y += bmap[3];
94*4882a593Smuzhiyun 					dst += bmap[3] * linesize;
95*4882a593Smuzhiyun 					dst += bmap[2] * 2;
96*4882a593Smuzhiyun 				}
97*4882a593Smuzhiyun 				bmap += 4;
98*4882a593Smuzhiyun 				break;
99*4882a593Smuzhiyun 			default:
100*4882a593Smuzhiyun 				/* unencoded run */
101*4882a593Smuzhiyun 				runlen = bmap[1];
102*4882a593Smuzhiyun 				bmap += 2;
103*4882a593Smuzhiyun 				if (y >= height || x >= width) {
104*4882a593Smuzhiyun 					decode = 0;
105*4882a593Smuzhiyun 					break;
106*4882a593Smuzhiyun 				}
107*4882a593Smuzhiyun 				if (x + runlen > width)
108*4882a593Smuzhiyun 					cnt = width - x;
109*4882a593Smuzhiyun 				else
110*4882a593Smuzhiyun 					cnt = runlen;
111*4882a593Smuzhiyun 				draw_unencoded_bitmap((uint16_t **)&dst, bmap,
112*4882a593Smuzhiyun 						      cmap, cnt);
113*4882a593Smuzhiyun 				x += runlen;
114*4882a593Smuzhiyun 				bmap += runlen;
115*4882a593Smuzhiyun 				if (runlen & 1)
116*4882a593Smuzhiyun 					bmap++;
117*4882a593Smuzhiyun 			}
118*4882a593Smuzhiyun 		} else {
119*4882a593Smuzhiyun 			/* encoded run */
120*4882a593Smuzhiyun 			if (y < height) {
121*4882a593Smuzhiyun 				runlen = bmap[0];
122*4882a593Smuzhiyun 				if (x < width) {
123*4882a593Smuzhiyun 					/* aggregate the same code */
124*4882a593Smuzhiyun 					while (bmap[0] == 0xff &&
125*4882a593Smuzhiyun 					       bmap[2] != BMP_RLE8_ESCAPE &&
126*4882a593Smuzhiyun 					       bmap[1] == bmap[3]) {
127*4882a593Smuzhiyun 						runlen += bmap[2];
128*4882a593Smuzhiyun 						bmap += 2;
129*4882a593Smuzhiyun 					}
130*4882a593Smuzhiyun 					if (x + runlen > width)
131*4882a593Smuzhiyun 						cnt = width - x;
132*4882a593Smuzhiyun 					else
133*4882a593Smuzhiyun 						cnt = runlen;
134*4882a593Smuzhiyun 					draw_encoded_bitmap((uint16_t **)&dst,
135*4882a593Smuzhiyun 							    cmap[bmap[1]], cnt);
136*4882a593Smuzhiyun 				}
137*4882a593Smuzhiyun 				x += runlen;
138*4882a593Smuzhiyun 			}
139*4882a593Smuzhiyun 			bmap += 2;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
bmpdecoder(void * bmp_addr,void * pdst,int dst_bpp)144*4882a593Smuzhiyun int bmpdecoder(void *bmp_addr, void *pdst, int dst_bpp)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int stride, padded_width, bpp, i, width, height;
147*4882a593Smuzhiyun 	struct bmp_image *bmp = bmp_addr;
148*4882a593Smuzhiyun 	uint8_t *src = bmp_addr;
149*4882a593Smuzhiyun 	uint8_t *dst = pdst;
150*4882a593Smuzhiyun 	bool flip = false;
151*4882a593Smuzhiyun 	uint16_t *cmap;
152*4882a593Smuzhiyun 	uint8_t *cmap_base;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	if (!bmp || !(bmp->header.signature[0] == 'B' &&
155*4882a593Smuzhiyun 	    bmp->header.signature[1] == 'M')) {
156*4882a593Smuzhiyun 		printf("cat not find bmp file\n");
157*4882a593Smuzhiyun 		return -1;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 	width = get_unaligned_le32(&bmp->header.width);
160*4882a593Smuzhiyun 	height = get_unaligned_le32(&bmp->header.height);
161*4882a593Smuzhiyun 	bpp = get_unaligned_le16(&bmp->header.bit_count);
162*4882a593Smuzhiyun 	padded_width = width & 0x3 ? (width & ~0x3) + 4 : width;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (height < 0)
165*4882a593Smuzhiyun 		height = 0 - height;
166*4882a593Smuzhiyun 	else
167*4882a593Smuzhiyun 		flip = true;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	cmap_base = src + sizeof(bmp->header);
170*4882a593Smuzhiyun 	src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	switch (bpp) {
173*4882a593Smuzhiyun 	case 8:
174*4882a593Smuzhiyun 		if (dst_bpp != 16) {
175*4882a593Smuzhiyun 			printf("can't support covert bmap to bit[%d]\n",
176*4882a593Smuzhiyun 			       dst_bpp);
177*4882a593Smuzhiyun 			return -1;
178*4882a593Smuzhiyun 		}
179*4882a593Smuzhiyun 		cmap = malloc(sizeof(cmap) * 256);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 		/* Set color map */
182*4882a593Smuzhiyun 		for (i = 0; i < 256; i++) {
183*4882a593Smuzhiyun 			ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
184*4882a593Smuzhiyun 					((cmap_base[1] << 3) & 0x07e0) |
185*4882a593Smuzhiyun 					((cmap_base[0] >> 3) & 0x001f) ;
186*4882a593Smuzhiyun 			cmap_base += 4;
187*4882a593Smuzhiyun 			cmap[i] = colreg;
188*4882a593Smuzhiyun 		}
189*4882a593Smuzhiyun 		/*
190*4882a593Smuzhiyun 		 * only support convert 8bit bmap file to RGB565.
191*4882a593Smuzhiyun 		 */
192*4882a593Smuzhiyun 		if (get_unaligned_le32(&bmp->header.compression)) {
193*4882a593Smuzhiyun 			decode_rle8_bitmap(src, dst, cmap, width, height,
194*4882a593Smuzhiyun 					   bpp, 0, 0, flip);
195*4882a593Smuzhiyun 		} else {
196*4882a593Smuzhiyun 			int j;
197*4882a593Smuzhiyun 			stride = width * 2;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 			if (flip)
200*4882a593Smuzhiyun 				dst += stride * (height - 1);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 			for (i = 0; i < height; ++i) {
203*4882a593Smuzhiyun 				for (j = 0; j < width; j++) {
204*4882a593Smuzhiyun 					*(uint16_t *)dst = cmap[*(src++)];
205*4882a593Smuzhiyun 					dst += sizeof(uint16_t) / sizeof(*dst);
206*4882a593Smuzhiyun 				}
207*4882a593Smuzhiyun 				src += (padded_width - width);
208*4882a593Smuzhiyun 				if (flip)
209*4882a593Smuzhiyun 					dst -= stride * 2;
210*4882a593Smuzhiyun 			}
211*4882a593Smuzhiyun 		}
212*4882a593Smuzhiyun 		free(cmap);
213*4882a593Smuzhiyun 		break;
214*4882a593Smuzhiyun 	case 24:
215*4882a593Smuzhiyun 		if (get_unaligned_le32(&bmp->header.compression)) {
216*4882a593Smuzhiyun 			printf("can't not support compression for 24bit bmap");
217*4882a593Smuzhiyun 			return -1;
218*4882a593Smuzhiyun 		}
219*4882a593Smuzhiyun 		stride = ALIGN(width * 3, 4);
220*4882a593Smuzhiyun 		if (flip)
221*4882a593Smuzhiyun 			src += stride * (height - 1);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		for (i = 0; i < height; i++) {
224*4882a593Smuzhiyun 			memcpy(dst, src, 3 * width);
225*4882a593Smuzhiyun 			dst += stride;
226*4882a593Smuzhiyun 			src += stride;
227*4882a593Smuzhiyun 			if (flip)
228*4882a593Smuzhiyun 				src -= stride * 2;
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 		break;
231*4882a593Smuzhiyun 	case 16:
232*4882a593Smuzhiyun 	case 32:
233*4882a593Smuzhiyun 	default:
234*4882a593Smuzhiyun 		printf("unsupport bit=%d now\n", bpp);
235*4882a593Smuzhiyun 		return -1;
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240