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