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

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

When scrolling viewport, do not redraw glyphs. Instead use a (not very smart) blit.

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