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 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