xref: /netbsd-src/sys/dev/splash/splash.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /* $NetBSD: splash.c,v 1.12 2012/06/02 14:24:00 martin 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.12 2012/06/02 14:24:00 martin 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
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
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
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 	/* XXX */
199 	if (flg & SPLASH_F_CENTER) {
200 		xoff = (si->si_width - width) / 2;
201 		yoff = (si->si_height - height) / 2;
202 	} else
203 		xoff = yoff = 0;
204 
205 	switch (si->si_depth) {
206 #if NSPLASH8 > 0
207 	case 8:
208 		splash_render8(si, data, xoff, yoff, width, height, flg);
209 		break;
210 #endif
211 #if NSPLASH16 > 0
212 	case 16:
213 		splash_render16(si, data, xoff, yoff, width, height, flg);
214 		break;
215 #endif
216 #if NSPLASH32 > 0
217 	case 32:
218 		splash_render32(si, data, xoff, yoff, width, height, flg);
219 		break;
220 #endif
221 	default:
222 		aprint_error("WARNING: Splash not supported at %dbpp\n",
223 		    si->si_depth);
224 		error = EINVAL;
225 	}
226 
227 	if (data)
228 		stbi_image_free(data);
229 
230 	return error;
231 }
232 
233 #if NSPLASH8 > 0
234 
235 static void
236 splash_render8(struct splash_info *si, const char *data, int xoff, int yoff,
237 	       int swidth, int sheight, int flg)
238 {
239 	const char *d;
240 	u_char *fb, *p;
241 	u_char pix[3];
242 	int x, y, i;
243 	int filled;
244 
245 	fb = si->si_bits;
246 
247 	if (flg & SPLASH_F_FILL)
248 		filled = 0;
249 	else
250 		filled = 1;
251 
252 	d = data;
253 	fb += xoff + yoff * si->si_stride;
254 
255 	for (y = 0; y < sheight; y++) {
256 		for (x = 0; x < swidth; x++) {
257 			pix[0] = *d++;
258 			pix[1] = *d++;
259 			pix[2] = *d++;
260 			if (filled == 0) {
261 				p = si->si_bits;
262 				i = 0;
263 				while (i < si->si_height*si->si_stride) {
264 					p[i] = SPLASH_INDEX(
265 					    pix[0], pix[1], pix[2]) +
266 					    SPLASH_CMAP_OFFSET;
267 					i++;
268 				}
269 				filled = 1;
270 			}
271 			fb[x] = SPLASH_INDEX(pix[0], pix[1], pix[2]) +
272 				    SPLASH_CMAP_OFFSET;
273 		}
274 		fb += si->si_stride;
275 	}
276 
277 	/* If we've just written to the shadow fb, copy it to the display */
278 	if (si->si_hwbits) {
279 		if (flg & SPLASH_F_FILL) {
280 			memcpy(si->si_hwbits, si->si_bits,
281 			    si->si_height*si->si_width);
282 		} else {
283 			u_char *rp, *hrp;
284 
285 			rp = si->si_bits + xoff + (yoff * si->si_width);
286 			hrp = si->si_hwbits + xoff + (yoff * si->si_width);
287 
288 			for (y = 0; y < sheight; y++) {
289 				memcpy(hrp, rp, swidth);
290 				rp += si->si_stride;
291 				hrp += si->si_stride;
292 			}
293 		}
294 	}
295 
296 	return;
297 }
298 #endif /* !NSPLASH8 > 0 */
299 
300 #if NSPLASH16 > 0
301 #define RGBTO16(b, o, x, c)					\
302 	do {							\
303 		uint16_t *_ptr = (uint16_t *)(&(b)[(o)]);	\
304 		*_ptr = (((c)[(x)*3+0] / 8) << 11) |		\
305 			(((c)[(x)*3+1] / 4) << 5) |		\
306 			(((c)[(x)*3+2] / 8) << 0);		\
307 	} while (0)
308 
309 static void
310 splash_render16(struct splash_info *si, const char *data, int xoff, int yoff,
311 		int swidth, int sheight, int flg)
312 {
313 	const char *d;
314 	u_char *fb, *p;
315 	u_char pix[3];
316 	int x, y, i;
317 	int filled;
318 
319 	fb = si->si_bits;
320 
321 	if (flg & SPLASH_F_FILL)
322 		filled = 0;
323 	else
324 		filled = 1;
325 
326 	d = data;
327 	fb += xoff * 2 + yoff * si->si_stride;
328 
329 	for (y = 0; y < sheight; y++) {
330 		for (x = 0; x < swidth; x++) {
331 			pix[0] = *d++;
332 			pix[1] = *d++;
333 			pix[2] = *d++;
334 			if (filled == 0) {
335 				p = si->si_bits;
336 				i = 0;
337 				while (i < si->si_height*si->si_stride) {
338 					RGBTO16(p, i, 0, pix);
339 					i += 2;
340 				}
341 				filled = 1;
342 			}
343 			RGBTO16(fb, x*2, 0, pix);
344 		}
345 		fb += si->si_stride;
346 	}
347 
348 	/* If we've just written to the shadow fb, copy it to the display */
349 	if (si->si_hwbits) {
350 		if (flg & SPLASH_F_FILL) {
351 			memcpy(si->si_hwbits, si->si_bits,
352 			    si->si_height*si->si_stride);
353 		} else {
354 			u_char *rp, *hrp;
355 
356 			rp = si->si_bits + (xoff * 2) + (yoff * si->si_stride);
357 			hrp = si->si_hwbits + (xoff * 2) +
358 			    (yoff * si->si_stride);
359 
360 			for (y = 0; y < sheight; y++) {
361 				memcpy(hrp, rp, swidth * 2);
362 				rp += si->si_stride;
363 				hrp += si->si_stride;
364 			}
365 		}
366 	}
367 
368 	return;
369 }
370 #undef RGBTO16
371 #endif /* !NSPLASH16 > 0 */
372 
373 #if NSPLASH32 > 0
374 static void
375 splash_render32(struct splash_info *si, const char *data, int xoff, int yoff,
376 		int swidth, int sheight, int flg)
377 {
378 	const char *d;
379 	u_char *fb, *p;
380 	u_char pix[3];
381 	int x, y, i;
382 	int filled;
383 
384 	fb = si->si_bits;
385 
386 	if (flg & SPLASH_F_FILL)
387 		filled = 0;
388 	else
389 		filled = 1;
390 
391 	d = data;
392 	fb += xoff * 4 + yoff * si->si_stride;
393 
394 	for (y = 0; y < sheight; y++) {
395 		for (x = 0; x < swidth; x++) {
396 			pix[0] = *d++;
397 			pix[1] = *d++;
398 			pix[2] = *d++;
399 			if (filled == 0) {
400 				p = si->si_bits;
401 				i = 0;
402 				while (i < si->si_height*si->si_stride) {
403 					p[i++] = pix[2];
404 					p[i++] = pix[1];
405 					p[i++] = pix[0];
406 					p[i++] = 0;
407 				}
408 				filled = 1;
409 			}
410 			fb[x*4+0] = pix[2];
411 			fb[x*4+1] = pix[1];
412 			fb[x*4+2] = pix[0];
413 			fb[x*4+3] = 0;
414 		}
415 		fb += si->si_stride;
416 	}
417 
418 	/* If we've just written to the shadow fb, copy it to the display */
419 	if (si->si_hwbits) {
420 		if (flg & SPLASH_F_FILL) {
421 			memcpy(si->si_hwbits, si->si_bits,
422 			    si->si_height*si->si_stride);
423 		} else {
424 			u_char *rp, *hrp;
425 
426 			rp = si->si_bits + (xoff * 4) + (yoff * si->si_stride);
427 			hrp = si->si_hwbits + (xoff * 4) +
428 			    (yoff * si->si_stride);
429 
430 			for (y = 0; y < sheight; y++) {
431 				memcpy(hrp, rp, swidth * 4);
432 				rp += si->si_stride;
433 				hrp += si->si_stride;
434 			}
435 		}
436 	}
437 
438 	return;
439 }
440 #endif /* !NSPLASH32 > 0 */
441 
442 #endif /* !SPLASHSCREEN */
443