source: mainline/kernel/genarch/src/fb/fb.c@ b888d5f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b888d5f was 98895c5c, checked in by Martin Decky <martin@…>, 17 years ago

simplify glyph mapping function
draw invalid glyphs with a distinctive color

  • Property mode set to 100644
File size: 12.0 KB
Line 
1/*
2 * Copyright (c) 2008 Martin Decky
3 * Copyright (c) 2006 Ondrej Palkovsky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - 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 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup genarch
31 * @{
32 */
33/** @file
34 */
35
36#include <genarch/fb/font-8x16.h>
37#include <genarch/fb/logo-196x66.h>
38#include <genarch/fb/visuals.h>
39#include <genarch/fb/fb.h>
40#include <console/chardev.h>
41#include <console/console.h>
42#include <sysinfo/sysinfo.h>
43#include <mm/slab.h>
44#include <align.h>
45#include <panic.h>
46#include <memstr.h>
47#include <config.h>
48#include <bitops.h>
49#include <print.h>
50#include <ddi/ddi.h>
51#include <arch/types.h>
52
53SPINLOCK_INITIALIZE(fb_lock);
54
55static uint8_t *fb_addr;
56static uint16_t *backbuf;
57static uint8_t *glyphs;
58static uint8_t *bgscan;
59
60static unsigned int xres;
61static unsigned int yres;
62
63static unsigned int ylogo;
64static unsigned int ytrim;
65static unsigned int rowtrim;
66
67static unsigned int scanline;
68static unsigned int glyphscanline;
69
70static unsigned int pixelbytes;
71static unsigned int glyphbytes;
72static unsigned int bgscanbytes;
73
74static unsigned int cols;
75static unsigned int rows;
76static unsigned int position = 0;
77
78#define BG_COLOR 0x000080
79#define FG_COLOR 0xffff00
80#define INV_COLOR 0xaaaaaa
81
82#define CURSOR 0x2588
83
84#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
85#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
86#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
87
88#define COL2X(col) ((col) * FONT_WIDTH)
89#define ROW2Y(row) ((row) * FONT_SCANLINES)
90
91#define X2COL(x) ((x) / FONT_WIDTH)
92#define Y2ROW(y) ((y) / FONT_SCANLINES)
93
94#define FB_POS(x, y) ((y) * scanline + (x) * pixelbytes)
95#define BB_POS(col, row) ((row) * cols + (col))
96#define GLYPH_POS(glyph, y) ((glyph) * glyphbytes + (y) * glyphscanline)
97
98
99static void (*rgb_conv)(void *, uint32_t);
100
101
102/** ARGB 8:8:8:8 conversion
103 *
104 */
105static void rgb_0888(void *dst, uint32_t rgb)
106{
107 *((uint32_t *) dst) = rgb & 0xffffff;
108}
109
110
111/** ABGR 8:8:8:8 conversion
112 *
113 */
114static void bgr_0888(void *dst, uint32_t rgb)
115{
116 *((uint32_t *) dst)
117 = (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | RED(rgb, 8);
118}
119
120
121/** RGB 8:8:8 conversion
122 *
123 */
124static void rgb_888(void *dst, uint32_t rgb)
125{
126 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
127 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
128 ((uint8_t *) dst)[2] = RED(rgb, 8);
129}
130
131
132/** BGR 8:8:8 conversion
133 *
134 */
135static void bgr_888(void *dst, uint32_t rgb)
136{
137 ((uint8_t *) dst)[0] = RED(rgb, 8);
138 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
139 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
140}
141
142
143/** RGB 5:5:5 conversion
144 *
145 */
146static void rgb_555(void *dst, uint32_t rgb)
147{
148 *((uint16_t *) dst)
149 = (RED(rgb, 5) << 10) | (GREEN(rgb, 5) << 5) | BLUE(rgb, 5);
150}
151
152
153/** RGB 5:6:5 conversion
154 *
155 */
156static void rgb_565(void *dst, uint32_t rgb)
157{
158 *((uint16_t *) dst)
159 = (RED(rgb, 5) << 11) | (GREEN(rgb, 6) << 5) | BLUE(rgb, 5);
160}
161
162
163/** RGB 3:2:3
164 *
165 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
166 * will most likely use a color palette. The color appearance
167 * will be pretty random and depend on the default installed
168 * palette. This could be fixed by supporting custom palette
169 * and setting it to simulate the 8-bit truecolor.
170 *
171 * Currently we set the palette on the ia32, amd64 and sparc64 port.
172 *
173 * Note that the byte is being inverted by this function. The reason is
174 * that we would like to use a color palette where the white color code
175 * is 0 and the black color code is 255, as some machines (Sun Blade 1500)
176 * use these codes for black and white and prevent to set codes
177 * 0 and 255 to other colors.
178 *
179 */
180static void rgb_323(void *dst, uint32_t rgb)
181{
182 *((uint8_t *) dst)
183 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
184}
185
186
187/** Hide logo and refresh screen
188 *
189 */
190static void logo_hide(bool silent)
191{
192 ylogo = 0;
193 ytrim = yres;
194 rowtrim = rows;
195 if (!silent)
196 fb_redraw();
197}
198
199
200/** Draw character at given position
201 *
202 */
203static void glyph_draw(uint16_t glyph, unsigned int col, unsigned int row, bool silent)
204{
205 unsigned int x = COL2X(col);
206 unsigned int y = ROW2Y(row);
207 unsigned int yd;
208
209 if (y >= ytrim)
210 logo_hide(silent);
211
212 backbuf[BB_POS(col, row)] = glyph;
213
214 if (!silent) {
215 for (yd = 0; yd < FONT_SCANLINES; yd++)
216 memcpy(&fb_addr[FB_POS(x, y + yd + ylogo)],
217 &glyphs[GLYPH_POS(glyph, yd)], glyphscanline);
218 }
219}
220
221
222/** Scroll screen down by one row
223 *
224 *
225 */
226static void screen_scroll(bool silent)
227{
228 if (ylogo > 0) {
229 logo_hide(silent);
230 return;
231 }
232
233 if (!silent) {
234 unsigned int row;
235
236 for (row = 0; row < rows; row++) {
237 unsigned int y = ROW2Y(row);
238 unsigned int yd;
239
240 for (yd = 0; yd < FONT_SCANLINES; yd++) {
241 unsigned int x;
242 unsigned int col;
243
244 for (col = 0, x = 0; col < cols; col++,
245 x += FONT_WIDTH) {
246 uint16_t glyph;
247
248 if (row < rows - 1) {
249 if (backbuf[BB_POS(col, row)] ==
250 backbuf[BB_POS(col, row + 1)])
251 continue;
252
253 glyph = backbuf[BB_POS(col, row + 1)];
254 } else
255 glyph = 0;
256
257 memcpy(&fb_addr[FB_POS(x, y + yd)],
258 &glyphs[GLYPH_POS(glyph, yd)],
259 glyphscanline);
260 }
261 }
262 }
263 }
264
265 memmove(backbuf, &backbuf[BB_POS(0, 1)], cols * (rows - 1) * sizeof(uint16_t));
266 memsetw(&backbuf[BB_POS(0, rows - 1)], cols, 0);
267}
268
269
270static void cursor_put(bool silent)
271{
272 glyph_draw(fb_font_glyph(CURSOR), position % cols, position / cols, silent);
273}
274
275
276static void cursor_remove(bool silent)
277{
278 glyph_draw(fb_font_glyph(0), position % cols, position / cols, silent);
279}
280
281
282/** Print character to screen
283 *
284 * Emulate basic terminal commands.
285 *
286 */
287static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent)
288{
289 spinlock_lock(&fb_lock);
290
291 switch (ch) {
292 case '\n':
293 cursor_remove(silent);
294 position += cols;
295 position -= position % cols;
296 break;
297 case '\r':
298 cursor_remove(silent);
299 position -= position % cols;
300 break;
301 case '\b':
302 cursor_remove(silent);
303 if (position % cols)
304 position--;
305 break;
306 case '\t':
307 cursor_remove(silent);
308 do {
309 glyph_draw(fb_font_glyph(' '), position % cols,
310 position / cols, silent);
311 position++;
312 } while ((position % 8) && (position < cols * rows));
313 break;
314 default:
315 glyph_draw(fb_font_glyph(ch), position % cols,
316 position / cols, silent);
317 position++;
318 }
319
320 if (position >= cols * rows) {
321 position -= cols;
322 screen_scroll(silent);
323 }
324
325 cursor_put(silent);
326
327 spinlock_unlock(&fb_lock);
328}
329
330static outdev_t fb_console;
331static outdev_operations_t fb_ops = {
332 .write = fb_putchar
333};
334
335
336/** Render glyphs
337 *
338 * Convert glyphs from device independent font
339 * description to current visual representation.
340 *
341 */
342static void glyphs_render(void)
343{
344 /* Prerender glyphs */
345 uint16_t glyph;
346
347 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
348 uint32_t fg_color;
349
350 if (glyph == FONT_GLYPHS - 1)
351 fg_color = INV_COLOR;
352 else
353 fg_color = FG_COLOR;
354
355 unsigned int y;
356
357 for (y = 0; y < FONT_SCANLINES; y++) {
358 unsigned int x;
359
360 for (x = 0; x < FONT_WIDTH; x++) {
361 void *dst = &glyphs[GLYPH_POS(glyph, y) +
362 x * pixelbytes];
363 uint32_t rgb = (fb_font[glyph][y] &
364 (1 << (7 - x))) ? fg_color : BG_COLOR;
365 rgb_conv(dst, rgb);
366 }
367 }
368 }
369
370 /* Prerender background scanline */
371 unsigned int x;
372
373 for (x = 0; x < xres; x++)
374 rgb_conv(&bgscan[x * pixelbytes], BG_COLOR);
375}
376
377
378/** Refresh the screen
379 *
380 */
381void fb_redraw(void)
382{
383 if (ylogo > 0) {
384 unsigned int y;
385
386 for (y = 0; y < LOGO_HEIGHT; y++) {
387 unsigned int x;
388
389 for (x = 0; x < xres; x++)
390 rgb_conv(&fb_addr[FB_POS(x, y)],
391 (x < LOGO_WIDTH) ?
392 fb_logo[y * LOGO_WIDTH + x] :
393 LOGO_COLOR);
394 }
395 }
396
397 unsigned int row;
398
399 for (row = 0; row < rowtrim; row++) {
400 unsigned int y = ylogo + ROW2Y(row);
401 unsigned int yd;
402
403 for (yd = 0; yd < FONT_SCANLINES; yd++) {
404 unsigned int x;
405 unsigned int col;
406
407 for (col = 0, x = 0; col < cols;
408 col++, x += FONT_WIDTH) {
409 uint16_t glyph = backbuf[BB_POS(col, row)];
410 void *dst = &fb_addr[FB_POS(x, y + yd)];
411 void *src = &glyphs[GLYPH_POS(glyph, yd)];
412 memcpy(dst, src, glyphscanline);
413 }
414 }
415 }
416
417 if (COL2X(cols) < xres) {
418 unsigned int y;
419 unsigned int size = (xres - COL2X(cols)) * pixelbytes;
420
421 for (y = ylogo; y < yres; y++)
422 memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size);
423 }
424
425 if (ROW2Y(rowtrim) + ylogo < yres) {
426 unsigned int y;
427
428 for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++)
429 memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes);
430 }
431}
432
433
434/** Initialize framebuffer as a output character device
435 *
436 * @param addr Physical address of the framebuffer
437 * @param x Screen width in pixels
438 * @param y Screen height in pixels
439 * @param scan Bytes per one scanline
440 * @param visual Color model
441 *
442 */
443void fb_init(fb_properties_t *props)
444{
445 switch (props->visual) {
446 case VISUAL_INDIRECT_8:
447 rgb_conv = rgb_323;
448 pixelbytes = 1;
449 break;
450 case VISUAL_RGB_5_5_5:
451 rgb_conv = rgb_555;
452 pixelbytes = 2;
453 break;
454 case VISUAL_RGB_5_6_5:
455 rgb_conv = rgb_565;
456 pixelbytes = 2;
457 break;
458 case VISUAL_RGB_8_8_8:
459 rgb_conv = rgb_888;
460 pixelbytes = 3;
461 break;
462 case VISUAL_BGR_8_8_8:
463 rgb_conv = bgr_888;
464 pixelbytes = 3;
465 break;
466 case VISUAL_RGB_8_8_8_0:
467 rgb_conv = rgb_888;
468 pixelbytes = 4;
469 break;
470 case VISUAL_RGB_0_8_8_8:
471 rgb_conv = rgb_0888;
472 pixelbytes = 4;
473 break;
474 case VISUAL_BGR_0_8_8_8:
475 rgb_conv = bgr_0888;
476 pixelbytes = 4;
477 break;
478 default:
479 panic("Unsupported visual.");
480 }
481
482 xres = props->x;
483 yres = props->y;
484 scanline = props->scan;
485
486 cols = X2COL(xres);
487 rows = Y2ROW(yres);
488
489 if (yres > ylogo) {
490 ylogo = LOGO_HEIGHT;
491 rowtrim = rows - Y2ROW(ylogo);
492 if (ylogo % FONT_SCANLINES > 0)
493 rowtrim--;
494 ytrim = ROW2Y(rowtrim);
495 } else {
496 ylogo = 0;
497 ytrim = yres;
498 rowtrim = rows;
499 }
500
501 glyphscanline = FONT_WIDTH * pixelbytes;
502 glyphbytes = ROW2Y(glyphscanline);
503 bgscanbytes = xres * pixelbytes;
504
505 size_t fbsize = scanline * yres;
506 size_t bbsize = cols * rows * sizeof(uint16_t);
507 size_t glyphsize = FONT_GLYPHS * glyphbytes;
508
509 backbuf = (uint16_t *) malloc(bbsize, 0);
510 if (!backbuf)
511 panic("Unable to allocate backbuffer.");
512
513 glyphs = (uint8_t *) malloc(glyphsize, 0);
514 if (!glyphs)
515 panic("Unable to allocate glyphs.");
516
517 bgscan = malloc(bgscanbytes, 0);
518 if (!bgscan)
519 panic("Unable to allocate background pixel.");
520
521 memsetw(backbuf, cols * rows, 0);
522
523 glyphs_render();
524
525 fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
526
527 sysinfo_set_item_val("fb", NULL, true);
528 sysinfo_set_item_val("fb.kind", NULL, 1);
529 sysinfo_set_item_val("fb.width", NULL, xres);
530 sysinfo_set_item_val("fb.height", NULL, yres);
531 sysinfo_set_item_val("fb.scanline", NULL, scanline);
532 sysinfo_set_item_val("fb.visual", NULL, props->visual);
533 sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
534
535 fb_redraw();
536
537 outdev_initialize("fb", &fb_console, &fb_ops);
538 stdout = &fb_console;
539}
540
541/** @}
542 */
Note: See TracBrowser for help on using the repository browser.