source: mainline/uspace/srv/fb/fb.c@ 36251c6

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

Fix overeager optimization causing VC numbers not to be redrawn.

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