xref: /netbsd-src/sys/dev/splash/splash.c (revision 30e30cd09c64d9529b40a613be18783a2c7a1074)
1 /* $NetBSD: splash.c,v 1.13 2016/04/25 22:26:50 khorben Exp $ */
2 
3 /*-
4  * Copyright (c) 2006 Jared D. McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by the NetBSD
18  *        Foundation, Inc. and its contributors.
19  * 4. Neither the name of The NetBSD Foundation nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: splash.c,v 1.13 2016/04/25 22:26:50 khorben Exp $");
38 
39 #include "opt_splash.h"
40 
41 /* XXX */
42 #define NSPLASH8  1
43 #define	NSPLASH16 1
44 #define	NSPLASH32 1
45 
46 #include <sys/param.h>
47 #include <sys/device.h>
48 #include <sys/systm.h>
49 #include <sys/types.h>
50 #include <sys/kernel.h>
51 #include <sys/kthread.h>
52 
53 #include <dev/splash/splash.h>
54 #include <dev/stbi/stbi.h>
55 
56 #ifdef SPLASHSCREEN
57 
58 static struct {
59 	const u_char	*data;
60 	size_t		datalen;
61 } splash_image = { NULL, 0 };
62 
63 #define SPLASH_INDEX(r, g, b)						\
64 	((((r) >> 6) << 4) | (((g) >> 6) << 2) | (((b) >> 6) << 0))
65 
66 static uint8_t splash_palette[SPLASH_CMAP_SIZE][3] = {
67 	{ 0x00, 0x00, 0x00 },
68 	{ 0x00, 0x00, 0x55 },
69 	{ 0x00, 0x00, 0xaa },
70 	{ 0x00, 0x00, 0xff },
71 	{ 0x00, 0x55, 0x00 },
72 	{ 0x00, 0x55, 0x55 },
73 	{ 0x00, 0x55, 0xaa },
74 	{ 0x00, 0x55, 0xff },
75 	{ 0x00, 0xaa, 0x00 },
76 	{ 0x00, 0xaa, 0x55 },
77 	{ 0x00, 0xaa, 0xaa },
78 	{ 0x00, 0xaa, 0xff },
79 	{ 0x00, 0xff, 0x00 },
80 	{ 0x00, 0xff, 0x55 },
81 	{ 0x00, 0xff, 0xaa },
82 	{ 0x00, 0xff, 0xff },
83 	{ 0x55, 0x00, 0x00 },
84 	{ 0x55, 0x00, 0x55 },
85 	{ 0x55, 0x00, 0xaa },
86 	{ 0x55, 0x00, 0xff },
87 	{ 0x55, 0x55, 0x00 },
88 	{ 0x55, 0x55, 0x55 },
89 	{ 0x55, 0x55, 0xaa },
90 	{ 0x55, 0x55, 0xff },
91 	{ 0x55, 0xaa, 0x00 },
92 	{ 0x55, 0xaa, 0x55 },
93 	{ 0x55, 0xaa, 0xaa },
94 	{ 0x55, 0xaa, 0xff },
95 	{ 0x55, 0xff, 0x00 },
96 	{ 0x55, 0xff, 0x55 },
97 	{ 0x55, 0xff, 0xaa },
98 	{ 0x55, 0xff, 0xff },
99 	{ 0xaa, 0x00, 0x00 },
100 	{ 0xaa, 0x00, 0x55 },
101 	{ 0xaa, 0x00, 0xaa },
102 	{ 0xaa, 0x00, 0xff },
103 	{ 0xaa, 0x55, 0x00 },
104 	{ 0xaa, 0x55, 0x55 },
105 	{ 0xaa, 0x55, 0xaa },
106 	{ 0xaa, 0x55, 0xff },
107 	{ 0xaa, 0xaa, 0x00 },
108 	{ 0xaa, 0xaa, 0x55 },
109 	{ 0xaa, 0xaa, 0xaa },
110 	{ 0xaa, 0xaa, 0xff },
111 	{ 0xaa, 0xff, 0x00 },
112 	{ 0xaa, 0xff, 0x55 },
113 	{ 0xaa, 0xff, 0xaa },
114 	{ 0xaa, 0xff, 0xff },
115 	{ 0xff, 0x00, 0x00 },
116 	{ 0xff, 0x00, 0x55 },
117 	{ 0xff, 0x00, 0xaa },
118 	{ 0xff, 0x00, 0xff },
119 	{ 0xff, 0x55, 0x00 },
120 	{ 0xff, 0x55, 0x55 },
121 	{ 0xff, 0x55, 0xaa },
122 	{ 0xff, 0x55, 0xff },
123 	{ 0xff, 0xaa, 0x00 },
124 	{ 0xff, 0xaa, 0x55 },
125 	{ 0xff, 0xaa, 0xaa },
126 	{ 0xff, 0xaa, 0xff },
127 	{ 0xff, 0xff, 0x00 },
128 	{ 0xff, 0xff, 0x55 },
129 	{ 0xff, 0xff, 0xaa },
130 	{ 0xff, 0xff, 0xff },
131 };
132 
133 #if NSPLASH8 > 0
134 static void	splash_render8(struct splash_info *, const char *, int,
135 			       int, int, int, int);
136 #endif
137 #if NSPLASH16 > 0
138 static void	splash_render16(struct splash_info *, const char *, int,
139 				int, int, int, int);
140 #endif
141 #if NSPLASH32 > 0
142 static void	splash_render32(struct splash_info *, const char *, int,
143 				int, int, int, int);
144 #endif
145 
146 int
splash_setimage(const void * imgdata,size_t imgdatalen)147 splash_setimage(const void *imgdata, size_t imgdatalen)
148 {
149 	if (splash_image.data != NULL) {
150 		aprint_debug("WARNING: %s: already initialized\n", __func__);
151 		return EBUSY;
152 	}
153 
154 	aprint_verbose("%s: splash image @ %p, %zu bytes\n",
155 	    __func__, imgdata, imgdatalen);
156 	splash_image.data = imgdata;
157 	splash_image.datalen = imgdatalen;
158 
159 	return 0;
160 }
161 
162 int
splash_get_cmap(int index,uint8_t * r,uint8_t * g,uint8_t * b)163 splash_get_cmap(int index, uint8_t *r, uint8_t *g, uint8_t *b)
164 {
165 	if (index < SPLASH_CMAP_OFFSET ||
166 	    index >= SPLASH_CMAP_OFFSET + SPLASH_CMAP_SIZE)
167 		return ERANGE;
168 
169 	*r = splash_palette[index - SPLASH_CMAP_OFFSET][0];
170 	*g = splash_palette[index - SPLASH_CMAP_OFFSET][1];
171 	*b = splash_palette[index - SPLASH_CMAP_OFFSET][2];
172 
173 	return 0;
174 }
175 
176 int
splash_render(struct splash_info * si,int flg)177 splash_render(struct splash_info *si, int flg)
178 {
179 	char *data = NULL;
180 	int xoff, yoff, width, height, comp;
181 	int error = 0;
182 
183 	if (splash_image.data == NULL) {
184 		aprint_error("WARNING: %s: not initialized\n", __func__);
185 		return ENXIO;
186 	}
187 
188 	data = stbi_load_from_memory(splash_image.data,
189 	    splash_image.datalen, &width, &height, &comp, STBI_rgb);
190 	if (data == NULL) {
191 		aprint_error("WARNING: couldn't load splash image: %s\n",
192 		    stbi_failure_reason());
193 		return EINVAL;
194 	}
195 	aprint_debug("%s: splash loaded, width %d height %d comp %d\n",
196 	    __func__, width, height, comp);
197 
198 	if ((width > si->si_width) || (height > si->si_height)) {
199 		aprint_error(
200 			"WARNING: splash size (%dx%d) too big for framebuffer (%dx%d)\n",
201 			width, height, si->si_width, si->si_height);
202 		stbi_image_free(data);
203 		return EINVAL;
204 	}
205 
206 	/* XXX */
207 	if (flg & SPLASH_F_CENTER) {
208 		xoff = (si->si_width - width) / 2;
209 		yoff = (si->si_height - height) / 2;
210 	} else
211 		xoff = yoff = 0;
212 
213 	switch (si->si_depth) {
214 #if NSPLASH8 > 0
215 	case 8:
216 		splash_render8(si, data, xoff, yoff, width, height, flg);
217 		break;
218 #endif
219 #if NSPLASH16 > 0
220 	case 16:
221 		splash_render16(si, data, xoff, yoff, width, height, flg);
222 		break;
223 #endif
224 #if NSPLASH32 > 0
225 	case 32:
226 		splash_render32(si, data, xoff, yoff, width, height, flg);
227 		break;
228 #endif
229 	default:
230 		aprint_error("WARNING: Splash not supported at %dbpp\n",
231 		    si->si_depth);
232 		error = EINVAL;
233 	}
234 
235 	if (data)
236 		stbi_image_free(data);
237 
238 	return error;
239 }
240 
241 #if NSPLASH8 > 0
242 
243 static void
splash_render8(struct splash_info * si,const char * data,int xoff,int yoff,int swidth,int sheight,int flg)244 splash_render8(struct splash_info *si, const char *data, int xoff, int yoff,
245 	       int swidth, int sheight, int flg)
246 {
247 	const char *d;
248 	u_char *fb, *p;
249 	u_char pix[3];
250 	int x, y, i;
251 	int filled;
252 
253 	fb = si->si_bits;
254 
255 	if (flg & SPLASH_F_FILL)
256 		filled = 0;
257 	else
258 		filled = 1;
259 
260 	d = data;
261 	fb += xoff + yoff * si->si_stride;
262 
263 	for (y = 0; y < sheight; y++) {
264 		for (x = 0; x < swidth; x++) {
265 			pix[0] = *d++;
266 			pix[1] = *d++;
267 			pix[2] = *d++;
268 			if (filled == 0) {
269 				p = si->si_bits;
270 				i = 0;
271 				while (i < si->si_height*si->si_stride) {
272 					p[i] = SPLASH_INDEX(
273 					    pix[0], pix[1], pix[2]) +
274 					    SPLASH_CMAP_OFFSET;
275 					i++;
276 				}
277 				filled = 1;
278 			}
279 			fb[x] = SPLASH_INDEX(pix[0], pix[1], pix[2]) +
280 				    SPLASH_CMAP_OFFSET;
281 		}
282 		fb += si->si_stride;
283 	}
284 
285 	/* If we've just written to the shadow fb, copy it to the display */
286 	if (si->si_hwbits) {
287 		if (flg & SPLASH_F_FILL) {
288 			memcpy(si->si_hwbits, si->si_bits,
289 			    si->si_height*si->si_width);
290 		} else {
291 			u_char *rp, *hrp;
292 
293 			rp = si->si_bits + xoff + (yoff * si->si_width);
294 			hrp = si->si_hwbits + xoff + (yoff * si->si_width);
295 
296 			for (y = 0; y < sheight; y++) {
297 				memcpy(hrp, rp, swidth);
298 				rp += si->si_stride;
299 				hrp += si->si_stride;
300 			}
301 		}
302 	}
303 
304 	return;
305 }
306 #endif /* !NSPLASH8 > 0 */
307 
308 #if NSPLASH16 > 0
309 #define RGBTO16(b, o, x, c)					\
310 	do {							\
311 		uint16_t *_ptr = (uint16_t *)(&(b)[(o)]);	\
312 		*_ptr = (((c)[(x)*3+0] / 8) << 11) |		\
313 			(((c)[(x)*3+1] / 4) << 5) |		\
314 			(((c)[(x)*3+2] / 8) << 0);		\
315 	} while (0)
316 
317 static void
splash_render16(struct splash_info * si,const char * data,int xoff,int yoff,int swidth,int sheight,int flg)318 splash_render16(struct splash_info *si, const char *data, int xoff, int yoff,
319 		int swidth, int sheight, int flg)
320 {
321 	const char *d;
322 	u_char *fb, *p;
323 	u_char pix[3];
324 	int x, y, i;
325 	int filled;
326 
327 	fb = si->si_bits;
328 
329 	if (flg & SPLASH_F_FILL)
330 		filled = 0;
331 	else
332 		filled = 1;
333 
334 	d = data;
335 	fb += xoff * 2 + yoff * si->si_stride;
336 
337 	for (y = 0; y < sheight; y++) {
338 		for (x = 0; x < swidth; x++) {
339 			pix[0] = *d++;
340 			pix[1] = *d++;
341 			pix[2] = *d++;
342 			if (filled == 0) {
343 				p = si->si_bits;
344 				i = 0;
345 				while (i < si->si_height*si->si_stride) {
346 					RGBTO16(p, i, 0, pix);
347 					i += 2;
348 				}
349 				filled = 1;
350 			}
351 			RGBTO16(fb, x*2, 0, pix);
352 		}
353 		fb += si->si_stride;
354 	}
355 
356 	/* If we've just written to the shadow fb, copy it to the display */
357 	if (si->si_hwbits) {
358 		if (flg & SPLASH_F_FILL) {
359 			memcpy(si->si_hwbits, si->si_bits,
360 			    si->si_height*si->si_stride);
361 		} else {
362 			u_char *rp, *hrp;
363 
364 			rp = si->si_bits + (xoff * 2) + (yoff * si->si_stride);
365 			hrp = si->si_hwbits + (xoff * 2) +
366 			    (yoff * si->si_stride);
367 
368 			for (y = 0; y < sheight; y++) {
369 				memcpy(hrp, rp, swidth * 2);
370 				rp += si->si_stride;
371 				hrp += si->si_stride;
372 			}
373 		}
374 	}
375 
376 	return;
377 }
378 #undef RGBTO16
379 #endif /* !NSPLASH16 > 0 */
380 
381 #if NSPLASH32 > 0
382 static void
splash_render32(struct splash_info * si,const char * data,int xoff,int yoff,int swidth,int sheight,int flg)383 splash_render32(struct splash_info *si, const char *data, int xoff, int yoff,
384 		int swidth, int sheight, int flg)
385 {
386 	const char *d;
387 	u_char *fb, *p;
388 	u_char pix[3];
389 	int x, y, i;
390 	int filled;
391 
392 	fb = si->si_bits;
393 
394 	if (flg & SPLASH_F_FILL)
395 		filled = 0;
396 	else
397 		filled = 1;
398 
399 	d = data;
400 	fb += xoff * 4 + yoff * si->si_stride;
401 
402 	for (y = 0; y < sheight; y++) {
403 		for (x = 0; x < swidth; x++) {
404 			pix[0] = *d++;
405 			pix[1] = *d++;
406 			pix[2] = *d++;
407 			if (filled == 0) {
408 				p = si->si_bits;
409 				i = 0;
410 				while (i < si->si_height*si->si_stride) {
411 					p[i++] = pix[2];
412 					p[i++] = pix[1];
413 					p[i++] = pix[0];
414 					p[i++] = 0;
415 				}
416 				filled = 1;
417 			}
418 			fb[x*4+0] = pix[2];
419 			fb[x*4+1] = pix[1];
420 			fb[x*4+2] = pix[0];
421 			fb[x*4+3] = 0;
422 		}
423 		fb += si->si_stride;
424 	}
425 
426 	/* If we've just written to the shadow fb, copy it to the display */
427 	if (si->si_hwbits) {
428 		if (flg & SPLASH_F_FILL) {
429 			memcpy(si->si_hwbits, si->si_bits,
430 			    si->si_height*si->si_stride);
431 		} else {
432 			u_char *rp, *hrp;
433 
434 			rp = si->si_bits + (xoff * 4) + (yoff * si->si_stride);
435 			hrp = si->si_hwbits + (xoff * 4) +
436 			    (yoff * si->si_stride);
437 
438 			for (y = 0; y < sheight; y++) {
439 				memcpy(hrp, rp, swidth * 4);
440 				rp += si->si_stride;
441 				hrp += si->si_stride;
442 			}
443 		}
444 	}
445 
446 	return;
447 }
448 #endif /* !NSPLASH32 > 0 */
449 
450 #endif /* !SPLASHSCREEN */
451