xref: /rk3399_rockchip-uboot/drivers/video/drm/bmp_helper.c (revision 8fd483da849f3e4d28c23fc8d96e8461cb1dcd60)
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 <command.h>
8 #include <log.h>
9 #include <config.h>
10 #include <common.h>
11 #include <malloc.h>
12 #include <asm/unaligned.h>
13 #include <bmp_layout.h>
14 
15 #define BMP_RLE8_ESCAPE		0
16 #define BMP_RLE8_EOL		0
17 #define BMP_RLE8_EOBMP		1
18 #define BMP_RLE8_DELTA		2
19 
20 static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
21 				  uint32_t cnt)
22 {
23 	while (cnt > 0) {
24 		*(*dst)++ = cmap[*bmap++];
25 		cnt--;
26 	}
27 }
28 
29 static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
30 {
31 	uint16_t *fb = *dst;
32 	int cnt_8copy = cnt >> 3;
33 
34 	cnt -= cnt_8copy << 3;
35 	while (cnt_8copy > 0) {
36 		*fb++ = c;
37 		*fb++ = c;
38 		*fb++ = c;
39 		*fb++ = c;
40 		*fb++ = c;
41 		*fb++ = c;
42 		*fb++ = c;
43 		*fb++ = c;
44 		cnt_8copy--;
45 	}
46 	while (cnt > 0) {
47 		*fb++ = c;
48 		cnt--;
49 	}
50 	*dst = fb;
51 }
52 
53 static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap,
54 			       int width, int height, int bits, int x_off,
55 			       int y_off, bool flip)
56 {
57 	uint32_t cnt, runlen;
58 	int x = 0, y = 0;
59 	int decode = 1;
60 	int linesize = width * 2;
61 	uint8_t *bmap = psrc;
62 	uint8_t *dst = pdst;
63 
64 	if (flip) {
65 		y = height - 1;
66 		dst = pdst + y * linesize;
67 	}
68 
69 	while (decode) {
70 		if (bmap[0] == BMP_RLE8_ESCAPE) {
71 			switch (bmap[1]) {
72 			case BMP_RLE8_EOL:
73 				/* end of line */
74 				bmap += 2;
75 				x = 0;
76 				if (flip) {
77 					y--;
78 					dst -= linesize * 2;
79 				} else {
80 					y++;
81 				}
82 				break;
83 			case BMP_RLE8_EOBMP:
84 				/* end of bitmap */
85 				decode = 0;
86 				break;
87 			case BMP_RLE8_DELTA:
88 				/* delta run */
89 				x += bmap[2];
90 				if (flip) {
91 					y -= bmap[3];
92 					dst -= bmap[3] * linesize;
93 					dst += bmap[2] * 2;
94 				} else {
95 					y += bmap[3];
96 					dst += bmap[3] * linesize;
97 					dst += bmap[2] * 2;
98 				}
99 				bmap += 4;
100 				break;
101 			default:
102 				/* unencoded run */
103 				runlen = bmap[1];
104 				bmap += 2;
105 				if (y >= height || x >= width) {
106 					decode = 0;
107 					break;
108 				}
109 				if (x + runlen > width)
110 					cnt = width - x;
111 				else
112 					cnt = runlen;
113 				draw_unencoded_bitmap((uint16_t **)&dst, bmap,
114 						      cmap, cnt);
115 				x += runlen;
116 				bmap += runlen;
117 				if (runlen & 1)
118 					bmap++;
119 			}
120 		} else {
121 			/* encoded run */
122 			if (y < height) {
123 				runlen = bmap[0];
124 				if (x < width) {
125 					/* aggregate the same code */
126 					while (bmap[0] == 0xff &&
127 					       bmap[2] != BMP_RLE8_ESCAPE &&
128 					       bmap[1] == bmap[3]) {
129 						runlen += bmap[2];
130 						bmap += 2;
131 					}
132 					if (x + runlen > width)
133 						cnt = width - x;
134 					else
135 						cnt = runlen;
136 					draw_encoded_bitmap((uint16_t **)&dst,
137 							    cmap[bmap[1]], cnt);
138 				}
139 				x += runlen;
140 			}
141 			bmap += 2;
142 		}
143 	}
144 }
145 
146 static void dump_bmp_dib_head(void *bmp_addr)
147 {
148 	struct bmp_image *bmp = bmp_addr;
149 
150 	debug("########## BMP DIB_HEAD ##########\n"
151 	      "Width  : %u\n"
152 	      "Height : %u\n"
153 	      "Bpp    : %u\n"
154 	      "Compression method : %u\n"
155 	      "Image size : %u\n"
156 	      "Colors in palette  : %u\n"
157 	      "##################################\n",
158 		bmp->header.width,
159 		bmp->header.height,
160 		bmp->header.bit_count,
161 		bmp->header.compression,
162 		bmp->header.image_size,
163 		bmp->header.colors_used);
164 }
165 
166 int bmpdecoder(void *bmp_addr, void *pdst, int dst_bpp)
167 {
168 	int i, j;
169 	int stride, padded_width, bpp, width, height;
170 	struct bmp_image *bmp = bmp_addr;
171 	uint8_t *src = bmp_addr;
172 	uint8_t *dst = pdst;
173 	bool flip = false;
174 	uint16_t *cmap;
175 	uint8_t *cmap_base;
176 
177 	if (!bmp || !(bmp->header.signature[0] == 'B' &&
178 	    bmp->header.signature[1] == 'M')) {
179 		printf("Error: Invalid bmp file.\n");
180 		return -1;
181 	}
182 	dump_bmp_dib_head(bmp);
183 	width = get_unaligned_le32(&bmp->header.width);
184 	height = get_unaligned_le32(&bmp->header.height);
185 	bpp = get_unaligned_le16(&bmp->header.bit_count);
186 	padded_width = width & 0x3 ? (width & ~0x3) + 4 : width;
187 
188 	if (height < 0)
189 		height = 0 - height;
190 	else
191 		flip = true;
192 
193 	cmap_base = src + sizeof(bmp->header);
194 	src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset);
195 
196 	switch (bpp) {
197 	case 8:
198 		if (dst_bpp != 16) {
199 			printf("Error: Target pixel's bpp is not 16bit.\n");
200 
201 			return -1;
202 		}
203 		cmap = malloc(sizeof(cmap) * 256);
204 
205 		/* Set color map */
206 		for (i = 0; i < 256; i++) {
207 			ushort colreg = ((cmap_base[0] << 8) & 0xf800) |
208 					((cmap_base[1] << 3) & 0x07e0) |
209 					((cmap_base[2] >> 3) & 0x001f) ;
210 			cmap_base += 4;
211 			cmap[i] = colreg;
212 		}
213 		/*
214 		 * only support convert 8bit bmap file to RGB565.
215 		 */
216 		if (get_unaligned_le32(&bmp->header.compression)) {
217 			decode_rle8_bitmap(src, dst, cmap, width, height,
218 					   bpp, 0, 0, flip);
219 		} else {
220 			stride = width * 2;
221 
222 			if (flip)
223 				dst += stride * (height - 1);
224 
225 			for (i = 0; i < height; ++i) {
226 				for (j = 0; j < width; j++) {
227 					*(uint16_t *)dst = cmap[*(src++)];
228 					dst += sizeof(uint16_t) / sizeof(*dst);
229 				}
230 				src += (padded_width - width);
231 				if (flip)
232 					dst -= stride * 2;
233 			}
234 		}
235 		free(cmap);
236 		break;
237 	case 16:
238 		if (get_unaligned_le32(&bmp->header.compression)) {
239 			printf("Error: Failed to decompression bmp file.\n");
240 
241 			return -1;
242 		}
243 		stride = ALIGN(width * bpp / 8, 4);
244 		if (flip)
245 			src += stride * (height - 1);
246 		for (i = 0; i < height; i++) {
247 			for (j = 0; j < width; j++) {
248 				ushort color = (src[1] << 8) | src[0];
249 
250 				color = (((color & 0x7c00) << 1) |
251 					((color & 0x03e0) << 1) |
252 					(color & 0x001f));
253 				*(uint16_t *)dst = color;
254 				src += 2;
255 				dst += 2;
256 			}
257 			src += (padded_width - width);
258 			if (flip)
259 				src -= stride * 2;
260 		}
261 		break;
262 	case 24:
263 		if (get_unaligned_le32(&bmp->header.compression)) {
264 			printf("Error: Failed to decompression bmp file.\n");
265 
266 			return -1;
267 		}
268 		stride = ALIGN(width * 3, 4);
269 		if (flip)
270 			src += stride * (height - 1);
271 
272 		for (i = 0; i < height; i++) {
273 			memcpy(dst, src, 3 * width);
274 			dst += stride;
275 			src += stride;
276 			if (flip)
277 				src -= stride * 2;
278 		}
279 		break;
280 	case 32:
281 		if (get_unaligned_le32(&bmp->header.compression)) {
282 			printf("Error: Failed to decompression bmp file.\n");
283 
284 			return -1;
285 		}
286 		stride = ALIGN(width * 4, 4);
287 		if (flip)
288 			src += stride * (height - 1);
289 
290 		for (i = 0; i < height; i++) {
291 			memcpy(dst, src, 4 * width);
292 			dst += stride;
293 			src += stride;
294 			if (flip)
295 				src -= stride * 2;
296 		}
297 		break;
298 	default:
299 		printf("Error: Can't decode this bmp file with bit=%d\n", bpp);
300 		return -1;
301 	}
302 
303 	return 0;
304 }
305