xref: /rk3399_rockchip-uboot/drivers/video/drm/bmp_helper.c (revision 2c6a058b7ea25398013cb25b4e3bb96fe40da1a5)
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, bool flip)
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 	uint16_t *cmap;
174 	uint8_t *cmap_base;
175 
176 	if (!bmp || !(bmp->header.signature[0] == 'B' &&
177 	    bmp->header.signature[1] == 'M')) {
178 		printf("Error: Invalid bmp file.\n");
179 		return -1;
180 	}
181 	dump_bmp_dib_head(bmp);
182 	width = get_unaligned_le32(&bmp->header.width);
183 	height = get_unaligned_le32(&bmp->header.height);
184 	bpp = get_unaligned_le16(&bmp->header.bit_count);
185 	padded_width = width & 0x3 ? (width & ~0x3) + 4 : width;
186 
187 	if (height < 0) {
188 		height = 0 - height;
189 		flip = false;
190 	}
191 	cmap_base = src + sizeof(bmp->header);
192 	src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset);
193 
194 	switch (bpp) {
195 	case 8:
196 		if (dst_bpp != 16) {
197 			printf("Error: Target pixel's bpp is not 16bit.\n");
198 
199 			return -1;
200 		}
201 		cmap = malloc(sizeof(cmap) * 256);
202 
203 		/* Set color map */
204 		for (i = 0; i < 256; i++) {
205 			ushort colreg = ((cmap_base[0] << 8) & 0xf800) |
206 					((cmap_base[1] << 3) & 0x07e0) |
207 					((cmap_base[2] >> 3) & 0x001f) ;
208 			cmap_base += 4;
209 			cmap[i] = colreg;
210 		}
211 		/*
212 		 * only support convert 8bit bmap file to RGB565.
213 		 */
214 		if (get_unaligned_le32(&bmp->header.compression)) {
215 			decode_rle8_bitmap(src, dst, cmap, width, height,
216 					   bpp, 0, 0, flip);
217 		} else {
218 			stride = width * 2;
219 
220 			if (flip)
221 				dst += stride * (height - 1);
222 
223 			for (i = 0; i < height; ++i) {
224 				for (j = 0; j < width; j++) {
225 					*(uint16_t *)dst = cmap[*(src++)];
226 					dst += sizeof(uint16_t) / sizeof(*dst);
227 				}
228 				src += (padded_width - width);
229 				if (flip)
230 					dst -= stride * 2;
231 			}
232 		}
233 		free(cmap);
234 		break;
235 	case 16:
236 		if (get_unaligned_le32(&bmp->header.compression)) {
237 			printf("Error: Failed to decompression bmp file.\n");
238 
239 			return -1;
240 		}
241 		stride = ALIGN(width * bpp / 8, 4);
242 		if (flip)
243 			src += stride * (height - 1);
244 		for (i = 0; i < height; i++) {
245 			for (j = 0; j < width; j++) {
246 				ushort color = (src[1] << 8) | src[0];
247 
248 				color = (((color & 0x7c00) << 1) |
249 					((color & 0x03e0) << 1) |
250 					(color & 0x001f));
251 				*(uint16_t *)dst = color;
252 				src += 2;
253 				dst += 2;
254 			}
255 			src += (padded_width - width);
256 			if (flip)
257 				src -= stride * 2;
258 		}
259 		break;
260 	case 24:
261 		if (get_unaligned_le32(&bmp->header.compression)) {
262 			printf("Error: Failed to decompression bmp file.\n");
263 
264 			return -1;
265 		}
266 		stride = ALIGN(width * 3, 4);
267 		if (flip)
268 			src += stride * (height - 1);
269 
270 		for (i = 0; i < height; i++) {
271 			memcpy(dst, src, 3 * width);
272 			dst += stride;
273 			src += stride;
274 			if (flip)
275 				src -= stride * 2;
276 		}
277 		break;
278 	case 32:
279 		if (get_unaligned_le32(&bmp->header.compression)) {
280 			printf("Error: Failed to decompression bmp file.\n");
281 
282 			return -1;
283 		}
284 		stride = ALIGN(width * 4, 4);
285 		if (flip)
286 			src += stride * (height - 1);
287 
288 		for (i = 0; i < height; i++) {
289 			memcpy(dst, src, 4 * width);
290 			dst += stride;
291 			src += stride;
292 			if (flip)
293 				src -= stride * 2;
294 		}
295 		break;
296 	default:
297 		printf("Error: Can't decode this bmp file with bit=%d\n", bpp);
298 		return -1;
299 	}
300 
301 	return 0;
302 }
303