Home | History | Annotate | Line # | Download | only in splash
splash.c revision 1.12
      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 (at) 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