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

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

Slightly faster draw_fill_rect() (although 2x VRAM access).

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