source: mainline/uspace/srv/fb/fb.c@ bda24ee7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bda24ee7 was 42ec919, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Viewport invalidation. Makes delta-redraw optimization work when returning from kcon.

  • Property mode set to 100644
File size: 39.2 KB
Line 
1/*
2 * Copyright (c) 2008 Martin Decky
3 * Copyright (c) 2006 Jakub Vana
4 * Copyright (c) 2006 Ondrej Palkovsky
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 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @defgroup fb Graphical framebuffer
33 * @brief HelenOS graphical framebuffer.
34 * @ingroup fbs
35 * @{
36 */
37
38/** @file
39 */
40
41#include <stdlib.h>
42#include <unistd.h>
43#include <string.h>
44#include <ddi.h>
45#include <sysinfo.h>
46#include <align.h>
47#include <as.h>
48#include <ipc/fb.h>
49#include <ipc/ipc.h>
50#include <ipc/ns.h>
51#include <ipc/services.h>
52#include <kernel/errno.h>
53#include <kernel/genarch/fb/visuals.h>
54#include <console/color.h>
55#include <console/style.h>
56#include <async.h>
57#include <bool.h>
58
59#include "font-8x16.h"
60#include "fb.h"
61#include "main.h"
62#include "../console/screenbuffer.h"
63#include "ppm.h"
64
65#include "pointer.xbm"
66#include "pointer_mask.xbm"
67
68#define DEFAULT_BGCOLOR 0xf0f0f0
69#define DEFAULT_FGCOLOR 0x000000
70
71#define MAX_ANIM_LEN 8
72#define MAX_ANIMATIONS 4
73#define MAX_PIXMAPS 256 /**< Maximum number of saved pixmaps */
74#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
75
76/** Function to render a pixel from a RGB value. */
77typedef void (*rgb_conv_t)(void *, uint32_t);
78
79/** Function to draw a glyph. */
80typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
81 uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
82
83struct {
84 uint8_t *fb_addr;
85
86 unsigned int xres;
87 unsigned int yres;
88
89 unsigned int scanline;
90 unsigned int glyphscanline;
91
92 unsigned int pixelbytes;
93 unsigned int glyphbytes;
94
95 rgb_conv_t rgb_conv;
96} screen;
97
98/** Backbuffer character cell. */
99typedef struct {
100 uint8_t glyph;
101 uint32_t fg_color;
102 uint32_t bg_color;
103} bb_cell_t;
104
105typedef struct {
106 bool initialized;
107 unsigned int x;
108 unsigned int y;
109 unsigned int width;
110 unsigned int height;
111
112 /* Text support in window */
113 unsigned int cols;
114 unsigned int rows;
115
116 /*
117 * Style and glyphs for text printing
118 */
119
120 /** Current attributes. */
121 attr_rgb_t attr;
122
123 /** Pre-rendered mask for rendering glyphs. Different viewports
124 * might use different drawing functions depending on whether their
125 * scanlines are aligned on a word boundary.*/
126 uint8_t *glyphs;
127
128 uint8_t *bgpixel;
129
130 /** Glyph drawing function for this viewport. */
131 dg_t dglyph;
132
133 /* Auto-cursor position */
134 bool cursor_active;
135 unsigned int cur_col;
136 unsigned int cur_row;
137 bool cursor_shown;
138
139 /* Back buffer */
140 bb_cell_t *backbuf;
141 unsigned int bbsize;
142 bool bb_invalid;
143} viewport_t;
144
145typedef struct {
146 bool initialized;
147 bool enabled;
148 unsigned int vp;
149
150 unsigned int pos;
151 unsigned int animlen;
152 unsigned int pixmaps[MAX_ANIM_LEN];
153} animation_t;
154
155static animation_t animations[MAX_ANIMATIONS];
156static bool anims_enabled;
157
158typedef struct {
159 unsigned int width;
160 unsigned int height;
161 uint8_t *data;
162} pixmap_t;
163
164static pixmap_t pixmaps[MAX_PIXMAPS];
165static viewport_t viewports[128];
166
167static bool client_connected = false; /**< Allow only 1 connection */
168
169static uint32_t color_table[16] = {
170 [COLOR_BLACK] = 0x000000,
171 [COLOR_BLUE] = 0x0000f0,
172 [COLOR_GREEN] = 0x00f000,
173 [COLOR_CYAN] = 0x00f0f0,
174 [COLOR_RED] = 0xf00000,
175 [COLOR_MAGENTA] = 0xf000f0,
176 [COLOR_YELLOW] = 0xf0f000,
177 [COLOR_WHITE] = 0xf0f0f0,
178
179 [8 + COLOR_BLACK] = 0x000000,
180 [8 + COLOR_BLUE] = 0x0000ff,
181 [8 + COLOR_GREEN] = 0x00ff00,
182 [8 + COLOR_CYAN] = 0x00ffff,
183 [8 + COLOR_RED] = 0xff0000,
184 [8 + COLOR_MAGENTA] = 0xff00ff,
185 [8 + COLOR_YELLOW] = 0xffff00,
186 [8 + COLOR_WHITE] = 0xffffff,
187};
188
189static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
190static int rgb_from_style(attr_rgb_t *rgb, int style);
191static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
192 ipcarg_t bg_color, ipcarg_t flags);
193
194static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
195 ipcarg_t bg_color, ipcarg_t attr);
196
197static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
198 uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
199static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
200 uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
201
202static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
203 unsigned int row);
204
205
206#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
207#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
208#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
209
210#define COL2X(col) ((col) * FONT_WIDTH)
211#define ROW2Y(row) ((row) * FONT_SCANLINES)
212
213#define X2COL(x) ((x) / FONT_WIDTH)
214#define Y2ROW(y) ((y) / FONT_SCANLINES)
215
216#define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
217#define BB_POS(vport, col, row) ((row) * vport->cols + (col))
218#define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
219
220
221/** ARGB 8:8:8:8 conversion
222 *
223 */
224static void rgb_0888(void *dst, uint32_t rgb)
225{
226 *((uint32_t *) dst) = rgb & 0xffffff;
227}
228
229
230/** ABGR 8:8:8:8 conversion
231 *
232 */
233static void bgr_0888(void *dst, uint32_t rgb)
234{
235 *((uint32_t *) dst)
236 = (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | RED(rgb, 8);
237}
238
239
240/** BGR 8:8:8 conversion
241 *
242 */
243static void rgb_888(void *dst, uint32_t rgb)
244{
245#if defined(FB_INVERT_ENDIAN)
246 ((uint8_t *) dst)[0] = RED(rgb, 8);
247 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
248 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
249#else
250 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
251 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
252 ((uint8_t *) dst)[2] = RED(rgb, 8);
253#endif
254}
255
256
257/** RGB 5:5:5 conversion
258 *
259 */
260static void rgb_555(void *dst, uint32_t rgb)
261{
262 *((uint16_t *) dst)
263 = (RED(rgb, 5) << 10) | (GREEN(rgb, 5) << 5) | BLUE(rgb, 5);
264}
265
266
267/** RGB 5:6:5 conversion
268 *
269 */
270static void rgb_565(void *dst, uint32_t rgb)
271{
272 *((uint16_t *) dst)
273 = (RED(rgb, 5) << 11) | (GREEN(rgb, 6) << 5) | BLUE(rgb, 5);
274}
275
276
277/** RGB 3:2:3
278 *
279 */
280static void rgb_323(void *dst, uint32_t rgb)
281{
282 *((uint8_t *) dst)
283 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
284}
285
286/** Draw a filled rectangle.
287 *
288 * @note Need real implementation that does not access VRAM twice.
289 */
290static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
291 unsigned int y1, uint32_t color)
292{
293 unsigned int x, y;
294 unsigned int copy_bytes;
295
296 uint8_t *sp, *dp;
297 uint8_t cbuf[4];
298
299 if (y0 >= y1 || x0 >= x1) return;
300 screen.rgb_conv(cbuf, color);
301
302 sp = &screen.fb_addr[FB_POS(x0, y0)];
303 dp = sp;
304
305 /* Draw the first line. */
306 for (x = x0; x < x1; x++) {
307 memcpy(dp, cbuf, screen.pixelbytes);
308 dp += screen.pixelbytes;
309 }
310
311 dp = sp + screen.scanline;
312 copy_bytes = (x1 - x0) * screen.pixelbytes;
313
314 /* Draw the remaining lines by copying. */
315 for (y = y0 + 1; y < y1; y++) {
316 memcpy(dp, sp, copy_bytes);
317 dp += screen.scanline;
318 }
319}
320
321/** Redraw viewport.
322 *
323 * @param vport Viewport to redraw
324 *
325 */
326static void vport_redraw(viewport_t *vport)
327{
328 unsigned int row, col;
329
330 for (row = 0; row < vport->rows; row++) {
331 for (col = 0; col < vport->cols; col++) {
332 draw_vp_glyph(vport, false, col, row);
333 }
334 }
335
336 if (COL2X(vport->cols) < vport->width) {
337 draw_filled_rect(
338 vport->x + COL2X(vport->cols), vport->y,
339 vport->x + vport->width, vport->y + vport->height,
340 vport->attr.bg_color);
341 }
342
343 if (ROW2Y(vport->rows) < vport->height) {
344 draw_filled_rect(
345 vport->x, vport->y + ROW2Y(vport->rows),
346 vport->x + vport->width, vport->y + vport->height,
347 vport->attr.bg_color);
348 }
349}
350
351static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
352 uint32_t bg_color)
353{
354 unsigned i;
355
356 for (i = 0; i < len; i++) {
357 backbuf[i].glyph = 0;
358 backbuf[i].fg_color = fg_color;
359 backbuf[i].bg_color = bg_color;
360 }
361}
362
363/** Clear viewport.
364 *
365 * @param vport Viewport to clear
366 *
367 */
368static void vport_clear(viewport_t *vport)
369{
370 backbuf_clear(vport->backbuf, vport->cols * vport->rows,
371 vport->attr.fg_color, vport->attr.bg_color);
372 vport_redraw(vport);
373}
374
375/** Scroll viewport by the specified number of lines.
376 *
377 * @param vport Viewport to scroll
378 * @param lines Number of lines to scroll
379 *
380 */
381static void vport_scroll(viewport_t *vport, int lines)
382{
383 unsigned int row, col;
384 unsigned int x, y;
385 uint8_t glyph;
386 uint32_t fg_color;
387 uint32_t bg_color;
388 bb_cell_t *bbp, *xbp;
389
390 /*
391 * Redraw.
392 */
393
394 y = vport->y;
395 for (row = 0; row < vport->rows; row++) {
396 x = vport->x;
397 for (col = 0; col < vport->cols; col++) {
398 if ((row + lines >= 0) && (row + lines < vport->rows)) {
399 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
400 bbp = &vport->backbuf[BB_POS(vport, col, row)];
401
402 glyph = xbp->glyph;
403 fg_color = xbp->fg_color;
404 bg_color = xbp->bg_color;
405
406 if (bbp->glyph == glyph &&
407 bbp->fg_color == xbp->fg_color &&
408 bbp->bg_color == xbp->bg_color) {
409 x += FONT_WIDTH;
410 continue;
411 }
412 } else {
413 glyph = 0;
414 fg_color = vport->attr.fg_color;
415 bg_color = vport->attr.bg_color;
416 }
417
418 (*vport->dglyph)(x, y, false, vport->glyphs, glyph,
419 fg_color, bg_color);
420 x += FONT_WIDTH;
421 }
422 y += FONT_SCANLINES;
423 }
424
425 /*
426 * Scroll backbuffer.
427 */
428
429 if (lines > 0) {
430 memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
431 vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
432 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
433 vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
434 } else {
435 memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
436 vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
437 backbuf_clear(vport->backbuf, - vport->cols * lines,
438 vport->attr.fg_color, vport->attr.bg_color);
439 }
440}
441
442/** Render glyphs
443 *
444 * Convert glyphs from device independent font
445 * description to current visual representation.
446 *
447 * @param vport Viewport
448 *
449 */
450static void render_glyphs(viewport_t* vport)
451{
452 unsigned int glyph;
453
454 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
455 unsigned int y;
456
457 for (y = 0; y < FONT_SCANLINES; y++) {
458 unsigned int x;
459
460 for (x = 0; x < FONT_WIDTH; x++) {
461 screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
462 (fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
463 ? 0xffffff : 0x000000);
464
465 screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
466 (fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
467 ? 0x000000 : 0xffffff);
468 }
469 }
470 }
471
472 screen.rgb_conv(vport->bgpixel, vport->attr.bg_color);
473}
474
475
476/** Create new viewport
477 *
478 * @param x Origin of the viewport (x).
479 * @param y Origin of the viewport (y).
480 * @param width Width of the viewport.
481 * @param height Height of the viewport.
482 *
483 * @return New viewport number.
484 *
485 */
486static int vport_create(unsigned int x, unsigned int y,
487 unsigned int width, unsigned int height)
488{
489 unsigned int i;
490
491 for (i = 0; i < MAX_VIEWPORTS; i++) {
492 if (!viewports[i].initialized)
493 break;
494 }
495 if (i == MAX_VIEWPORTS)
496 return ELIMIT;
497
498 unsigned int cols = width / FONT_WIDTH;
499 unsigned int rows = height / FONT_SCANLINES;
500 unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
501 unsigned int glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
502 unsigned int word_size = sizeof(unsigned long);
503
504 bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
505 if (!backbuf)
506 return ENOMEM;
507
508 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
509 if (!glyphs) {
510 free(backbuf);
511 return ENOMEM;
512 }
513
514 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
515 if (!bgpixel) {
516 free(glyphs);
517 free(backbuf);
518 return ENOMEM;
519 }
520
521 backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
522 memset(glyphs, 0, glyphsize);
523 memset(bgpixel, 0, screen.pixelbytes);
524
525 viewports[i].x = x;
526 viewports[i].y = y;
527 viewports[i].width = width;
528 viewports[i].height = height;
529
530 viewports[i].cols = cols;
531 viewports[i].rows = rows;
532
533 viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
534 viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
535
536 viewports[i].glyphs = glyphs;
537 viewports[i].bgpixel = bgpixel;
538
539 /*
540 * Conditions necessary to select aligned version:
541 *
542 * - word size is divisible by pixelbytes
543 * - cell scanline size is divisible by word size
544 * - cell scanlines are word-aligned
545 */
546 if ((word_size % screen.pixelbytes) == 0 &&
547 (FONT_WIDTH * screen.pixelbytes) % word_size == 0 &&
548 (x * screen.pixelbytes) % word_size == 0 &&
549 screen.scanline % word_size == 0) {
550
551 viewports[i].dglyph = draw_glyph_aligned;
552 } else {
553 viewports[i].dglyph = draw_glyph_fallback;
554 }
555
556 viewports[i].cur_col = 0;
557 viewports[i].cur_row = 0;
558 viewports[i].cursor_active = false;
559 viewports[i].cursor_shown = false;
560
561 viewports[i].bbsize = bbsize;
562 viewports[i].backbuf = backbuf;
563 viewports[i].bb_invalid = false;
564
565 viewports[i].initialized = true;
566
567 render_glyphs(&viewports[i]);
568
569 return i;
570}
571
572
573/** Initialize framebuffer as a chardev output device
574 *
575 * @param addr Address of the framebuffer
576 * @param xres Screen width in pixels
577 * @param yres Screen height in pixels
578 * @param visual Bits per pixel (8, 16, 24, 32)
579 * @param scan Bytes per one scanline
580 *
581 */
582static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
583 unsigned int scan, unsigned int visual)
584{
585 switch (visual) {
586 case VISUAL_INDIRECT_8:
587 screen.rgb_conv = rgb_323;
588 screen.pixelbytes = 1;
589 break;
590 case VISUAL_RGB_5_5_5:
591 screen.rgb_conv = rgb_555;
592 screen.pixelbytes = 2;
593 break;
594 case VISUAL_RGB_5_6_5:
595 screen.rgb_conv = rgb_565;
596 screen.pixelbytes = 2;
597 break;
598 case VISUAL_RGB_8_8_8:
599 screen.rgb_conv = rgb_888;
600 screen.pixelbytes = 3;
601 break;
602 case VISUAL_RGB_8_8_8_0:
603 screen.rgb_conv = rgb_888;
604 screen.pixelbytes = 4;
605 break;
606 case VISUAL_RGB_0_8_8_8:
607 screen.rgb_conv = rgb_0888;
608 screen.pixelbytes = 4;
609 break;
610 case VISUAL_BGR_0_8_8_8:
611 screen.rgb_conv = bgr_0888;
612 screen.pixelbytes = 4;
613 break;
614 default:
615 return false;
616 }
617
618 screen.fb_addr = (unsigned char *) addr;
619 screen.xres = xres;
620 screen.yres = yres;
621 screen.scanline = scan;
622
623 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
624 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
625
626 /* Create first viewport */
627 vport_create(0, 0, xres, yres);
628
629 return true;
630}
631
632
633/** Draw a glyph, takes advantage of alignment.
634 *
635 * This version can only be used if the following conditions are met:
636 *
637 * - word size is divisible by pixelbytes
638 * - cell scanline size is divisible by word size
639 * - cell scanlines are word-aligned
640 *
641 * It makes use of the pre-rendered mask to process (possibly) several
642 * pixels at once (word size / pixelbytes pixels at a time are processed)
643 * making it very fast. Most notably this version is not applicable at 24 bits
644 * per pixel.
645 *
646 * @param x x coordinate of top-left corner on screen.
647 * @param y y coordinate of top-left corner on screen.
648 * @param cursor Draw glyph with cursor
649 * @param glyphs Pointer to font bitmap.
650 * @param glyph Code of the glyph to draw.
651 * @param fg_color Foreground color.
652 * @param bg_color Backgroudn color.
653 */
654static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
655 uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color)
656{
657 unsigned int i, yd;
658 unsigned long fg_buf, bg_buf;
659 unsigned long *maskp, *dp;
660 unsigned long mask;
661 unsigned int ww, d_add;
662
663 /*
664 * Prepare a pair of words, one filled with foreground-color
665 * pattern and the other filled with background-color pattern.
666 */
667 for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
668 screen.rgb_conv(&((uint8_t *)&fg_buf)[i * screen.pixelbytes],
669 fg_color);
670 screen.rgb_conv(&((uint8_t *)&bg_buf)[i * screen.pixelbytes],
671 bg_color);
672 }
673
674
675 /* Pointer to the current position in the mask. */
676 maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
677
678 /* Pointer to the current position on the screen. */
679 dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
680
681 /* Width of the character cell in words. */
682 ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
683
684 /* Offset to add when moving to another screen scanline. */
685 d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
686
687 for (yd = 0; yd < FONT_SCANLINES; yd++) {
688 /*
689 * Now process the cell scanline, combining foreground
690 * and background color patters using the pre-rendered mask.
691 */
692 for (i = 0; i < ww; i++) {
693 mask = *maskp++;
694 *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
695 }
696
697 /* Move to the beginning of the next scanline of the cell. */
698 dp = (unsigned long *) ((uint8_t *) dp + d_add);
699 }
700}
701
702/** Draw a glyph, fallback version.
703 *
704 * This version does not make use of the pre-rendered mask, it uses
705 * the font bitmap directly. It works always, but it is slower.
706 *
707 * @param x x coordinate of top-left corner on screen.
708 * @param y y coordinate of top-left corner on screen.
709 * @param cursor Draw glyph with cursor
710 * @param glyphs Pointer to font bitmap.
711 * @param glyph Code of the glyph to draw.
712 * @param fg_color Foreground color.
713 * @param bg_color Backgroudn color.
714 */
715void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
716 uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color)
717{
718 unsigned int i, j, yd;
719 uint8_t fg_buf[4], bg_buf[4];
720 uint8_t *dp, *sp;
721 unsigned int d_add;
722 uint8_t b;
723
724 /* Pre-render 1x the foreground and background color pixels. */
725 if (cursor) {
726 screen.rgb_conv(fg_buf, bg_color);
727 screen.rgb_conv(bg_buf, fg_color);
728 } else {
729 screen.rgb_conv(fg_buf, fg_color);
730 screen.rgb_conv(bg_buf, bg_color);
731 }
732
733 /* Pointer to the current position on the screen. */
734 dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
735
736 /* Offset to add when moving to another screen scanline. */
737 d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
738
739 for (yd = 0; yd < FONT_SCANLINES; yd++) {
740 /* Byte containing bits of the glyph scanline. */
741 b = fb_font[glyph * FONT_SCANLINES + yd];
742
743 for (i = 0; i < FONT_WIDTH; i++) {
744 /* Choose color based on the current bit. */
745 sp = (b & 0x80) ? fg_buf : bg_buf;
746
747 /* Copy the pixel. */
748 for (j = 0; j < screen.pixelbytes; j++) {
749 *dp++ = *sp++;
750 }
751
752 /* Move to the next bit. */
753 b = b << 1;
754 }
755
756 /* Move to the beginning of the next scanline of the cell. */
757 dp += d_add;
758 }
759}
760
761/** Draw glyph at specified position in viewport.
762 *
763 * @param vport Viewport identification
764 * @param cursor Draw glyph with cursor
765 * @param col Screen position relative to viewport
766 * @param row Screen position relative to viewport
767 *
768 */
769static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
770 unsigned int row)
771{
772 unsigned int x = vport->x + COL2X(col);
773 unsigned int y = vport->y + ROW2Y(row);
774
775 uint8_t glyph;
776 uint32_t fg_color;
777 uint32_t bg_color;
778
779 glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
780 fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
781 bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
782
783 (*vport->dglyph)(x, y, cursor, vport->glyphs, glyph,
784 fg_color, bg_color);
785}
786
787/** Hide cursor if it is shown
788 *
789 */
790static void cursor_hide(viewport_t *vport)
791{
792 if ((vport->cursor_active) && (vport->cursor_shown)) {
793 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
794 vport->cursor_shown = false;
795 }
796}
797
798
799/** Show cursor if cursor showing is enabled
800 *
801 */
802static void cursor_show(viewport_t *vport)
803{
804 /* Do not check for cursor_shown */
805 if (vport->cursor_active) {
806 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
807 vport->cursor_shown = true;
808 }
809}
810
811
812/** Invert cursor, if it is enabled
813 *
814 */
815static void cursor_blink(viewport_t *vport)
816{
817 if (vport->cursor_shown)
818 cursor_hide(vport);
819 else
820 cursor_show(vport);
821}
822
823
824/** Draw character at given position relative to viewport
825 *
826 * @param vport Viewport identification
827 * @param c Character to draw
828 * @param col Screen position relative to viewport
829 * @param row Screen position relative to viewport
830 *
831 */
832static void draw_char(viewport_t *vport, uint8_t c, unsigned int col, unsigned int row)
833{
834 bb_cell_t *bbp;
835
836 /* Do not hide cursor if we are going to overwrite it */
837 if ((vport->cursor_active) && (vport->cursor_shown) &&
838 ((vport->cur_col != col) || (vport->cur_row != row)))
839 cursor_hide(vport);
840
841 bbp = &vport->backbuf[BB_POS(vport, col, row)];
842 bbp->glyph = c;
843 bbp->fg_color = vport->attr.fg_color;
844 bbp->bg_color = vport->attr.bg_color;
845
846 draw_vp_glyph(vport, false, col, row);
847
848 vport->cur_col = col;
849 vport->cur_row = row;
850
851 vport->cur_col++;
852 if (vport->cur_col >= vport->cols) {
853 vport->cur_col = 0;
854 vport->cur_row++;
855 if (vport->cur_row >= vport->rows)
856 vport->cur_row--;
857 }
858
859 cursor_show(vport);
860}
861
862
863/** Draw text data to viewport
864 *
865 * @param vport Viewport id
866 * @param data Text data fitting exactly into viewport
867 *
868 */
869static void draw_text_data(viewport_t *vport, keyfield_t *data)
870{
871 unsigned int i;
872 bb_cell_t *bbp;
873 attrs_t *a;
874 attr_rgb_t rgb;
875
876 for (i = 0; i < vport->cols * vport->rows; i++) {
877 unsigned int col = i % vport->cols;
878 unsigned int row = i / vport->cols;
879
880 bbp = &vport->backbuf[BB_POS(vport, col, row)];
881 uint8_t glyph = bbp->glyph;
882
883 a = &data[i].attrs;
884 rgb_from_attr(&rgb, a);
885
886 if (glyph != data[i].character ||
887 rgb.fg_color != bbp->fg_color ||
888 rgb.bg_color != bbp->bg_color ||
889 vport->bb_invalid) {
890 bbp->glyph = data[i].character;
891
892 bbp->fg_color = rgb.fg_color;
893 bbp->bg_color = rgb.bg_color;
894
895 draw_vp_glyph(vport, false, col, row);
896 }
897 }
898 cursor_show(vport);
899}
900
901
902static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
903{
904 int pm = *((int *) data);
905 pixmap_t *pmap = &pixmaps[pm];
906 unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
907
908 screen.rgb_conv(&pmap->data[pos], color);
909}
910
911
912static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
913{
914 viewport_t *vport = (viewport_t *) data;
915 unsigned int dx = vport->x + x;
916 unsigned int dy = vport->y + y;
917
918 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
919}
920
921
922/** Return first free pixmap
923 *
924 */
925static int find_free_pixmap(void)
926{
927 unsigned int i;
928
929 for (i = 0; i < MAX_PIXMAPS; i++)
930 if (!pixmaps[i].data)
931 return i;
932
933 return -1;
934}
935
936
937/** Create a new pixmap and return appropriate ID
938 *
939 */
940static int shm2pixmap(unsigned char *shm, size_t size)
941{
942 int pm;
943 pixmap_t *pmap;
944
945 pm = find_free_pixmap();
946 if (pm == -1)
947 return ELIMIT;
948
949 pmap = &pixmaps[pm];
950
951 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
952 return EINVAL;
953
954 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
955 if (!pmap->data)
956 return ENOMEM;
957
958 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
959
960 return pm;
961}
962
963
964/** Handle shared memory communication calls
965 *
966 * Protocol for drawing pixmaps:
967 * - FB_PREPARE_SHM(client shm identification)
968 * - IPC_M_AS_AREA_SEND
969 * - FB_DRAW_PPM(startx, starty)
970 * - FB_DROP_SHM
971 *
972 * Protocol for text drawing
973 * - IPC_M_AS_AREA_SEND
974 * - FB_DRAW_TEXT_DATA
975 *
976 * @param callid Callid of the current call
977 * @param call Current call data
978 * @param vp Active viewport
979 *
980 * @return false if the call was not handled byt this function, true otherwise
981 *
982 * Note: this function is not threads safe, you would have
983 * to redefine static variables with __thread
984 *
985 */
986static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
987{
988 static keyfield_t *interbuffer = NULL;
989 static size_t intersize = 0;
990
991 static unsigned char *shm = NULL;
992 static ipcarg_t shm_id = 0;
993 static size_t shm_size;
994
995 bool handled = true;
996 int retval = EOK;
997 viewport_t *vport = &viewports[vp];
998 unsigned int x;
999 unsigned int y;
1000
1001 switch (IPC_GET_METHOD(*call)) {
1002 case IPC_M_SHARE_OUT:
1003 /* We accept one area for data interchange */
1004 if (IPC_GET_ARG1(*call) == shm_id) {
1005 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
1006 shm_size = IPC_GET_ARG2(*call);
1007 if (!ipc_answer_1(callid, EOK, (sysarg_t) dest))
1008 shm = dest;
1009 else
1010 shm_id = 0;
1011
1012 if (shm[0] != 'P')
1013 return false;
1014
1015 return true;
1016 } else {
1017 intersize = IPC_GET_ARG2(*call);
1018 receive_comm_area(callid, call, (void *) &interbuffer);
1019 }
1020 return true;
1021 case FB_PREPARE_SHM:
1022 if (shm_id)
1023 retval = EBUSY;
1024 else
1025 shm_id = IPC_GET_ARG1(*call);
1026 break;
1027
1028 case FB_DROP_SHM:
1029 if (shm) {
1030 as_area_destroy(shm);
1031 shm = NULL;
1032 }
1033 shm_id = 0;
1034 break;
1035
1036 case FB_SHM2PIXMAP:
1037 if (!shm) {
1038 retval = EINVAL;
1039 break;
1040 }
1041 retval = shm2pixmap(shm, shm_size);
1042 break;
1043 case FB_DRAW_PPM:
1044 if (!shm) {
1045 retval = EINVAL;
1046 break;
1047 }
1048 x = IPC_GET_ARG1(*call);
1049 y = IPC_GET_ARG2(*call);
1050
1051 if ((x > vport->width) || (y > vport->height)) {
1052 retval = EINVAL;
1053 break;
1054 }
1055
1056 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
1057 IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
1058 break;
1059 case FB_DRAW_TEXT_DATA:
1060 if (!interbuffer) {
1061 retval = EINVAL;
1062 break;
1063 }
1064 if (intersize < vport->cols * vport->rows * sizeof(*interbuffer)) {
1065 retval = EINVAL;
1066 break;
1067 }
1068 draw_text_data(vport, interbuffer);
1069 break;
1070 default:
1071 handled = false;
1072 }
1073
1074 if (handled)
1075 ipc_answer_0(callid, retval);
1076 return handled;
1077}
1078
1079
1080static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
1081{
1082 unsigned int width = vport->width;
1083 unsigned int height = vport->height;
1084
1085 if (width + vport->x > screen.xres)
1086 width = screen.xres - vport->x;
1087 if (height + vport->y > screen.yres)
1088 height = screen.yres - vport->y;
1089
1090 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1091 unsigned int realheight = pmap->height <= height ? pmap->height : height;
1092
1093 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1094 unsigned int realrowsize = realwidth * screen.pixelbytes;
1095
1096 unsigned int y;
1097 for (y = 0; y < realheight; y++) {
1098 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1099 memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
1100 }
1101}
1102
1103
1104/** Save viewport to pixmap
1105 *
1106 */
1107static int save_vp_to_pixmap(viewport_t *vport)
1108{
1109 int pm;
1110 pixmap_t *pmap;
1111
1112 pm = find_free_pixmap();
1113 if (pm == -1)
1114 return ELIMIT;
1115
1116 pmap = &pixmaps[pm];
1117 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
1118 if (!pmap->data)
1119 return ENOMEM;
1120
1121 pmap->width = vport->width;
1122 pmap->height = vport->height;
1123
1124 copy_vp_to_pixmap(vport, pmap);
1125
1126 return pm;
1127}
1128
1129
1130/** Draw pixmap on screen
1131 *
1132 * @param vp Viewport to draw on
1133 * @param pm Pixmap identifier
1134 *
1135 */
1136static int draw_pixmap(int vp, int pm)
1137{
1138 pixmap_t *pmap = &pixmaps[pm];
1139 viewport_t *vport = &viewports[vp];
1140
1141 unsigned int width = vport->width;
1142 unsigned int height = vport->height;
1143
1144 if (width + vport->x > screen.xres)
1145 width = screen.xres - vport->x;
1146 if (height + vport->y > screen.yres)
1147 height = screen.yres - vport->y;
1148
1149 if (!pmap->data)
1150 return EINVAL;
1151
1152 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1153 unsigned int realheight = pmap->height <= height ? pmap->height : height;
1154
1155 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1156 unsigned int realrowsize = realwidth * screen.pixelbytes;
1157
1158 unsigned int y;
1159 for (y = 0; y < realheight; y++) {
1160 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1161 memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
1162 }
1163
1164 return EOK;
1165}
1166
1167
1168/** Tick animation one step forward
1169 *
1170 */
1171static void anims_tick(void)
1172{
1173 unsigned int i;
1174 static int counts = 0;
1175
1176 /* Limit redrawing */
1177 counts = (counts + 1) % 8;
1178 if (counts)
1179 return;
1180
1181 for (i = 0; i < MAX_ANIMATIONS; i++) {
1182 if ((!animations[i].animlen) || (!animations[i].initialized) ||
1183 (!animations[i].enabled))
1184 continue;
1185
1186 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
1187 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
1188 }
1189}
1190
1191
1192static unsigned int pointer_x;
1193static unsigned int pointer_y;
1194static bool pointer_shown, pointer_enabled;
1195static int pointer_vport = -1;
1196static int pointer_pixmap = -1;
1197
1198
1199static void mouse_show(void)
1200{
1201 int i, j;
1202 int visibility;
1203 int color;
1204 int bytepos;
1205
1206 if ((pointer_shown) || (!pointer_enabled))
1207 return;
1208
1209 /* Save image under the pointer. */
1210 if (pointer_vport == -1) {
1211 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
1212 if (pointer_vport < 0)
1213 return;
1214 } else {
1215 viewports[pointer_vport].x = pointer_x;
1216 viewports[pointer_vport].y = pointer_y;
1217 }
1218
1219 if (pointer_pixmap == -1)
1220 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
1221 else
1222 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
1223
1224 /* Draw mouse pointer. */
1225 for (i = 0; i < pointer_height; i++)
1226 for (j = 0; j < pointer_width; j++) {
1227 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
1228 visibility = pointer_mask_bits[bytepos] &
1229 (1 << (j % 8));
1230 if (visibility) {
1231 color = pointer_bits[bytepos] &
1232 (1 << (j % 8)) ? 0 : 0xffffff;
1233 if (pointer_x + j < screen.xres && pointer_y +
1234 i < screen.yres)
1235 putpixel(&viewports[0], pointer_x + j,
1236 pointer_y + i, color);
1237 }
1238 }
1239 pointer_shown = 1;
1240}
1241
1242
1243static void mouse_hide(void)
1244{
1245 /* Restore image under the pointer. */
1246 if (pointer_shown) {
1247 draw_pixmap(pointer_vport, pointer_pixmap);
1248 pointer_shown = 0;
1249 }
1250}
1251
1252
1253static void mouse_move(unsigned int x, unsigned int y)
1254{
1255 mouse_hide();
1256 pointer_x = x;
1257 pointer_y = y;
1258 mouse_show();
1259}
1260
1261
1262static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1263{
1264 bool handled = true;
1265 int retval = EOK;
1266 int i, nvp;
1267 int newval;
1268
1269 switch (IPC_GET_METHOD(*call)) {
1270 case FB_ANIM_CREATE:
1271 nvp = IPC_GET_ARG1(*call);
1272 if (nvp == -1)
1273 nvp = vp;
1274 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1275 !viewports[nvp].initialized) {
1276 retval = EINVAL;
1277 break;
1278 }
1279 for (i = 0; i < MAX_ANIMATIONS; i++) {
1280 if (!animations[i].initialized)
1281 break;
1282 }
1283 if (i == MAX_ANIMATIONS) {
1284 retval = ELIMIT;
1285 break;
1286 }
1287 animations[i].initialized = 1;
1288 animations[i].animlen = 0;
1289 animations[i].pos = 0;
1290 animations[i].enabled = 0;
1291 animations[i].vp = nvp;
1292 retval = i;
1293 break;
1294 case FB_ANIM_DROP:
1295 i = IPC_GET_ARG1(*call);
1296 if (i >= MAX_ANIMATIONS || i < 0) {
1297 retval = EINVAL;
1298 break;
1299 }
1300 animations[i].initialized = 0;
1301 break;
1302 case FB_ANIM_ADDPIXMAP:
1303 i = IPC_GET_ARG1(*call);
1304 if (i >= MAX_ANIMATIONS || i < 0 ||
1305 !animations[i].initialized) {
1306 retval = EINVAL;
1307 break;
1308 }
1309 if (animations[i].animlen == MAX_ANIM_LEN) {
1310 retval = ELIMIT;
1311 break;
1312 }
1313 newval = IPC_GET_ARG2(*call);
1314 if (newval < 0 || newval > MAX_PIXMAPS ||
1315 !pixmaps[newval].data) {
1316 retval = EINVAL;
1317 break;
1318 }
1319 animations[i].pixmaps[animations[i].animlen++] = newval;
1320 break;
1321 case FB_ANIM_CHGVP:
1322 i = IPC_GET_ARG1(*call);
1323 if (i >= MAX_ANIMATIONS || i < 0) {
1324 retval = EINVAL;
1325 break;
1326 }
1327 nvp = IPC_GET_ARG2(*call);
1328 if (nvp == -1)
1329 nvp = vp;
1330 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1331 !viewports[nvp].initialized) {
1332 retval = EINVAL;
1333 break;
1334 }
1335 animations[i].vp = nvp;
1336 break;
1337 case FB_ANIM_START:
1338 case FB_ANIM_STOP:
1339 i = IPC_GET_ARG1(*call);
1340 if (i >= MAX_ANIMATIONS || i < 0) {
1341 retval = EINVAL;
1342 break;
1343 }
1344 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
1345 if (newval ^ animations[i].enabled) {
1346 animations[i].enabled = newval;
1347 anims_enabled += newval ? 1 : -1;
1348 }
1349 break;
1350 default:
1351 handled = 0;
1352 }
1353 if (handled)
1354 ipc_answer_0(callid, retval);
1355 return handled;
1356}
1357
1358
1359/** Handler for messages concerning pixmap handling
1360 *
1361 */
1362static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1363{
1364 bool handled = true;
1365 int retval = EOK;
1366 int i, nvp;
1367
1368 switch (IPC_GET_METHOD(*call)) {
1369 case FB_VP_DRAW_PIXMAP:
1370 nvp = IPC_GET_ARG1(*call);
1371 if (nvp == -1)
1372 nvp = vp;
1373 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1374 !viewports[nvp].initialized) {
1375 retval = EINVAL;
1376 break;
1377 }
1378 i = IPC_GET_ARG2(*call);
1379 retval = draw_pixmap(nvp, i);
1380 break;
1381 case FB_VP2PIXMAP:
1382 nvp = IPC_GET_ARG1(*call);
1383 if (nvp == -1)
1384 nvp = vp;
1385 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1386 !viewports[nvp].initialized)
1387 retval = EINVAL;
1388 else
1389 retval = save_vp_to_pixmap(&viewports[nvp]);
1390 break;
1391 case FB_DROP_PIXMAP:
1392 i = IPC_GET_ARG1(*call);
1393 if (i >= MAX_PIXMAPS) {
1394 retval = EINVAL;
1395 break;
1396 }
1397 if (pixmaps[i].data) {
1398 free(pixmaps[i].data);
1399 pixmaps[i].data = NULL;
1400 }
1401 break;
1402 default:
1403 handled = 0;
1404 }
1405
1406 if (handled)
1407 ipc_answer_0(callid, retval);
1408 return handled;
1409
1410}
1411
1412static int rgb_from_style(attr_rgb_t *rgb, int style)
1413{
1414 switch (style) {
1415 case STYLE_NORMAL:
1416 rgb->fg_color = color_table[COLOR_BLACK];
1417 rgb->bg_color = color_table[COLOR_WHITE];
1418 break;
1419 case STYLE_EMPHASIS:
1420 rgb->fg_color = color_table[COLOR_RED];
1421 rgb->bg_color = color_table[COLOR_WHITE];
1422 break;
1423 default:
1424 return EINVAL;
1425 }
1426
1427 return EOK;
1428}
1429
1430static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
1431 ipcarg_t bg_color, ipcarg_t flags)
1432{
1433 fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1434 bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1435
1436 rgb->fg_color = color_table[fg_color];
1437 rgb->bg_color = color_table[bg_color];
1438
1439 return EOK;
1440}
1441
1442static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
1443{
1444 int rc;
1445
1446 switch (a->t) {
1447 case at_style:
1448 rc = rgb_from_style(rgb, a->a.s.style);
1449 break;
1450 case at_idx:
1451 rc = rgb_from_idx(rgb, a->a.i.fg_color,
1452 a->a.i.bg_color, a->a.i.flags);
1453 break;
1454 case at_rgb:
1455 *rgb = a->a.r;
1456 rc = EOK;
1457 break;
1458 }
1459
1460 return rc;
1461}
1462
1463static int fb_set_style(viewport_t *vport, ipcarg_t style)
1464{
1465 return rgb_from_style(&vport->attr, (int) style);
1466}
1467
1468static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
1469 ipcarg_t bg_color, ipcarg_t flags)
1470{
1471 return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
1472}
1473
1474/** Function for handling connections to FB
1475 *
1476 */
1477static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1478{
1479 unsigned int vp = 0;
1480 viewport_t *vport = &viewports[vp];
1481
1482 if (client_connected) {
1483 ipc_answer_0(iid, ELIMIT);
1484 return;
1485 }
1486
1487 /* Accept connection */
1488 client_connected = true;
1489 ipc_answer_0(iid, EOK);
1490
1491 while (true) {
1492 ipc_callid_t callid;
1493 ipc_call_t call;
1494 int retval;
1495 unsigned int i;
1496 int scroll;
1497 uint8_t glyph;
1498 unsigned int row, col;
1499
1500 if ((vport->cursor_active) || (anims_enabled))
1501 callid = async_get_call_timeout(&call, 250000);
1502 else
1503 callid = async_get_call(&call);
1504
1505 mouse_hide();
1506 if (!callid) {
1507 cursor_blink(vport);
1508 anims_tick();
1509 mouse_show();
1510 continue;
1511 }
1512
1513 if (shm_handle(callid, &call, vp))
1514 continue;
1515
1516 if (pixmap_handle(callid, &call, vp))
1517 continue;
1518
1519 if (anim_handle(callid, &call, vp))
1520 continue;
1521
1522 switch (IPC_GET_METHOD(call)) {
1523 case IPC_M_PHONE_HUNGUP:
1524 client_connected = false;
1525
1526 /* Cleanup other viewports */
1527 for (i = 1; i < MAX_VIEWPORTS; i++)
1528 vport->initialized = false;
1529
1530 /* Exit thread */
1531 return;
1532
1533 case FB_PUTCHAR:
1534 glyph = IPC_GET_ARG1(call);
1535 row = IPC_GET_ARG2(call);
1536 col = IPC_GET_ARG3(call);
1537
1538 if ((col >= vport->cols) || (row >= vport->rows)) {
1539 retval = EINVAL;
1540 break;
1541 }
1542 ipc_answer_0(callid, EOK);
1543
1544 draw_char(vport, glyph, col, row);
1545
1546 /* Message already answered */
1547 continue;
1548 case FB_CLEAR:
1549 vport_clear(vport);
1550 cursor_show(vport);
1551 retval = EOK;
1552 break;
1553 case FB_CURSOR_GOTO:
1554 row = IPC_GET_ARG1(call);
1555 col = IPC_GET_ARG2(call);
1556
1557 if ((col >= vport->cols) || (row >= vport->rows)) {
1558 retval = EINVAL;
1559 break;
1560 }
1561 retval = EOK;
1562
1563 cursor_hide(vport);
1564 vport->cur_col = col;
1565 vport->cur_row = row;
1566 cursor_show(vport);
1567 break;
1568 case FB_CURSOR_VISIBILITY:
1569 cursor_hide(vport);
1570 vport->cursor_active = IPC_GET_ARG1(call);
1571 cursor_show(vport);
1572 retval = EOK;
1573 break;
1574 case FB_GET_CSIZE:
1575 ipc_answer_2(callid, EOK, vport->rows, vport->cols);
1576 continue;
1577 case FB_SCROLL:
1578 scroll = IPC_GET_ARG1(call);
1579 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
1580 retval = EINVAL;
1581 break;
1582 }
1583 cursor_hide(vport);
1584 vport_scroll(vport, scroll);
1585 cursor_show(vport);
1586 retval = EOK;
1587 break;
1588 case FB_VIEWPORT_SWITCH:
1589 i = IPC_GET_ARG1(call);
1590 if (i >= MAX_VIEWPORTS) {
1591 retval = EINVAL;
1592 break;
1593 }
1594 if (!viewports[i].initialized) {
1595 retval = EADDRNOTAVAIL;
1596 break;
1597 }
1598 cursor_hide(vport);
1599 vp = i;
1600 vport = &viewports[vp];
1601 cursor_show(vport);
1602 retval = EOK;
1603 break;
1604 case FB_VIEWPORT_CREATE:
1605 retval = vport_create(IPC_GET_ARG1(call) >> 16,
1606 IPC_GET_ARG1(call) & 0xffff,
1607 IPC_GET_ARG2(call) >> 16,
1608 IPC_GET_ARG2(call) & 0xffff);
1609 break;
1610 case FB_VIEWPORT_DELETE:
1611 i = IPC_GET_ARG1(call);
1612 if (i >= MAX_VIEWPORTS) {
1613 retval = EINVAL;
1614 break;
1615 }
1616 if (!viewports[i].initialized) {
1617 retval = EADDRNOTAVAIL;
1618 break;
1619 }
1620 viewports[i].initialized = false;
1621 if (viewports[i].glyphs)
1622 free(viewports[i].glyphs);
1623 if (viewports[i].bgpixel)
1624 free(viewports[i].bgpixel);
1625 if (viewports[i].backbuf)
1626 free(viewports[i].backbuf);
1627 retval = EOK;
1628 break;
1629 case FB_VIEWPORT_INVALIDATE:
1630 i = IPC_GET_ARG1(call);
1631 if (i >= MAX_VIEWPORTS) {
1632 retval = EINVAL;
1633 break;
1634 }
1635 viewports[i].bb_invalid = true;
1636 retval = EOK;
1637 break;
1638
1639 case FB_SET_STYLE:
1640 retval = fb_set_style(vport, IPC_GET_ARG1(call));
1641 break;
1642 case FB_SET_COLOR:
1643 retval = fb_set_color(vport, IPC_GET_ARG1(call),
1644 IPC_GET_ARG2(call), IPC_GET_ARG3(call));
1645 break;
1646 case FB_SET_RGB_COLOR:
1647 vport->attr.fg_color = IPC_GET_ARG1(call);
1648 vport->attr.bg_color = IPC_GET_ARG2(call);
1649 retval = EOK;
1650 break;
1651 case FB_GET_RESOLUTION:
1652 ipc_answer_2(callid, EOK, screen.xres, screen.yres);
1653 continue;
1654 case FB_POINTER_MOVE:
1655 pointer_enabled = true;
1656 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1657 retval = EOK;
1658 break;
1659 default:
1660 retval = ENOENT;
1661 }
1662 ipc_answer_0(callid, retval);
1663 }
1664}
1665
1666/** Initialization of framebuffer
1667 *
1668 */
1669int fb_init(void)
1670{
1671 async_set_client_connection(fb_client_connection);
1672
1673 void *fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1674 unsigned int fb_offset = sysinfo_value("fb.offset");
1675 unsigned int fb_width = sysinfo_value("fb.width");
1676 unsigned int fb_height = sysinfo_value("fb.height");
1677 unsigned int fb_scanline = sysinfo_value("fb.scanline");
1678 unsigned int fb_visual = sysinfo_value("fb.visual");
1679
1680 unsigned int fbsize = fb_scanline * fb_height;
1681 void *fb_addr = as_get_mappable_page(fbsize);
1682
1683 physmem_map(fb_ph_addr + fb_offset, fb_addr,
1684 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
1685
1686 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
1687 return 0;
1688
1689 return -1;
1690}
1691
1692/**
1693 * @}
1694 */
Note: See TracBrowser for help on using the repository browser.