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