Home | History | Annotate | Line # | Download | only in splash
      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 (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.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
    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 	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
    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
    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
    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