source: mainline/uspace/srv/fb/fb.c@ 8c6337d

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

Revert c3724 as it actually made scrolling slower on some arches.

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