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