source: mainline/uspace/srv/fb/fb.c@ 2d32081

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

Minor refactoring in fb server.

  • Property mode set to 100644
File size: 29.4 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 <async.h>
55#include <bool.h>
56
57#include "font-8x16.h"
58#include "fb.h"
59#include "main.h"
60#include "../console/screenbuffer.h"
61#include "ppm.h"
62
63#include "pointer.xbm"
64#include "pointer_mask.xbm"
65
66#define DEFAULT_BGCOLOR 0xf0f0f0
67#define DEFAULT_FGCOLOR 0x000000
68
69#define MAX_ANIM_LEN 8
70#define MAX_ANIMATIONS 4
71#define MAX_PIXMAPS 256 /**< Maximum number of saved pixmaps */
72#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
73
74typedef void (*rgb_conv_t)(void *, uint32_t);
75
76struct {
77 uint8_t *fb_addr;
78
79 unsigned int xres;
80 unsigned int yres;
81
82 unsigned int scanline;
83 unsigned int glyphscanline;
84
85 unsigned int pixelbytes;
86 unsigned int glyphbytes;
87
88 rgb_conv_t rgb_conv;
89} screen;
90
91typedef struct {
92 bool initialized;
93 unsigned int x;
94 unsigned int y;
95 unsigned int width;
96 unsigned int height;
97
98 /* Text support in window */
99 unsigned int cols;
100 unsigned int rows;
101
102 /* Style and glyphs for text printing */
103 style_t style;
104 uint8_t *glyphs;
105 uint8_t *bgpixel;
106
107 /* Auto-cursor position */
108 bool cursor_active;
109 unsigned int cur_col;
110 unsigned int cur_row;
111 bool cursor_shown;
112
113 /* Back buffer */
114 unsigned int bbsize;
115 uint8_t *backbuf;
116} viewport_t;
117
118typedef struct {
119 bool initialized;
120 bool enabled;
121 unsigned int vp;
122
123 unsigned int pos;
124 unsigned int animlen;
125 unsigned int pixmaps[MAX_ANIM_LEN];
126} animation_t;
127
128static animation_t animations[MAX_ANIMATIONS];
129static bool anims_enabled;
130
131typedef struct {
132 unsigned int width;
133 unsigned int height;
134 uint8_t *data;
135} pixmap_t;
136
137static pixmap_t pixmaps[MAX_PIXMAPS];
138static viewport_t viewports[128];
139
140static bool client_connected = false; /**< Allow only 1 connection */
141
142static void draw_glyph(viewport_t *vport, bool cursor, unsigned int col,
143 unsigned int row);
144
145
146#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
147#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
148#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
149
150#define COL2X(col) ((col) * FONT_WIDTH)
151#define ROW2Y(row) ((row) * FONT_SCANLINES)
152
153#define X2COL(x) ((x) / FONT_WIDTH)
154#define Y2ROW(y) ((y) / FONT_SCANLINES)
155
156#define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
157#define BB_POS(vport, col, row) ((row) * vport->cols + (col))
158#define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
159
160
161/** ARGB 8:8:8:8 conversion
162 *
163 */
164static void rgb_0888(void *dst, uint32_t rgb)
165{
166 *((uint32_t *) dst) = rgb & 0xffffff;
167}
168
169
170/** ABGR 8:8:8:8 conversion
171 *
172 */
173static void bgr_0888(void *dst, uint32_t rgb)
174{
175 *((uint32_t *) dst)
176 = (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | RED(rgb, 8);
177}
178
179
180/** BGR 8:8:8 conversion
181 *
182 */
183static void rgb_888(void *dst, uint32_t rgb)
184{
185#if defined(FB_INVERT_ENDIAN)
186 ((uint8_t *) dst)[0] = RED(rgb, 8);
187 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
188 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
189#else
190 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
191 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
192 ((uint8_t *) dst)[2] = RED(rgb, 8);
193#endif
194}
195
196
197/** RGB 5:5:5 conversion
198 *
199 */
200static void rgb_555(void *dst, uint32_t rgb)
201{
202 *((uint16_t *) dst)
203 = (RED(rgb, 5) << 10) | (GREEN(rgb, 5) << 5) | BLUE(rgb, 5);
204}
205
206
207/** RGB 5:6:5 conversion
208 *
209 */
210static void rgb_565(void *dst, uint32_t rgb)
211{
212 *((uint16_t *) dst)
213 = (RED(rgb, 5) << 11) | (GREEN(rgb, 6) << 5) | BLUE(rgb, 5);
214}
215
216
217/** RGB 3:2:3
218 *
219 */
220static void rgb_323(void *dst, uint32_t rgb)
221{
222 *((uint8_t *) dst)
223 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
224}
225
226/** Draw a filled rectangle. */
227static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
228 unsigned int y1, uint32_t color)
229{
230 unsigned int x, y;
231 uint8_t cbuf[4];
232
233 screen.rgb_conv(cbuf, color);
234
235 for (y = y0; y < y1; y++) {
236 for (x = x0; x < x1; x++) {
237 memcpy(&screen.fb_addr[FB_POS(x, y)], cbuf,
238 screen.pixelbytes);
239 }
240 }
241}
242
243/** Redraw viewport.
244 *
245 * @param vport Viewport to redraw
246 *
247 */
248static void vport_redraw(viewport_t *vport)
249{
250 unsigned int row, col;
251
252 for (row = 0; row < vport->rows; row++) {
253 for (col = 0; col < vport->cols; col++) {
254 draw_glyph(vport, false, col, row);
255 }
256 }
257
258 if (COL2X(vport->cols) < vport->width) {
259 draw_filled_rect(
260 vport->x + COL2X(vport->cols), vport->y,
261 vport->x + vport->width, vport->y + vport->height,
262 vport->style.bg_color);
263 }
264
265 if (ROW2Y(vport->rows) < vport->height) {
266 draw_filled_rect(
267 vport->x, vport->y + ROW2Y(vport->rows),
268 vport->x + vport->width, vport->y + vport->height,
269 vport->style.bg_color);
270 }
271}
272
273
274/** Clear viewport
275 *
276 * @param vport Viewport to clear
277 *
278 */
279static void vport_clear(viewport_t *vport)
280{
281 memset(vport->backbuf, 0, vport->bbsize);
282 vport_redraw(vport);
283}
284
285/** Scroll viewport by given number of lines
286 *
287 * @param vport Viewport to scroll
288 * @param lines Number of lines to scroll
289 *
290 */
291static void vport_scroll(viewport_t *vport, int lines)
292{
293 unsigned int row, col;
294
295 if (lines > 0) {
296 memcpy(vport->backbuf, vport->backbuf + vport->cols * lines,
297 vport->cols * (vport->rows - lines));
298 memset(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
299 0, vport->cols * lines);
300 } else {
301 memcpy(vport->backbuf - vport->cols * lines, vport->backbuf,
302 vport->cols * (vport->rows + lines));
303 memset(vport->backbuf, 0, - vport->cols * lines);
304 }
305
306 for (row = 0; row < vport->rows; row++) {
307 for (col = 0; col < vport->cols; col++) {
308 draw_glyph(vport, false, col, row);
309 }
310 }
311}
312
313/** Render glyphs
314 *
315 * Convert glyphs from device independent font
316 * description to current visual representation.
317 *
318 * @param vport Viewport
319 *
320 */
321static void render_glyphs(viewport_t* vport)
322{
323 unsigned int glyph;
324
325 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
326 unsigned int y;
327
328 for (y = 0; y < FONT_SCANLINES; y++) {
329 unsigned int x;
330
331 for (x = 0; x < FONT_WIDTH; x++) {
332 screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
333 (fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
334 ? vport->style.fg_color : vport->style.bg_color);
335
336 uint32_t curcolor;
337
338 if (y < FONT_SCANLINES - 2)
339 curcolor =
340 (fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
341 ? vport->style.fg_color : vport->style.bg_color;
342 else
343 curcolor = vport->style.fg_color;
344
345 screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes], curcolor);
346 }
347 }
348 }
349
350 screen.rgb_conv(vport->bgpixel, vport->style.bg_color);
351}
352
353
354/** Create new viewport
355 *
356 * @param x Origin of the viewport (x).
357 * @param y Origin of the viewport (y).
358 * @param width Width of the viewport.
359 * @param height Height of the viewport.
360 *
361 * @return New viewport number.
362 *
363 */
364static int vport_create(unsigned int x, unsigned int y,
365 unsigned int width, unsigned int height)
366{
367 unsigned int i;
368
369 for (i = 0; i < MAX_VIEWPORTS; i++) {
370 if (!viewports[i].initialized)
371 break;
372 }
373 if (i == MAX_VIEWPORTS)
374 return ELIMIT;
375
376 unsigned int cols = width / FONT_WIDTH;
377 unsigned int rows = height / FONT_SCANLINES;
378 unsigned int bbsize = cols * rows;
379 unsigned int glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
380
381 uint8_t *backbuf = (uint8_t *) malloc(bbsize);
382 if (!backbuf)
383 return ENOMEM;
384
385 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
386 if (!glyphs) {
387 free(backbuf);
388 return ENOMEM;
389 }
390
391 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
392 if (!bgpixel) {
393 free(glyphs);
394 free(backbuf);
395 return ENOMEM;
396 }
397
398 memset(backbuf, 0, bbsize);
399 memset(glyphs, 0, glyphsize);
400 memset(bgpixel, 0, screen.pixelbytes);
401
402 viewports[i].x = x;
403 viewports[i].y = y;
404 viewports[i].width = width;
405 viewports[i].height = height;
406
407 viewports[i].cols = cols;
408 viewports[i].rows = rows;
409
410 viewports[i].style.bg_color = DEFAULT_BGCOLOR;
411 viewports[i].style.fg_color = DEFAULT_FGCOLOR;
412
413 viewports[i].glyphs = glyphs;
414 viewports[i].bgpixel = bgpixel;
415
416 viewports[i].cur_col = 0;
417 viewports[i].cur_row = 0;
418 viewports[i].cursor_active = false;
419 viewports[i].cursor_shown = false;
420
421 viewports[i].bbsize = bbsize;
422 viewports[i].backbuf = backbuf;
423
424 viewports[i].initialized = true;
425
426 render_glyphs(&viewports[i]);
427
428 return i;
429}
430
431
432/** Initialize framebuffer as a chardev output device
433 *
434 * @param addr Address of the framebuffer
435 * @param xres Screen width in pixels
436 * @param yres Screen height in pixels
437 * @param visual Bits per pixel (8, 16, 24, 32)
438 * @param scan Bytes per one scanline
439 *
440 */
441static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
442 unsigned int scan, unsigned int visual)
443{
444 switch (visual) {
445 case VISUAL_INDIRECT_8:
446 screen.rgb_conv = rgb_323;
447 screen.pixelbytes = 1;
448 break;
449 case VISUAL_RGB_5_5_5:
450 screen.rgb_conv = rgb_555;
451 screen.pixelbytes = 2;
452 break;
453 case VISUAL_RGB_5_6_5:
454 screen.rgb_conv = rgb_565;
455 screen.pixelbytes = 2;
456 break;
457 case VISUAL_RGB_8_8_8:
458 screen.rgb_conv = rgb_888;
459 screen.pixelbytes = 3;
460 break;
461 case VISUAL_RGB_8_8_8_0:
462 screen.rgb_conv = rgb_888;
463 screen.pixelbytes = 4;
464 break;
465 case VISUAL_RGB_0_8_8_8:
466 screen.rgb_conv = rgb_0888;
467 screen.pixelbytes = 4;
468 break;
469 case VISUAL_BGR_0_8_8_8:
470 screen.rgb_conv = bgr_0888;
471 screen.pixelbytes = 4;
472 break;
473 default:
474 return false;
475 }
476
477 screen.fb_addr = (unsigned char *) addr;
478 screen.xres = xres;
479 screen.yres = yres;
480 screen.scanline = scan;
481
482 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
483 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
484
485 /* Create first viewport */
486 vport_create(0, 0, xres, yres);
487
488 return true;
489}
490
491
492/** Draw glyph at given position relative to viewport
493 *
494 * @param vport Viewport identification
495 * @param cursor Draw glyph with cursor
496 * @param col Screen position relative to viewport
497 * @param row Screen position relative to viewport
498 *
499 */
500static void draw_glyph(viewport_t *vport, bool cursor, unsigned int col, unsigned int row)
501{
502 unsigned int x = vport->x + COL2X(col);
503 unsigned int y = vport->y + ROW2Y(row);
504 unsigned int yd;
505
506 uint8_t glyph = vport->backbuf[BB_POS(vport, col, row)];
507
508 for (yd = 0; yd < FONT_SCANLINES; yd++)
509 memcpy(&screen.fb_addr[FB_POS(x, y + yd)],
510 &vport->glyphs[GLYPH_POS(glyph, yd, cursor)], screen.glyphscanline);
511}
512
513
514/** Hide cursor if it is shown
515 *
516 */
517static void cursor_hide(viewport_t *vport)
518{
519 if ((vport->cursor_active) && (vport->cursor_shown)) {
520 draw_glyph(vport, false, vport->cur_col, vport->cur_row);
521 vport->cursor_shown = false;
522 }
523}
524
525
526/** Show cursor if cursor showing is enabled
527 *
528 */
529static void cursor_show(viewport_t *vport)
530{
531 /* Do not check for cursor_shown */
532 if (vport->cursor_active) {
533 draw_glyph(vport, true, vport->cur_col, vport->cur_row);
534 vport->cursor_shown = true;
535 }
536}
537
538
539/** Invert cursor, if it is enabled
540 *
541 */
542static void cursor_blink(viewport_t *vport)
543{
544 if (vport->cursor_shown)
545 cursor_hide(vport);
546 else
547 cursor_show(vport);
548}
549
550
551/** Draw character at given position relative to viewport
552 *
553 * @param vport Viewport identification
554 * @param c Character to draw
555 * @param col Screen position relative to viewport
556 * @param row Screen position relative to viewport
557 *
558 */
559static void draw_char(viewport_t *vport, uint8_t c, unsigned int col, unsigned int row)
560{
561 /* Do not hide cursor if we are going to overwrite it */
562 if ((vport->cursor_active) && (vport->cursor_shown) &&
563 ((vport->cur_col != col) || (vport->cur_row != row)))
564 cursor_hide(vport);
565
566 vport->backbuf[BB_POS(vport, col, row)] = c;
567 draw_glyph(vport, false, col, row);
568
569 vport->cur_col = col;
570 vport->cur_row = row;
571
572 vport->cur_col++;
573 if (vport->cur_col >= vport->cols) {
574 vport->cur_col = 0;
575 vport->cur_row++;
576 if (vport->cur_row >= vport->rows)
577 vport->cur_row--;
578 }
579
580 cursor_show(vport);
581}
582
583
584/** Draw text data to viewport
585 *
586 * @param vport Viewport id
587 * @param data Text data fitting exactly into viewport
588 *
589 */
590static void draw_text_data(viewport_t *vport, keyfield_t *data)
591{
592 unsigned int i;
593
594 for (i = 0; i < vport->cols * vport->rows; i++) {
595 unsigned int col = i % vport->cols;
596 unsigned int row = i / vport->cols;
597
598 uint8_t glyph = vport->backbuf[BB_POS(vport, col, row)];
599
600 // TODO: use data[i].style
601
602 if (glyph != data[i].character) {
603 vport->backbuf[BB_POS(vport, col, row)] = data[i].character;
604 draw_glyph(vport, false, col, row);
605 }
606 }
607 cursor_show(vport);
608}
609
610
611static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
612{
613 int pm = *((int *) data);
614 pixmap_t *pmap = &pixmaps[pm];
615 unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
616
617 screen.rgb_conv(&pmap->data[pos], color);
618}
619
620
621static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
622{
623 viewport_t *vport = (viewport_t *) data;
624 unsigned int dx = vport->x + x;
625 unsigned int dy = vport->y + y;
626
627 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
628}
629
630
631/** Return first free pixmap
632 *
633 */
634static int find_free_pixmap(void)
635{
636 unsigned int i;
637
638 for (i = 0; i < MAX_PIXMAPS; i++)
639 if (!pixmaps[i].data)
640 return i;
641
642 return -1;
643}
644
645
646/** Create a new pixmap and return appropriate ID
647 *
648 */
649static int shm2pixmap(unsigned char *shm, size_t size)
650{
651 int pm;
652 pixmap_t *pmap;
653
654 pm = find_free_pixmap();
655 if (pm == -1)
656 return ELIMIT;
657
658 pmap = &pixmaps[pm];
659
660 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
661 return EINVAL;
662
663 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
664 if (!pmap->data)
665 return ENOMEM;
666
667 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
668
669 return pm;
670}
671
672
673/** Handle shared memory communication calls
674 *
675 * Protocol for drawing pixmaps:
676 * - FB_PREPARE_SHM(client shm identification)
677 * - IPC_M_AS_AREA_SEND
678 * - FB_DRAW_PPM(startx, starty)
679 * - FB_DROP_SHM
680 *
681 * Protocol for text drawing
682 * - IPC_M_AS_AREA_SEND
683 * - FB_DRAW_TEXT_DATA
684 *
685 * @param callid Callid of the current call
686 * @param call Current call data
687 * @param vp Active viewport
688 *
689 * @return false if the call was not handled byt this function, true otherwise
690 *
691 * Note: this function is not threads safe, you would have
692 * to redefine static variables with __thread
693 *
694 */
695static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
696{
697 static keyfield_t *interbuffer = NULL;
698 static size_t intersize = 0;
699
700 static unsigned char *shm = NULL;
701 static ipcarg_t shm_id = 0;
702 static size_t shm_size;
703
704 bool handled = true;
705 int retval = EOK;
706 viewport_t *vport = &viewports[vp];
707 unsigned int x;
708 unsigned int y;
709
710 switch (IPC_GET_METHOD(*call)) {
711 case IPC_M_SHARE_OUT:
712 /* We accept one area for data interchange */
713 if (IPC_GET_ARG1(*call) == shm_id) {
714 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
715 shm_size = IPC_GET_ARG2(*call);
716 if (!ipc_answer_1(callid, EOK, (sysarg_t) dest))
717 shm = dest;
718 else
719 shm_id = 0;
720
721 if (shm[0] != 'P')
722 return false;
723
724 return true;
725 } else {
726 intersize = IPC_GET_ARG2(*call);
727 receive_comm_area(callid, call, (void *) &interbuffer);
728 }
729 return true;
730 case FB_PREPARE_SHM:
731 if (shm_id)
732 retval = EBUSY;
733 else
734 shm_id = IPC_GET_ARG1(*call);
735 break;
736
737 case FB_DROP_SHM:
738 if (shm) {
739 as_area_destroy(shm);
740 shm = NULL;
741 }
742 shm_id = 0;
743 break;
744
745 case FB_SHM2PIXMAP:
746 if (!shm) {
747 retval = EINVAL;
748 break;
749 }
750 retval = shm2pixmap(shm, shm_size);
751 break;
752 case FB_DRAW_PPM:
753 if (!shm) {
754 retval = EINVAL;
755 break;
756 }
757 x = IPC_GET_ARG1(*call);
758 y = IPC_GET_ARG2(*call);
759
760 if ((x > vport->width) || (y > vport->height)) {
761 retval = EINVAL;
762 break;
763 }
764
765 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
766 IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
767 break;
768 case FB_DRAW_TEXT_DATA:
769 if (!interbuffer) {
770 retval = EINVAL;
771 break;
772 }
773 if (intersize < vport->cols * vport->rows * sizeof(*interbuffer)) {
774 retval = EINVAL;
775 break;
776 }
777 draw_text_data(vport, interbuffer);
778 break;
779 default:
780 handled = false;
781 }
782
783 if (handled)
784 ipc_answer_0(callid, retval);
785 return handled;
786}
787
788
789static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
790{
791 unsigned int width = vport->width;
792 unsigned int height = vport->height;
793
794 if (width + vport->x > screen.xres)
795 width = screen.xres - vport->x;
796 if (height + vport->y > screen.yres)
797 height = screen.yres - vport->y;
798
799 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
800 unsigned int realheight = pmap->height <= height ? pmap->height : height;
801
802 unsigned int srcrowsize = vport->width * screen.pixelbytes;
803 unsigned int realrowsize = realwidth * screen.pixelbytes;
804
805 unsigned int y;
806 for (y = 0; y < realheight; y++) {
807 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
808 memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
809 }
810}
811
812
813/** Save viewport to pixmap
814 *
815 */
816static int save_vp_to_pixmap(viewport_t *vport)
817{
818 int pm;
819 pixmap_t *pmap;
820
821 pm = find_free_pixmap();
822 if (pm == -1)
823 return ELIMIT;
824
825 pmap = &pixmaps[pm];
826 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
827 if (!pmap->data)
828 return ENOMEM;
829
830 pmap->width = vport->width;
831 pmap->height = vport->height;
832
833 copy_vp_to_pixmap(vport, pmap);
834
835 return pm;
836}
837
838
839/** Draw pixmap on screen
840 *
841 * @param vp Viewport to draw on
842 * @param pm Pixmap identifier
843 *
844 */
845static int draw_pixmap(int vp, int pm)
846{
847 pixmap_t *pmap = &pixmaps[pm];
848 viewport_t *vport = &viewports[vp];
849
850 unsigned int width = vport->width;
851 unsigned int height = vport->height;
852
853 if (width + vport->x > screen.xres)
854 width = screen.xres - vport->x;
855 if (height + vport->y > screen.yres)
856 height = screen.yres - vport->y;
857
858 if (!pmap->data)
859 return EINVAL;
860
861 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
862 unsigned int realheight = pmap->height <= height ? pmap->height : height;
863
864 unsigned int srcrowsize = vport->width * screen.pixelbytes;
865 unsigned int realrowsize = realwidth * screen.pixelbytes;
866
867 unsigned int y;
868 for (y = 0; y < realheight; y++) {
869 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
870 memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
871 }
872
873 return EOK;
874}
875
876
877/** Tick animation one step forward
878 *
879 */
880static void anims_tick(void)
881{
882 unsigned int i;
883 static int counts = 0;
884
885 /* Limit redrawing */
886 counts = (counts + 1) % 8;
887 if (counts)
888 return;
889
890 for (i = 0; i < MAX_ANIMATIONS; i++) {
891 if ((!animations[i].animlen) || (!animations[i].initialized) ||
892 (!animations[i].enabled))
893 continue;
894
895 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
896 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
897 }
898}
899
900
901static unsigned int pointer_x;
902static unsigned int pointer_y;
903static bool pointer_shown, pointer_enabled;
904static int pointer_vport = -1;
905static int pointer_pixmap = -1;
906
907
908static void mouse_show(void)
909{
910 int i, j;
911 int visibility;
912 int color;
913 int bytepos;
914
915 if ((pointer_shown) || (!pointer_enabled))
916 return;
917
918 /* Save image under the pointer. */
919 if (pointer_vport == -1) {
920 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
921 if (pointer_vport < 0)
922 return;
923 } else {
924 viewports[pointer_vport].x = pointer_x;
925 viewports[pointer_vport].y = pointer_y;
926 }
927
928 if (pointer_pixmap == -1)
929 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
930 else
931 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
932
933 /* Draw mouse pointer. */
934 for (i = 0; i < pointer_height; i++)
935 for (j = 0; j < pointer_width; j++) {
936 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
937 visibility = pointer_mask_bits[bytepos] &
938 (1 << (j % 8));
939 if (visibility) {
940 color = pointer_bits[bytepos] &
941 (1 << (j % 8)) ? 0 : 0xffffff;
942 if (pointer_x + j < screen.xres && pointer_y +
943 i < screen.yres)
944 putpixel(&viewports[0], pointer_x + j,
945 pointer_y + i, color);
946 }
947 }
948 pointer_shown = 1;
949}
950
951
952static void mouse_hide(void)
953{
954 /* Restore image under the pointer. */
955 if (pointer_shown) {
956 draw_pixmap(pointer_vport, pointer_pixmap);
957 pointer_shown = 0;
958 }
959}
960
961
962static void mouse_move(unsigned int x, unsigned int y)
963{
964 mouse_hide();
965 pointer_x = x;
966 pointer_y = y;
967 mouse_show();
968}
969
970
971static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
972{
973 bool handled = true;
974 int retval = EOK;
975 int i, nvp;
976 int newval;
977
978 switch (IPC_GET_METHOD(*call)) {
979 case FB_ANIM_CREATE:
980 nvp = IPC_GET_ARG1(*call);
981 if (nvp == -1)
982 nvp = vp;
983 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
984 !viewports[nvp].initialized) {
985 retval = EINVAL;
986 break;
987 }
988 for (i = 0; i < MAX_ANIMATIONS; i++) {
989 if (!animations[i].initialized)
990 break;
991 }
992 if (i == MAX_ANIMATIONS) {
993 retval = ELIMIT;
994 break;
995 }
996 animations[i].initialized = 1;
997 animations[i].animlen = 0;
998 animations[i].pos = 0;
999 animations[i].enabled = 0;
1000 animations[i].vp = nvp;
1001 retval = i;
1002 break;
1003 case FB_ANIM_DROP:
1004 i = IPC_GET_ARG1(*call);
1005 if (i >= MAX_ANIMATIONS || i < 0) {
1006 retval = EINVAL;
1007 break;
1008 }
1009 animations[i].initialized = 0;
1010 break;
1011 case FB_ANIM_ADDPIXMAP:
1012 i = IPC_GET_ARG1(*call);
1013 if (i >= MAX_ANIMATIONS || i < 0 ||
1014 !animations[i].initialized) {
1015 retval = EINVAL;
1016 break;
1017 }
1018 if (animations[i].animlen == MAX_ANIM_LEN) {
1019 retval = ELIMIT;
1020 break;
1021 }
1022 newval = IPC_GET_ARG2(*call);
1023 if (newval < 0 || newval > MAX_PIXMAPS ||
1024 !pixmaps[newval].data) {
1025 retval = EINVAL;
1026 break;
1027 }
1028 animations[i].pixmaps[animations[i].animlen++] = newval;
1029 break;
1030 case FB_ANIM_CHGVP:
1031 i = IPC_GET_ARG1(*call);
1032 if (i >= MAX_ANIMATIONS || i < 0) {
1033 retval = EINVAL;
1034 break;
1035 }
1036 nvp = IPC_GET_ARG2(*call);
1037 if (nvp == -1)
1038 nvp = vp;
1039 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1040 !viewports[nvp].initialized) {
1041 retval = EINVAL;
1042 break;
1043 }
1044 animations[i].vp = nvp;
1045 break;
1046 case FB_ANIM_START:
1047 case FB_ANIM_STOP:
1048 i = IPC_GET_ARG1(*call);
1049 if (i >= MAX_ANIMATIONS || i < 0) {
1050 retval = EINVAL;
1051 break;
1052 }
1053 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
1054 if (newval ^ animations[i].enabled) {
1055 animations[i].enabled = newval;
1056 anims_enabled += newval ? 1 : -1;
1057 }
1058 break;
1059 default:
1060 handled = 0;
1061 }
1062 if (handled)
1063 ipc_answer_0(callid, retval);
1064 return handled;
1065}
1066
1067
1068/** Handler for messages concerning pixmap handling
1069 *
1070 */
1071static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1072{
1073 bool handled = true;
1074 int retval = EOK;
1075 int i, nvp;
1076
1077 switch (IPC_GET_METHOD(*call)) {
1078 case FB_VP_DRAW_PIXMAP:
1079 nvp = IPC_GET_ARG1(*call);
1080 if (nvp == -1)
1081 nvp = vp;
1082 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1083 !viewports[nvp].initialized) {
1084 retval = EINVAL;
1085 break;
1086 }
1087 i = IPC_GET_ARG2(*call);
1088 retval = draw_pixmap(nvp, i);
1089 break;
1090 case FB_VP2PIXMAP:
1091 nvp = IPC_GET_ARG1(*call);
1092 if (nvp == -1)
1093 nvp = vp;
1094 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1095 !viewports[nvp].initialized)
1096 retval = EINVAL;
1097 else
1098 retval = save_vp_to_pixmap(&viewports[nvp]);
1099 break;
1100 case FB_DROP_PIXMAP:
1101 i = IPC_GET_ARG1(*call);
1102 if (i >= MAX_PIXMAPS) {
1103 retval = EINVAL;
1104 break;
1105 }
1106 if (pixmaps[i].data) {
1107 free(pixmaps[i].data);
1108 pixmaps[i].data = NULL;
1109 }
1110 break;
1111 default:
1112 handled = 0;
1113 }
1114
1115 if (handled)
1116 ipc_answer_0(callid, retval);
1117 return handled;
1118
1119}
1120
1121/** Function for handling connections to FB
1122 *
1123 */
1124static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1125{
1126 unsigned int vp = 0;
1127 viewport_t *vport = &viewports[vp];
1128
1129 if (client_connected) {
1130 ipc_answer_0(iid, ELIMIT);
1131 return;
1132 }
1133
1134 /* Accept connection */
1135 client_connected = true;
1136 ipc_answer_0(iid, EOK);
1137
1138 while (true) {
1139 ipc_callid_t callid;
1140 ipc_call_t call;
1141 int retval;
1142 unsigned int i;
1143 int scroll;
1144 uint8_t glyph;
1145 unsigned int row, col;
1146
1147 if ((vport->cursor_active) || (anims_enabled))
1148 callid = async_get_call_timeout(&call, 250000);
1149 else
1150 callid = async_get_call(&call);
1151
1152 mouse_hide();
1153 if (!callid) {
1154 cursor_blink(vport);
1155 anims_tick();
1156 mouse_show();
1157 continue;
1158 }
1159
1160 if (shm_handle(callid, &call, vp))
1161 continue;
1162
1163 if (pixmap_handle(callid, &call, vp))
1164 continue;
1165
1166 if (anim_handle(callid, &call, vp))
1167 continue;
1168
1169 switch (IPC_GET_METHOD(call)) {
1170 case IPC_M_PHONE_HUNGUP:
1171 client_connected = false;
1172
1173 /* Cleanup other viewports */
1174 for (i = 1; i < MAX_VIEWPORTS; i++)
1175 vport->initialized = false;
1176
1177 /* Exit thread */
1178 return;
1179
1180 case FB_PUTCHAR:
1181 glyph = IPC_GET_ARG1(call);
1182 row = IPC_GET_ARG2(call);
1183 col = IPC_GET_ARG3(call);
1184
1185 if ((col >= vport->cols) || (row >= vport->rows)) {
1186 retval = EINVAL;
1187 break;
1188 }
1189 ipc_answer_0(callid, EOK);
1190
1191 draw_char(vport, glyph, col, row);
1192
1193 /* Message already answered */
1194 continue;
1195 case FB_CLEAR:
1196 vport_clear(vport);
1197 cursor_show(vport);
1198 retval = EOK;
1199 break;
1200 case FB_CURSOR_GOTO:
1201 row = IPC_GET_ARG1(call);
1202 col = IPC_GET_ARG2(call);
1203
1204 if ((col >= vport->cols) || (row >= vport->rows)) {
1205 retval = EINVAL;
1206 break;
1207 }
1208 retval = EOK;
1209
1210 cursor_hide(vport);
1211 vport->cur_col = col;
1212 vport->cur_row = row;
1213 cursor_show(vport);
1214 break;
1215 case FB_CURSOR_VISIBILITY:
1216 cursor_hide(vport);
1217 vport->cursor_active = IPC_GET_ARG1(call);
1218 cursor_show(vport);
1219 retval = EOK;
1220 break;
1221 case FB_GET_CSIZE:
1222 ipc_answer_2(callid, EOK, vport->rows, vport->cols);
1223 continue;
1224 case FB_SCROLL:
1225 scroll = IPC_GET_ARG1(call);
1226 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
1227 retval = EINVAL;
1228 break;
1229 }
1230 cursor_hide(vport);
1231 vport_scroll(vport, scroll);
1232 cursor_show(vport);
1233 retval = EOK;
1234 break;
1235 case FB_VIEWPORT_SWITCH:
1236 i = IPC_GET_ARG1(call);
1237 if (i >= MAX_VIEWPORTS) {
1238 retval = EINVAL;
1239 break;
1240 }
1241 if (!viewports[i].initialized) {
1242 retval = EADDRNOTAVAIL;
1243 break;
1244 }
1245 cursor_hide(vport);
1246 vp = i;
1247 vport = &viewports[vp];
1248 cursor_show(vport);
1249 retval = EOK;
1250 break;
1251 case FB_VIEWPORT_CREATE:
1252 retval = vport_create(IPC_GET_ARG1(call) >> 16,
1253 IPC_GET_ARG1(call) & 0xffff,
1254 IPC_GET_ARG2(call) >> 16,
1255 IPC_GET_ARG2(call) & 0xffff);
1256 break;
1257 case FB_VIEWPORT_DELETE:
1258 i = IPC_GET_ARG1(call);
1259 if (i >= MAX_VIEWPORTS) {
1260 retval = EINVAL;
1261 break;
1262 }
1263 if (!viewports[i].initialized) {
1264 retval = EADDRNOTAVAIL;
1265 break;
1266 }
1267 viewports[i].initialized = false;
1268 if (viewports[i].glyphs)
1269 free(viewports[i].glyphs);
1270 if (viewports[i].bgpixel)
1271 free(viewports[i].bgpixel);
1272 if (viewports[i].backbuf)
1273 free(viewports[i].backbuf);
1274 retval = EOK;
1275 break;
1276 case FB_SET_STYLE:
1277 vport->style.fg_color = IPC_GET_ARG1(call);
1278 vport->style.bg_color = IPC_GET_ARG2(call);
1279 render_glyphs(vport);
1280 retval = EOK;
1281 break;
1282 case FB_GET_RESOLUTION:
1283 ipc_answer_2(callid, EOK, screen.xres, screen.yres);
1284 continue;
1285 case FB_POINTER_MOVE:
1286 pointer_enabled = true;
1287 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1288 retval = EOK;
1289 break;
1290 default:
1291 retval = ENOENT;
1292 }
1293 ipc_answer_0(callid, retval);
1294 }
1295}
1296
1297/** Initialization of framebuffer
1298 *
1299 */
1300int fb_init(void)
1301{
1302 async_set_client_connection(fb_client_connection);
1303
1304 void *fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1305 unsigned int fb_offset = sysinfo_value("fb.offset");
1306 unsigned int fb_width = sysinfo_value("fb.width");
1307 unsigned int fb_height = sysinfo_value("fb.height");
1308 unsigned int fb_scanline = sysinfo_value("fb.scanline");
1309 unsigned int fb_visual = sysinfo_value("fb.visual");
1310
1311 unsigned int fbsize = fb_scanline * fb_height;
1312 void *fb_addr = as_get_mappable_page(fbsize);
1313
1314 physmem_map(fb_ph_addr + fb_offset, fb_addr,
1315 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
1316
1317 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
1318 return 0;
1319
1320 return -1;
1321}
1322
1323/**
1324 * @}
1325 */
Note: See TracBrowser for help on using the repository browser.