source: mainline/uspace/srv/fb/fb.c@ 4f46695e

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

Use better method names.

  • Property mode set to 100644
File size: 40.6 KB
RevLine 
[afa6e74]1/*
[76fca31]2 * Copyright (c) 2008 Martin Decky
[df4ed85]3 * Copyright (c) 2006 Jakub Vana
4 * Copyright (c) 2006 Ondrej Palkovsky
[afa6e74]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
[231a60a]31/**
32 * @defgroup fb Graphical framebuffer
[ab1861a]33 * @brief HelenOS graphical framebuffer.
[ce5bcb4]34 * @ingroup fbs
35 * @{
[76fca31]36 */
[06e1e95]37
[ce5bcb4]38/** @file
39 */
40
[afa6e74]41#include <stdlib.h>
[7f5b37a]42#include <unistd.h>
43#include <string.h>
[afa6e74]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>
[7f5b37a]51#include <ipc/services.h>
[afa6e74]52#include <kernel/errno.h>
[2bc137c2]53#include <kernel/genarch/fb/visuals.h>
[9805cde]54#include <console/color.h>
55#include <console/style.h>
[80649a91]56#include <async.h>
[2bc137c2]57#include <bool.h>
[83b1d61]58
[a2cd194]59#include "font-8x16.h"
[afa6e74]60#include "fb.h"
[83b1d61]61#include "main.h"
62#include "../console/screenbuffer.h"
[90f5d64]63#include "ppm.h"
[afa6e74]64
[2ce520c]65#include "pointer.xbm"
66#include "pointer_mask.xbm"
67
[76fca31]68#define DEFAULT_BGCOLOR 0xf0f0f0
69#define DEFAULT_FGCOLOR 0x000000
[afa6e74]70
[ab1861a]71#define GLYPH_UNAVAIL '?'
[171f9a1]72
[76fca31]73#define MAX_ANIM_LEN 8
74#define MAX_ANIMATIONS 4
75#define MAX_PIXMAPS 256 /**< Maximum number of saved pixmaps */
76#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
[afa6e74]77
[68a4442]78/** Function to render a pixel from a RGB value. */
[76fca31]79typedef void (*rgb_conv_t)(void *, uint32_t);
[afa6e74]80
[ab1861a]81/** Function to render a bit mask. */
82typedef void (*mask_conv_t)(void *, bool);
83
[68a4442]84/** Function to draw a glyph. */
85typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
[171f9a1]86 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]87
[a2ae4f4]88struct {
[76fca31]89 uint8_t *fb_addr;
90
[253f35a1]91 unsigned int xres;
92 unsigned int yres;
[76fca31]93
[253f35a1]94 unsigned int scanline;
[76fca31]95 unsigned int glyphscanline;
96
[253f35a1]97 unsigned int pixelbytes;
[76fca31]98 unsigned int glyphbytes;
[ab1861a]99
[4527fb5]100 /** Pre-rendered mask for rendering glyphs. Specific for the visual. */
101 uint8_t *glyphs;
[76fca31]102
103 rgb_conv_t rgb_conv;
[ab1861a]104 mask_conv_t mask_conv;
[a2ae4f4]105} screen;
[afa6e74]106
[9805cde]107/** Backbuffer character cell. */
108typedef struct {
[7ce3cb2]109 uint32_t glyph;
[9805cde]110 uint32_t fg_color;
111 uint32_t bg_color;
112} bb_cell_t;
113
[a2ae4f4]114typedef struct {
[76fca31]115 bool initialized;
116 unsigned int x;
117 unsigned int y;
118 unsigned int width;
119 unsigned int height;
120
[a2ae4f4]121 /* Text support in window */
[76fca31]122 unsigned int cols;
123 unsigned int rows;
124
[68a4442]125 /*
126 * Style and glyphs for text printing
127 */
[ab1861a]128
[9805cde]129 /** Current attributes. */
130 attr_rgb_t attr;
[ab1861a]131
[76fca31]132 uint8_t *bgpixel;
[ab1861a]133
[4527fb5]134 /**
135 * Glyph drawing function for this viewport. Different viewports
136 * might use different drawing functions depending on whether their
137 * scanlines are aligned on a word boundary.
138 */
[68a4442]139 dg_t dglyph;
[76fca31]140
[a2ae4f4]141 /* Auto-cursor position */
[76fca31]142 bool cursor_active;
143 unsigned int cur_col;
144 unsigned int cur_row;
145 bool cursor_shown;
146
147 /* Back buffer */
[9805cde]148 bb_cell_t *backbuf;
[76fca31]149 unsigned int bbsize;
[a2ae4f4]150} viewport_t;
151
[1fd7700]152typedef struct {
[76fca31]153 bool initialized;
154 bool enabled;
[1fd7700]155 unsigned int vp;
[76fca31]156
[1fd7700]157 unsigned int pos;
158 unsigned int animlen;
159 unsigned int pixmaps[MAX_ANIM_LEN];
160} animation_t;
[76fca31]161
[1fd7700]162static animation_t animations[MAX_ANIMATIONS];
[76fca31]163static bool anims_enabled;
[1fd7700]164
[429acb9]165typedef struct {
166 unsigned int width;
167 unsigned int height;
[afbe96a]168 uint8_t *data;
[429acb9]169} pixmap_t;
170
[76fca31]171static pixmap_t pixmaps[MAX_PIXMAPS];
[a2ae4f4]172static viewport_t viewports[128];
173
[76fca31]174static bool client_connected = false; /**< Allow only 1 connection */
[afa6e74]175
[9805cde]176static uint32_t color_table[16] = {
[ab1861a]177 [COLOR_BLACK] = 0x000000,
178 [COLOR_BLUE] = 0x0000f0,
179 [COLOR_GREEN] = 0x00f000,
180 [COLOR_CYAN] = 0x00f0f0,
181 [COLOR_RED] = 0xf00000,
182 [COLOR_MAGENTA] = 0xf000f0,
183 [COLOR_YELLOW] = 0xf0f000,
184 [COLOR_WHITE] = 0xf0f0f0,
185
186 [8 + COLOR_BLACK] = 0x000000,
187 [8 + COLOR_BLUE] = 0x0000ff,
188 [8 + COLOR_GREEN] = 0x00ff00,
189 [8 + COLOR_CYAN] = 0x00ffff,
190 [8 + COLOR_RED] = 0xff0000,
191 [8 + COLOR_MAGENTA] = 0xff00ff,
192 [8 + COLOR_YELLOW] = 0xffff00,
193 [8 + COLOR_WHITE] = 0xffffff,
[9805cde]194};
195
[4a62ec9]196static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
[9805cde]197static int rgb_from_style(attr_rgb_t *rgb, int style);
198static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
199 ipcarg_t bg_color, ipcarg_t flags);
200
201static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
202 ipcarg_t bg_color, ipcarg_t attr);
203
[68a4442]204static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]205 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]206static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]207 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
[68a4442]208
[67c6c651]209static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
[2d32081]210 unsigned int row);
211
212
[76fca31]213#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
214#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
215#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
[afa6e74]216
[76fca31]217#define COL2X(col) ((col) * FONT_WIDTH)
218#define ROW2Y(row) ((row) * FONT_SCANLINES)
[afa6e74]219
[76fca31]220#define X2COL(x) ((x) / FONT_WIDTH)
221#define Y2ROW(y) ((y) / FONT_SCANLINES)
[afa6e74]222
[76fca31]223#define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
224#define BB_POS(vport, col, row) ((row) * vport->cols + (col))
225#define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
[253f35a1]226
[afa6e74]227
[76fca31]228/** ARGB 8:8:8:8 conversion
229 *
230 */
231static void rgb_0888(void *dst, uint32_t rgb)
[afa6e74]232{
[ab1861a]233 *((uint32_t *) dst) = rgb & 0x00ffffff;
234}
235
236static void mask_0888(void *dst, bool mask)
237{
238 *((uint32_t *) dst) = (mask ? 0x00ffffff : 0);
[afa6e74]239}
240
[ccb0cbc]241
[76fca31]242/** ABGR 8:8:8:8 conversion
243 *
244 */
245static void bgr_0888(void *dst, uint32_t rgb)
[ccb0cbc]246{
[76fca31]247 *((uint32_t *) dst)
248 = (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | RED(rgb, 8);
[ccb0cbc]249}
250
[76fca31]251
[fcd7053]252/** RGB 8:8:8 conversion
[76fca31]253 *
254 */
255static void rgb_888(void *dst, uint32_t rgb)
[afa6e74]256{
[6e71a9d8]257 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
258 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
259 ((uint8_t *) dst)[2] = RED(rgb, 8);
[fcd7053]260}
261
[ab1861a]262static void mask_888(void *dst, bool mask)
263{
264 if (mask) {
265 ((uint8_t *) dst)[0] = 0xff;
266 ((uint8_t *) dst)[1] = 0xff;
267 ((uint8_t *) dst)[2] = 0xff;
268 } else {
269 ((uint8_t *) dst)[0] = 0;
270 ((uint8_t *) dst)[1] = 0;
271 ((uint8_t *) dst)[2] = 0;
272 }
273}
274
[fcd7053]275
276/** BGR 8:8:8 conversion
277 *
278 */
279static void bgr_888(void *dst, uint32_t rgb)
280{
281 ((uint8_t *) dst)[0] = RED(rgb, 8);
282 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
283 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
[afa6e74]284}
285
286
[76fca31]287/** RGB 5:5:5 conversion
288 *
289 */
290static void rgb_555(void *dst, uint32_t rgb)
[2bc137c2]291{
[76fca31]292 *((uint16_t *) dst)
293 = (RED(rgb, 5) << 10) | (GREEN(rgb, 5) << 5) | BLUE(rgb, 5);
[2bc137c2]294}
295
[ab1861a]296static void mask_555(void *dst, bool mask)
297{
298 *((uint16_t *) dst) = (mask ? 0x7fff : 0);
299}
300
[2bc137c2]301
[76fca31]302/** RGB 5:6:5 conversion
303 *
304 */
305static void rgb_565(void *dst, uint32_t rgb)
[afa6e74]306{
[76fca31]307 *((uint16_t *) dst)
308 = (RED(rgb, 5) << 11) | (GREEN(rgb, 6) << 5) | BLUE(rgb, 5);
[afa6e74]309}
310
[ab1861a]311static void mask_565(void *dst, bool mask)
312{
313 *((uint16_t *) dst) = (mask ? 0xffff : 0);
314}
315
[afa6e74]316
[76fca31]317/** RGB 3:2:3
318 *
319 */
320static void rgb_323(void *dst, uint32_t rgb)
[afa6e74]321{
[76fca31]322 *((uint8_t *) dst)
323 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
[afa6e74]324}
325
[ab1861a]326static void mask_323(void *dst, bool mask)
327{
328 *((uint8_t *) dst) = (mask ? 0xff : 0);
329}
330
[d410328]331/** Draw a filled rectangle.
332 *
333 * @note Need real implementation that does not access VRAM twice.
[ab1861a]334 *
[d410328]335 */
[2d32081]336static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
337 unsigned int y1, uint32_t color)
338{
[ab1861a]339 unsigned int x;
340 unsigned int y;
[d410328]341 unsigned int copy_bytes;
[ab1861a]342
343 uint8_t *sp;
344 uint8_t *dp;
[2d32081]345 uint8_t cbuf[4];
[ab1861a]346
347 if ((y0 >= y1) || (x0 >= x1))
348 return;
349
[2d32081]350 screen.rgb_conv(cbuf, color);
[ab1861a]351
[d410328]352 sp = &screen.fb_addr[FB_POS(x0, y0)];
353 dp = sp;
[ab1861a]354
[d410328]355 /* Draw the first line. */
356 for (x = x0; x < x1; x++) {
357 memcpy(dp, cbuf, screen.pixelbytes);
358 dp += screen.pixelbytes;
359 }
[ab1861a]360
[d410328]361 dp = sp + screen.scanline;
362 copy_bytes = (x1 - x0) * screen.pixelbytes;
[ab1861a]363
[d410328]364 /* Draw the remaining lines by copying. */
365 for (y = y0 + 1; y < y1; y++) {
366 memcpy(dp, sp, copy_bytes);
367 dp += screen.scanline;
[2d32081]368 }
369}
[afa6e74]370
[2d32081]371/** Redraw viewport.
[76fca31]372 *
373 * @param vport Viewport to redraw
[1180a88e]374 *
375 */
[76fca31]376static void vport_redraw(viewport_t *vport)
[a2ae4f4]377{
[ab1861a]378 unsigned int row;
379 unsigned int col;
380
[76fca31]381 for (row = 0; row < vport->rows; row++) {
[2d32081]382 for (col = 0; col < vport->cols; col++) {
[67c6c651]383 draw_vp_glyph(vport, false, col, row);
[76fca31]384 }
[e92aabf]385 }
[ab1861a]386
[76fca31]387 if (COL2X(vport->cols) < vport->width) {
[2d32081]388 draw_filled_rect(
389 vport->x + COL2X(vport->cols), vport->y,
390 vport->x + vport->width, vport->y + vport->height,
[9805cde]391 vport->attr.bg_color);
[e92aabf]392 }
[ab1861a]393
[76fca31]394 if (ROW2Y(vport->rows) < vport->height) {
[2d32081]395 draw_filled_rect(
396 vport->x, vport->y + ROW2Y(vport->rows),
397 vport->x + vport->width, vport->y + vport->height,
[9805cde]398 vport->attr.bg_color);
[e92aabf]399 }
[67ec84b]400}
401
[9805cde]402static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
403 uint32_t bg_color)
404{
[ab1861a]405 size_t i;
406
[9805cde]407 for (i = 0; i < len; i++) {
408 backbuf[i].glyph = 0;
409 backbuf[i].fg_color = fg_color;
410 backbuf[i].bg_color = bg_color;
411 }
412}
[afa6e74]413
[a728ed3]414/** Clear viewport.
[76fca31]415 *
416 * @param vport Viewport to clear
[a2ae4f4]417 *
418 */
[76fca31]419static void vport_clear(viewport_t *vport)
[afa6e74]420{
[9805cde]421 backbuf_clear(vport->backbuf, vport->cols * vport->rows,
422 vport->attr.fg_color, vport->attr.bg_color);
[76fca31]423 vport_redraw(vport);
[e92aabf]424}
425
[a728ed3]426/** Scroll viewport by the specified number of lines.
[76fca31]427 *
428 * @param vport Viewport to scroll
429 * @param lines Number of lines to scroll
430 *
431 */
432static void vport_scroll(viewport_t *vport, int lines)
[e92aabf]433{
[ab1861a]434 unsigned int row;
435 unsigned int col;
436 unsigned int x;
437 unsigned int y;
[67ebf21]438 uint32_t glyph;
[9805cde]439 uint32_t fg_color;
440 uint32_t bg_color;
[ab1861a]441 bb_cell_t *bbp;
442 bb_cell_t *xbp;
443
[67c6c651]444 /*
445 * Redraw.
446 */
[ab1861a]447
[67c6c651]448 y = vport->y;
449 for (row = 0; row < vport->rows; row++) {
450 x = vport->x;
451 for (col = 0; col < vport->cols; col++) {
452 if ((row + lines >= 0) && (row + lines < vport->rows)) {
[9805cde]453 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
454 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[ab1861a]455
[9805cde]456 glyph = xbp->glyph;
457 fg_color = xbp->fg_color;
458 bg_color = xbp->bg_color;
[ab1861a]459
460 if ((bbp->glyph == glyph)
461 && (bbp->fg_color == xbp->fg_color)
462 && (bbp->bg_color == xbp->bg_color)) {
[67c6c651]463 x += FONT_WIDTH;
464 continue;
465 }
466 } else {
467 glyph = 0;
[9805cde]468 fg_color = vport->attr.fg_color;
469 bg_color = vport->attr.bg_color;
[67c6c651]470 }
[ab1861a]471
[4527fb5]472 (*vport->dglyph)(x, y, false, screen.glyphs, glyph,
[9805cde]473 fg_color, bg_color);
[67c6c651]474 x += FONT_WIDTH;
475 }
476 y += FONT_SCANLINES;
477 }
[ab1861a]478
[a728ed3]479 /*
480 * Scroll backbuffer.
481 */
[ab1861a]482
[76fca31]483 if (lines > 0) {
[67c6c651]484 memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
[9805cde]485 vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
486 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
487 vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
[76fca31]488 } else {
[67c6c651]489 memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
[9805cde]490 vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
491 backbuf_clear(vport->backbuf, - vport->cols * lines,
492 vport->attr.fg_color, vport->attr.bg_color);
[76fca31]493 }
[2d32081]494}
[afa6e74]495
[76fca31]496/** Render glyphs
497 *
498 * Convert glyphs from device independent font
499 * description to current visual representation.
[ab1861a]500 *
[d530237a]501 */
[4527fb5]502static void render_glyphs(void)
[afa6e74]503{
[76fca31]504 unsigned int glyph;
[ab1861a]505
[76fca31]506 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
507 unsigned int y;
[ab1861a]508
[76fca31]509 for (y = 0; y < FONT_SCANLINES; y++) {
510 unsigned int x;
[ab1861a]511
[76fca31]512 for (x = 0; x < FONT_WIDTH; x++) {
[ab1861a]513 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
[3c101bd4]514 (fb_font[glyph][y] & (1 << (7 - x))) ? true : false);
[ab1861a]515
516 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
[3c101bd4]517 (fb_font[glyph][y] & (1 << (7 - x))) ? false : true);
[76fca31]518 }
[6b5111a]519 }
520 }
[afa6e74]521}
522
[a2ae4f4]523/** Create new viewport
[afa6e74]524 *
[76fca31]525 * @param x Origin of the viewport (x).
526 * @param y Origin of the viewport (y).
527 * @param width Width of the viewport.
528 * @param height Height of the viewport.
529 *
530 * @return New viewport number.
531 *
[afa6e74]532 */
[76fca31]533static int vport_create(unsigned int x, unsigned int y,
534 unsigned int width, unsigned int height)
[afa6e74]535{
[76fca31]536 unsigned int i;
537
[d7baee6]538 for (i = 0; i < MAX_VIEWPORTS; i++) {
[a2ae4f4]539 if (!viewports[i].initialized)
[afa6e74]540 break;
541 }
[ab1861a]542
[a2ae4f4]543 if (i == MAX_VIEWPORTS)
544 return ELIMIT;
[76fca31]545
546 unsigned int cols = width / FONT_WIDTH;
547 unsigned int rows = height / FONT_SCANLINES;
[9805cde]548 unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
[68a4442]549 unsigned int word_size = sizeof(unsigned long);
[76fca31]550
[9805cde]551 bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
[76fca31]552 if (!backbuf)
553 return ENOMEM;
554
555 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
556 if (!bgpixel) {
557 free(backbuf);
558 return ENOMEM;
559 }
[ab1861a]560
[9805cde]561 backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
[76fca31]562 memset(bgpixel, 0, screen.pixelbytes);
563
[a2ae4f4]564 viewports[i].x = x;
565 viewports[i].y = y;
566 viewports[i].width = width;
567 viewports[i].height = height;
[afa6e74]568
[76fca31]569 viewports[i].cols = cols;
570 viewports[i].rows = rows;
571
[9805cde]572 viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
573 viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
[afa6e74]574
[76fca31]575 viewports[i].bgpixel = bgpixel;
[ab1861a]576
[68a4442]577 /*
[ab1861a]578 * Conditions necessary to select aligned version:
579 * - word size is divisible by pixelbytes
580 * - cell scanline size is divisible by word size
581 * - cell scanlines are word-aligned
[68a4442]582 *
583 */
[ab1861a]584 if (((word_size % screen.pixelbytes) == 0)
585 && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)
586 && ((x * screen.pixelbytes) % word_size == 0)
587 && (screen.scanline % word_size == 0)) {
[68a4442]588 viewports[i].dglyph = draw_glyph_aligned;
589 } else {
590 viewports[i].dglyph = draw_glyph_fallback;
591 }
[ab1861a]592
[c1d2c9d]593 viewports[i].cur_col = 0;
594 viewports[i].cur_row = 0;
[76fca31]595 viewports[i].cursor_active = false;
596 viewports[i].cursor_shown = false;
597
598 viewports[i].bbsize = bbsize;
599 viewports[i].backbuf = backbuf;
600
601 viewports[i].initialized = true;
602
[4527fb5]603 screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);
[76fca31]604
[a2ae4f4]605 return i;
[afa6e74]606}
607
[76fca31]608
[afa6e74]609/** Initialize framebuffer as a chardev output device
610 *
[76fca31]611 * @param addr Address of the framebuffer
612 * @param xres Screen width in pixels
613 * @param yres Screen height in pixels
614 * @param visual Bits per pixel (8, 16, 24, 32)
615 * @param scan Bytes per one scanline
[afa6e74]616 *
617 */
[76fca31]618static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
619 unsigned int scan, unsigned int visual)
[afa6e74]620{
[ab1861a]621
622
[2bc137c2]623 switch (visual) {
624 case VISUAL_INDIRECT_8:
[76fca31]625 screen.rgb_conv = rgb_323;
[ab1861a]626 screen.mask_conv = mask_323;
[775df25]627 screen.pixelbytes = 1;
628 break;
[2bc137c2]629 case VISUAL_RGB_5_5_5:
[76fca31]630 screen.rgb_conv = rgb_555;
[ab1861a]631 screen.mask_conv = mask_555;
[775df25]632 screen.pixelbytes = 2;
633 break;
[2bc137c2]634 case VISUAL_RGB_5_6_5:
[76fca31]635 screen.rgb_conv = rgb_565;
[ab1861a]636 screen.mask_conv = mask_565;
[2bc137c2]637 screen.pixelbytes = 2;
[775df25]638 break;
[2bc137c2]639 case VISUAL_RGB_8_8_8:
[76fca31]640 screen.rgb_conv = rgb_888;
[ab1861a]641 screen.mask_conv = mask_888;
[2bc137c2]642 screen.pixelbytes = 3;
643 break;
[fcd7053]644 case VISUAL_BGR_8_8_8:
645 screen.rgb_conv = bgr_888;
[ab1861a]646 screen.mask_conv = mask_888;
[fcd7053]647 screen.pixelbytes = 3;
648 break;
[2bc137c2]649 case VISUAL_RGB_8_8_8_0:
[76fca31]650 screen.rgb_conv = rgb_888;
[ab1861a]651 screen.mask_conv = mask_888;
[2bc137c2]652 screen.pixelbytes = 4;
653 break;
654 case VISUAL_RGB_0_8_8_8:
[76fca31]655 screen.rgb_conv = rgb_0888;
[ab1861a]656 screen.mask_conv = mask_0888;
[775df25]657 screen.pixelbytes = 4;
658 break;
[ccb0cbc]659 case VISUAL_BGR_0_8_8_8:
[76fca31]660 screen.rgb_conv = bgr_0888;
[ab1861a]661 screen.mask_conv = mask_0888;
[ccb0cbc]662 screen.pixelbytes = 4;
663 break;
[2bc137c2]664 default:
665 return false;
[afa6e74]666 }
[ab1861a]667
[76fca31]668 screen.fb_addr = (unsigned char *) addr;
[a2ae4f4]669 screen.xres = xres;
670 screen.yres = yres;
671 screen.scanline = scan;
[76fca31]672
673 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
674 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
[ab1861a]675
676 size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
677 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
[4527fb5]678 if (!glyphs)
679 return false;
680
681 memset(glyphs, 0, glyphsize);
682 screen.glyphs = glyphs;
[ab1861a]683
[4527fb5]684 render_glyphs();
[afa6e74]685
[a2ae4f4]686 /* Create first viewport */
[76fca31]687 vport_create(0, 0, xres, yres);
[2bc137c2]688
689 return true;
[afa6e74]690}
691
[76fca31]692
[68a4442]693/** Draw a glyph, takes advantage of alignment.
[67c6c651]694 *
[68a4442]695 * This version can only be used if the following conditions are met:
696 *
697 * - word size is divisible by pixelbytes
698 * - cell scanline size is divisible by word size
699 * - cell scanlines are word-aligned
[67c6c651]700 *
[68a4442]701 * It makes use of the pre-rendered mask to process (possibly) several
702 * pixels at once (word size / pixelbytes pixels at a time are processed)
703 * making it very fast. Most notably this version is not applicable at 24 bits
704 * per pixel.
705 *
[ab1861a]706 * @param x x coordinate of top-left corner on screen.
707 * @param y y coordinate of top-left corner on screen.
708 * @param cursor Draw glyph with cursor
709 * @param glyphs Pointer to font bitmap.
710 * @param glyph Code of the glyph to draw.
711 * @param fg_color Foreground color.
712 * @param bg_color Backgroudn color.
713 *
[67c6c651]714 */
[68a4442]715static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]716 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
[67c6c651]717{
[ab1861a]718 unsigned int i;
719 unsigned int yd;
720 unsigned long fg_buf;
721 unsigned long bg_buf;
[68a4442]722 unsigned long mask;
[ab1861a]723
[68a4442]724 /*
725 * Prepare a pair of words, one filled with foreground-color
726 * pattern and the other filled with background-color pattern.
727 */
728 for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
[ab1861a]729 screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],
[68a4442]730 fg_color);
[ab1861a]731 screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],
[68a4442]732 bg_color);
733 }
[ab1861a]734
[68a4442]735 /* Pointer to the current position in the mask. */
[ab1861a]736 unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
737
[68a4442]738 /* Pointer to the current position on the screen. */
[ab1861a]739 unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
740
[68a4442]741 /* Width of the character cell in words. */
[ab1861a]742 unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
743
[68a4442]744 /* Offset to add when moving to another screen scanline. */
[ab1861a]745 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
746
[68a4442]747 for (yd = 0; yd < FONT_SCANLINES; yd++) {
748 /*
749 * Now process the cell scanline, combining foreground
750 * and background color patters using the pre-rendered mask.
751 */
752 for (i = 0; i < ww; i++) {
753 mask = *maskp++;
754 *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
755 }
[ab1861a]756
[68a4442]757 /* Move to the beginning of the next scanline of the cell. */
758 dp = (unsigned long *) ((uint8_t *) dp + d_add);
759 }
760}
761
762/** Draw a glyph, fallback version.
763 *
764 * This version does not make use of the pre-rendered mask, it uses
765 * the font bitmap directly. It works always, but it is slower.
766 *
[ab1861a]767 * @param x x coordinate of top-left corner on screen.
768 * @param y y coordinate of top-left corner on screen.
769 * @param cursor Draw glyph with cursor
770 * @param glyphs Pointer to font bitmap.
771 * @param glyph Code of the glyph to draw.
772 * @param fg_color Foreground color.
773 * @param bg_color Backgroudn color.
774 *
[68a4442]775 */
776void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
[7ce3cb2]777 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
[68a4442]778{
[ab1861a]779 unsigned int i;
780 unsigned int j;
781 unsigned int yd;
782 uint8_t fg_buf[4];
783 uint8_t bg_buf[4];
784 uint8_t *sp;
[68a4442]785 uint8_t b;
[ab1861a]786
[68a4442]787 /* Pre-render 1x the foreground and background color pixels. */
788 if (cursor) {
789 screen.rgb_conv(fg_buf, bg_color);
790 screen.rgb_conv(bg_buf, fg_color);
791 } else {
792 screen.rgb_conv(fg_buf, fg_color);
793 screen.rgb_conv(bg_buf, bg_color);
794 }
[ab1861a]795
[68a4442]796 /* Pointer to the current position on the screen. */
[ab1861a]797 uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
798
[68a4442]799 /* Offset to add when moving to another screen scanline. */
[ab1861a]800 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
801
[68a4442]802 for (yd = 0; yd < FONT_SCANLINES; yd++) {
803 /* Byte containing bits of the glyph scanline. */
[67ebf21]804 b = fb_font[glyph][yd];
[ab1861a]805
[68a4442]806 for (i = 0; i < FONT_WIDTH; i++) {
807 /* Choose color based on the current bit. */
808 sp = (b & 0x80) ? fg_buf : bg_buf;
[ab1861a]809
[68a4442]810 /* Copy the pixel. */
811 for (j = 0; j < screen.pixelbytes; j++) {
812 *dp++ = *sp++;
813 }
[ab1861a]814
[68a4442]815 /* Move to the next bit. */
816 b = b << 1;
817 }
818
819 /* Move to the beginning of the next scanline of the cell. */
820 dp += d_add;
821 }
[67c6c651]822}
823
[ab1861a]824/** Draw glyph at specified position in viewport.
[76fca31]825 *
826 * @param vport Viewport identification
827 * @param cursor Draw glyph with cursor
828 * @param col Screen position relative to viewport
829 * @param row Screen position relative to viewport
830 *
831 */
[67c6c651]832static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
833 unsigned int row)
[76fca31]834{
835 unsigned int x = vport->x + COL2X(col);
836 unsigned int y = vport->y + ROW2Y(row);
837
[ab1861a]838 uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
839 uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
840 uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
841
[4527fb5]842 (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,
[9805cde]843 fg_color, bg_color);
[68a4442]844}
[76fca31]845
846/** Hide cursor if it is shown
847 *
848 */
849static void cursor_hide(viewport_t *vport)
[49d072e]850{
[76fca31]851 if ((vport->cursor_active) && (vport->cursor_shown)) {
[67c6c651]852 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
[76fca31]853 vport->cursor_shown = false;
[49d072e]854 }
855}
856
[76fca31]857
858/** Show cursor if cursor showing is enabled
859 *
860 */
861static void cursor_show(viewport_t *vport)
[49d072e]862{
863 /* Do not check for cursor_shown */
864 if (vport->cursor_active) {
[67c6c651]865 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
[76fca31]866 vport->cursor_shown = true;
[49d072e]867 }
868}
869
[76fca31]870
871/** Invert cursor, if it is enabled
872 *
873 */
874static void cursor_blink(viewport_t *vport)
[49d072e]875{
876 if (vport->cursor_shown)
[bd02038]877 cursor_hide(vport);
[49d072e]878 else
[76fca31]879 cursor_show(vport);
[49d072e]880}
881
[76fca31]882
883/** Draw character at given position relative to viewport
884 *
885 * @param vport Viewport identification
886 * @param c Character to draw
887 * @param col Screen position relative to viewport
888 * @param row Screen position relative to viewport
889 *
[1180a88e]890 */
[7ce3cb2]891static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)
[88c3151]892{
[9805cde]893 bb_cell_t *bbp;
[ab1861a]894
[76fca31]895 /* Do not hide cursor if we are going to overwrite it */
896 if ((vport->cursor_active) && (vport->cursor_shown) &&
897 ((vport->cur_col != col) || (vport->cur_row != row)))
898 cursor_hide(vport);
[ab1861a]899
[9805cde]900 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[67ebf21]901 bbp->glyph = fb_font_glyph(c);
[9805cde]902 bbp->fg_color = vport->attr.fg_color;
903 bbp->bg_color = vport->attr.bg_color;
[ab1861a]904
[67c6c651]905 draw_vp_glyph(vport, false, col, row);
[88c3151]906
[c1d2c9d]907 vport->cur_col = col;
908 vport->cur_row = row;
[76fca31]909
[c1d2c9d]910 vport->cur_col++;
[00bb6965]911 if (vport->cur_col >= vport->cols) {
[c1d2c9d]912 vport->cur_col = 0;
913 vport->cur_row++;
914 if (vport->cur_row >= vport->rows)
915 vport->cur_row--;
[88c3151]916 }
[76fca31]917
918 cursor_show(vport);
[88c3151]919}
920
[dc033a1]921/** Draw text data to viewport.
[429acb9]922 *
[096ba7a]923 * @param vport Viewport id
[dc033a1]924 * @param data Text data.
[ab1861a]925 * @param x Leftmost column of the area.
926 * @param y Topmost row of the area.
927 * @param w Number of rows.
928 * @param h Number of columns.
929 *
[429acb9]930 */
[dc033a1]931static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
932 unsigned int y, unsigned int w, unsigned int h)
[83b1d61]933{
[ab1861a]934 unsigned int i;
935 unsigned int j;
[9805cde]936 bb_cell_t *bbp;
937 attrs_t *a;
938 attr_rgb_t rgb;
[ab1861a]939
[dc033a1]940 for (j = 0; j < h; j++) {
941 for (i = 0; i < w; i++) {
942 unsigned int col = x + i;
943 unsigned int row = y + j;
[ab1861a]944
[dc033a1]945 bbp = &vport->backbuf[BB_POS(vport, col, row)];
[ab1861a]946
[dc033a1]947 a = &data[j * w + i].attrs;
948 rgb_from_attr(&rgb, a);
[ab1861a]949
[67ebf21]950 bbp->glyph = fb_font_glyph(data[j * w + i].character);
[dc033a1]951 bbp->fg_color = rgb.fg_color;
952 bbp->bg_color = rgb.bg_color;
[ab1861a]953
[dc033a1]954 draw_vp_glyph(vport, false, col, row);
955 }
[83b1d61]956 }
[76fca31]957 cursor_show(vport);
[83b1d61]958}
959
[76fca31]960
961static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
[a7d2d78]962{
[76fca31]963 int pm = *((int *) data);
964 pixmap_t *pmap = &pixmaps[pm];
965 unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
[a7d2d78]966
[76fca31]967 screen.rgb_conv(&pmap->data[pos], color);
[a7d2d78]968}
969
[76fca31]970
971static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
[a7d2d78]972{
[76fca31]973 viewport_t *vport = (viewport_t *) data;
974 unsigned int dx = vport->x + x;
975 unsigned int dy = vport->y + y;
976
977 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
978}
979
[a7d2d78]980
[76fca31]981/** Return first free pixmap
982 *
983 */
984static int find_free_pixmap(void)
985{
986 unsigned int i;
987
988 for (i = 0; i < MAX_PIXMAPS; i++)
989 if (!pixmaps[i].data)
990 return i;
991
992 return -1;
[a7d2d78]993}
994
[76fca31]995
996/** Create a new pixmap and return appropriate ID
997 *
998 */
999static int shm2pixmap(unsigned char *shm, size_t size)
[a7d2d78]1000{
1001 int pm;
1002 pixmap_t *pmap;
[76fca31]1003
[a7d2d78]1004 pm = find_free_pixmap();
1005 if (pm == -1)
1006 return ELIMIT;
[76fca31]1007
[a7d2d78]1008 pmap = &pixmaps[pm];
1009
1010 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
1011 return EINVAL;
1012
1013 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
1014 if (!pmap->data)
1015 return ENOMEM;
[76fca31]1016
1017 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
1018
[a7d2d78]1019 return pm;
1020}
1021
[76fca31]1022
[429acb9]1023/** Handle shared memory communication calls
1024 *
1025 * Protocol for drawing pixmaps:
1026 * - FB_PREPARE_SHM(client shm identification)
[00bb6965]1027 * - IPC_M_AS_AREA_SEND
[76fca31]1028 * - FB_DRAW_PPM(startx, starty)
[429acb9]1029 * - FB_DROP_SHM
1030 *
1031 * Protocol for text drawing
[00bb6965]1032 * - IPC_M_AS_AREA_SEND
[429acb9]1033 * - FB_DRAW_TEXT_DATA
1034 *
1035 * @param callid Callid of the current call
[76fca31]1036 * @param call Current call data
1037 * @param vp Active viewport
[429acb9]1038 *
[76fca31]1039 * @return false if the call was not handled byt this function, true otherwise
1040 *
1041 * Note: this function is not threads safe, you would have
[429acb9]1042 * to redefine static variables with __thread
[76fca31]1043 *
[429acb9]1044 */
[76fca31]1045static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
[90f5d64]1046{
1047 static keyfield_t *interbuffer = NULL;
1048 static size_t intersize = 0;
[76fca31]1049
[153a209]1050 static unsigned char *shm = NULL;
[a7d2d78]1051 static ipcarg_t shm_id = 0;
1052 static size_t shm_size;
[76fca31]1053
1054 bool handled = true;
1055 int retval = EOK;
[90f5d64]1056 viewport_t *vport = &viewports[vp];
[76fca31]1057 unsigned int x;
1058 unsigned int y;
[dc033a1]1059 unsigned int w;
1060 unsigned int h;
[76fca31]1061
[90f5d64]1062 switch (IPC_GET_METHOD(*call)) {
[27d293a]1063 case IPC_M_SHARE_OUT:
[90f5d64]1064 /* We accept one area for data interchange */
[a7d2d78]1065 if (IPC_GET_ARG1(*call) == shm_id) {
[2057572]1066 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
[a7d2d78]1067 shm_size = IPC_GET_ARG2(*call);
[76fca31]1068 if (!ipc_answer_1(callid, EOK, (sysarg_t) dest))
[a7d2d78]1069 shm = dest;
[90f5d64]1070 else
[a7d2d78]1071 shm_id = 0;
[76fca31]1072
[a7d2d78]1073 if (shm[0] != 'P')
[76fca31]1074 return false;
1075
1076 return true;
[90f5d64]1077 } else {
1078 intersize = IPC_GET_ARG2(*call);
[f8ddd17]1079 receive_comm_area(callid, call, (void *) &interbuffer);
[90f5d64]1080 }
[76fca31]1081 return true;
[90f5d64]1082 case FB_PREPARE_SHM:
[a7d2d78]1083 if (shm_id)
[90f5d64]1084 retval = EBUSY;
1085 else
[a7d2d78]1086 shm_id = IPC_GET_ARG1(*call);
[90f5d64]1087 break;
1088
1089 case FB_DROP_SHM:
[a7d2d78]1090 if (shm) {
1091 as_area_destroy(shm);
1092 shm = NULL;
[90f5d64]1093 }
[a7d2d78]1094 shm_id = 0;
1095 break;
[76fca31]1096
[a7d2d78]1097 case FB_SHM2PIXMAP:
1098 if (!shm) {
1099 retval = EINVAL;
1100 break;
1101 }
1102 retval = shm2pixmap(shm, shm_size);
[90f5d64]1103 break;
1104 case FB_DRAW_PPM:
[a7d2d78]1105 if (!shm) {
[90f5d64]1106 retval = EINVAL;
1107 break;
1108 }
1109 x = IPC_GET_ARG1(*call);
1110 y = IPC_GET_ARG2(*call);
[76fca31]1111
1112 if ((x > vport->width) || (y > vport->height)) {
[90f5d64]1113 retval = EINVAL;
1114 break;
1115 }
1116
[00bb6965]1117 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
[76fca31]1118 IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
[90f5d64]1119 break;
1120 case FB_DRAW_TEXT_DATA:
[dc033a1]1121 x = IPC_GET_ARG1(*call);
1122 y = IPC_GET_ARG2(*call);
1123 w = IPC_GET_ARG3(*call);
1124 h = IPC_GET_ARG4(*call);
[90f5d64]1125 if (!interbuffer) {
1126 retval = EINVAL;
1127 break;
1128 }
[dc033a1]1129 if (x + w > vport->cols || y + h > vport->rows) {
1130 retval = EINVAL;
1131 break;
1132 }
1133 if (intersize < w * h * sizeof(*interbuffer)) {
[90f5d64]1134 retval = EINVAL;
1135 break;
1136 }
[dc033a1]1137 draw_text_data(vport, interbuffer, x, y, w, h);
[90f5d64]1138 break;
1139 default:
[76fca31]1140 handled = false;
[90f5d64]1141 }
1142
1143 if (handled)
[b74959bd]1144 ipc_answer_0(callid, retval);
[90f5d64]1145 return handled;
1146}
[83b1d61]1147
[2ce520c]1148
[76fca31]1149static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
1150{
1151 unsigned int width = vport->width;
1152 unsigned int height = vport->height;
1153
[2ce520c]1154 if (width + vport->x > screen.xres)
1155 width = screen.xres - vport->x;
[07bd231e]1156 if (height + vport->y > screen.yres)
[2ce520c]1157 height = screen.yres - vport->y;
[07bd231e]1158
[76fca31]1159 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1160 unsigned int realheight = pmap->height <= height ? pmap->height : height;
[07bd231e]1161
[76fca31]1162 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1163 unsigned int realrowsize = realwidth * screen.pixelbytes;
1164
1165 unsigned int y;
[07bd231e]1166 for (y = 0; y < realheight; y++) {
[76fca31]1167 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1168 memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
[2ce520c]1169 }
1170}
1171
[76fca31]1172
1173/** Save viewport to pixmap
1174 *
1175 */
1176static int save_vp_to_pixmap(viewport_t *vport)
[2ce520c]1177{
1178 int pm;
1179 pixmap_t *pmap;
[76fca31]1180
[429acb9]1181 pm = find_free_pixmap();
1182 if (pm == -1)
1183 return ELIMIT;
1184
1185 pmap = &pixmaps[pm];
1186 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
1187 if (!pmap->data)
1188 return ENOMEM;
[76fca31]1189
[429acb9]1190 pmap->width = vport->width;
1191 pmap->height = vport->height;
[76fca31]1192
[2ce520c]1193 copy_vp_to_pixmap(vport, pmap);
[429acb9]1194
1195 return pm;
1196}
1197
[76fca31]1198
[429acb9]1199/** Draw pixmap on screen
1200 *
1201 * @param vp Viewport to draw on
1202 * @param pm Pixmap identifier
[76fca31]1203 *
[429acb9]1204 */
1205static int draw_pixmap(int vp, int pm)
1206{
1207 pixmap_t *pmap = &pixmaps[pm];
1208 viewport_t *vport = &viewports[vp];
[76fca31]1209
1210 unsigned int width = vport->width;
1211 unsigned int height = vport->height;
1212
[2ce520c]1213 if (width + vport->x > screen.xres)
1214 width = screen.xres - vport->x;
1215 if (height + vport->y > screen.yres)
1216 height = screen.yres - vport->y;
[76fca31]1217
[429acb9]1218 if (!pmap->data)
1219 return EINVAL;
[76fca31]1220
1221 unsigned int realwidth = pmap->width <= width ? pmap->width : width;
1222 unsigned int realheight = pmap->height <= height ? pmap->height : height;
1223
1224 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1225 unsigned int realrowsize = realwidth * screen.pixelbytes;
1226
1227 unsigned int y;
[d7baee6]1228 for (y = 0; y < realheight; y++) {
[76fca31]1229 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1230 memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
[429acb9]1231 }
[76fca31]1232
1233 return EOK;
[429acb9]1234}
1235
[76fca31]1236
1237/** Tick animation one step forward
1238 *
1239 */
1240static void anims_tick(void)
[1fd7700]1241{
[76fca31]1242 unsigned int i;
[1fd7700]1243 static int counts = 0;
1244
1245 /* Limit redrawing */
[00bb6965]1246 counts = (counts + 1) % 8;
[1fd7700]1247 if (counts)
1248 return;
[ab1861a]1249
[d7baee6]1250 for (i = 0; i < MAX_ANIMATIONS; i++) {
[76fca31]1251 if ((!animations[i].animlen) || (!animations[i].initialized) ||
1252 (!animations[i].enabled))
[1fd7700]1253 continue;
[76fca31]1254
1255 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
1256 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
[1fd7700]1257 }
1258}
1259
[2ce520c]1260
[76fca31]1261static unsigned int pointer_x;
1262static unsigned int pointer_y;
1263static bool pointer_shown, pointer_enabled;
[2ce520c]1264static int pointer_vport = -1;
1265static int pointer_pixmap = -1;
1266
[76fca31]1267
1268static void mouse_show(void)
[2ce520c]1269{
[d7baee6]1270 int i, j;
[2ce520c]1271 int visibility;
1272 int color;
1273 int bytepos;
[76fca31]1274
1275 if ((pointer_shown) || (!pointer_enabled))
[a3d2939]1276 return;
[76fca31]1277
[2d32081]1278 /* Save image under the pointer. */
[2ce520c]1279 if (pointer_vport == -1) {
[76fca31]1280 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
[2ce520c]1281 if (pointer_vport < 0)
1282 return;
1283 } else {
1284 viewports[pointer_vport].x = pointer_x;
1285 viewports[pointer_vport].y = pointer_y;
1286 }
[76fca31]1287
[2ce520c]1288 if (pointer_pixmap == -1)
1289 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
1290 else
[76fca31]1291 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
1292
[2d32081]1293 /* Draw mouse pointer. */
[00bb6965]1294 for (i = 0; i < pointer_height; i++)
1295 for (j = 0; j < pointer_width; j++) {
1296 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
[d7baee6]1297 visibility = pointer_mask_bits[bytepos] &
[b74959bd]1298 (1 << (j % 8));
[2ce520c]1299 if (visibility) {
[b74959bd]1300 color = pointer_bits[bytepos] &
1301 (1 << (j % 8)) ? 0 : 0xffffff;
[00bb6965]1302 if (pointer_x + j < screen.xres && pointer_y +
[b74959bd]1303 i < screen.yres)
[00bb6965]1304 putpixel(&viewports[0], pointer_x + j,
[b74959bd]1305 pointer_y + i, color);
[2ce520c]1306 }
1307 }
1308 pointer_shown = 1;
1309}
1310
[76fca31]1311
1312static void mouse_hide(void)
[2ce520c]1313{
[2d32081]1314 /* Restore image under the pointer. */
[2ce520c]1315 if (pointer_shown) {
1316 draw_pixmap(pointer_vport, pointer_pixmap);
1317 pointer_shown = 0;
1318 }
1319}
1320
[76fca31]1321
1322static void mouse_move(unsigned int x, unsigned int y)
[2ce520c]1323{
1324 mouse_hide();
1325 pointer_x = x;
1326 pointer_y = y;
1327 mouse_show();
1328}
1329
[76fca31]1330
1331static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
[1fd7700]1332{
[76fca31]1333 bool handled = true;
1334 int retval = EOK;
1335 int i, nvp;
[1fd7700]1336 int newval;
[76fca31]1337
[1fd7700]1338 switch (IPC_GET_METHOD(*call)) {
1339 case FB_ANIM_CREATE:
1340 nvp = IPC_GET_ARG1(*call);
1341 if (nvp == -1)
1342 nvp = vp;
[00bb6965]1343 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1344 !viewports[nvp].initialized) {
[1fd7700]1345 retval = EINVAL;
1346 break;
1347 }
[00bb6965]1348 for (i = 0; i < MAX_ANIMATIONS; i++) {
1349 if (!animations[i].initialized)
[1fd7700]1350 break;
1351 }
1352 if (i == MAX_ANIMATIONS) {
1353 retval = ELIMIT;
1354 break;
1355 }
1356 animations[i].initialized = 1;
1357 animations[i].animlen = 0;
1358 animations[i].pos = 0;
1359 animations[i].enabled = 0;
1360 animations[i].vp = nvp;
1361 retval = i;
1362 break;
1363 case FB_ANIM_DROP:
1364 i = IPC_GET_ARG1(*call);
[153a209]1365 if (i >= MAX_ANIMATIONS || i < 0) {
[1fd7700]1366 retval = EINVAL;
1367 break;
1368 }
1369 animations[i].initialized = 0;
1370 break;
1371 case FB_ANIM_ADDPIXMAP:
1372 i = IPC_GET_ARG1(*call);
[00bb6965]1373 if (i >= MAX_ANIMATIONS || i < 0 ||
1374 !animations[i].initialized) {
[1fd7700]1375 retval = EINVAL;
1376 break;
1377 }
1378 if (animations[i].animlen == MAX_ANIM_LEN) {
1379 retval = ELIMIT;
1380 break;
1381 }
1382 newval = IPC_GET_ARG2(*call);
[00bb6965]1383 if (newval < 0 || newval > MAX_PIXMAPS ||
1384 !pixmaps[newval].data) {
[1fd7700]1385 retval = EINVAL;
1386 break;
1387 }
1388 animations[i].pixmaps[animations[i].animlen++] = newval;
1389 break;
1390 case FB_ANIM_CHGVP:
1391 i = IPC_GET_ARG1(*call);
1392 if (i >= MAX_ANIMATIONS || i < 0) {
1393 retval = EINVAL;
1394 break;
1395 }
1396 nvp = IPC_GET_ARG2(*call);
1397 if (nvp == -1)
1398 nvp = vp;
[00bb6965]1399 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1400 !viewports[nvp].initialized) {
[1fd7700]1401 retval = EINVAL;
1402 break;
1403 }
1404 animations[i].vp = nvp;
1405 break;
1406 case FB_ANIM_START:
1407 case FB_ANIM_STOP:
1408 i = IPC_GET_ARG1(*call);
1409 if (i >= MAX_ANIMATIONS || i < 0) {
1410 retval = EINVAL;
1411 break;
1412 }
1413 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
1414 if (newval ^ animations[i].enabled) {
1415 animations[i].enabled = newval;
1416 anims_enabled += newval ? 1 : -1;
1417 }
1418 break;
1419 default:
1420 handled = 0;
1421 }
1422 if (handled)
[b74959bd]1423 ipc_answer_0(callid, retval);
[1fd7700]1424 return handled;
1425}
1426
[429acb9]1427
[76fca31]1428/** Handler for messages concerning pixmap handling
1429 *
1430 */
1431static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1432{
1433 bool handled = true;
1434 int retval = EOK;
1435 int i, nvp;
1436
[429acb9]1437 switch (IPC_GET_METHOD(*call)) {
1438 case FB_VP_DRAW_PIXMAP:
1439 nvp = IPC_GET_ARG1(*call);
1440 if (nvp == -1)
1441 nvp = vp;
[00bb6965]1442 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1443 !viewports[nvp].initialized) {
[429acb9]1444 retval = EINVAL;
1445 break;
1446 }
1447 i = IPC_GET_ARG2(*call);
1448 retval = draw_pixmap(nvp, i);
1449 break;
1450 case FB_VP2PIXMAP:
1451 nvp = IPC_GET_ARG1(*call);
1452 if (nvp == -1)
1453 nvp = vp;
[00bb6965]1454 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1455 !viewports[nvp].initialized)
[429acb9]1456 retval = EINVAL;
1457 else
[2ce520c]1458 retval = save_vp_to_pixmap(&viewports[nvp]);
[429acb9]1459 break;
1460 case FB_DROP_PIXMAP:
1461 i = IPC_GET_ARG1(*call);
1462 if (i >= MAX_PIXMAPS) {
1463 retval = EINVAL;
1464 break;
1465 }
1466 if (pixmaps[i].data) {
1467 free(pixmaps[i].data);
1468 pixmaps[i].data = NULL;
1469 }
1470 break;
1471 default:
1472 handled = 0;
1473 }
[76fca31]1474
[429acb9]1475 if (handled)
[b74959bd]1476 ipc_answer_0(callid, retval);
[429acb9]1477 return handled;
1478
1479}
1480
[9805cde]1481static int rgb_from_style(attr_rgb_t *rgb, int style)
1482{
1483 switch (style) {
1484 case STYLE_NORMAL:
1485 rgb->fg_color = color_table[COLOR_BLACK];
1486 rgb->bg_color = color_table[COLOR_WHITE];
1487 break;
1488 case STYLE_EMPHASIS:
1489 rgb->fg_color = color_table[COLOR_RED];
1490 rgb->bg_color = color_table[COLOR_WHITE];
1491 break;
1492 default:
1493 return EINVAL;
1494 }
1495
1496 return EOK;
1497}
1498
1499static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
1500 ipcarg_t bg_color, ipcarg_t flags)
1501{
1502 fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1503 bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1504
1505 rgb->fg_color = color_table[fg_color];
1506 rgb->bg_color = color_table[bg_color];
1507
1508 return EOK;
1509}
1510
[4a62ec9]1511static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
1512{
1513 int rc;
1514
1515 switch (a->t) {
1516 case at_style:
1517 rc = rgb_from_style(rgb, a->a.s.style);
1518 break;
1519 case at_idx:
1520 rc = rgb_from_idx(rgb, a->a.i.fg_color,
1521 a->a.i.bg_color, a->a.i.flags);
1522 break;
1523 case at_rgb:
1524 *rgb = a->a.r;
1525 rc = EOK;
1526 break;
1527 }
1528
1529 return rc;
1530}
1531
[9805cde]1532static int fb_set_style(viewport_t *vport, ipcarg_t style)
1533{
1534 return rgb_from_style(&vport->attr, (int) style);
1535}
1536
1537static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
1538 ipcarg_t bg_color, ipcarg_t flags)
1539{
1540 return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
1541}
1542
[1180a88e]1543/** Function for handling connections to FB
1544 *
1545 */
[76fca31]1546static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
[a2ae4f4]1547{
[76fca31]1548 unsigned int vp = 0;
1549 viewport_t *vport = &viewports[vp];
1550
[a2ae4f4]1551 if (client_connected) {
[b74959bd]1552 ipc_answer_0(iid, ELIMIT);
[a2ae4f4]1553 return;
1554 }
[76fca31]1555
1556 /* Accept connection */
1557 client_connected = true;
1558 ipc_answer_0(iid, EOK);
1559
1560 while (true) {
1561 ipc_callid_t callid;
1562 ipc_call_t call;
1563 int retval;
1564 unsigned int i;
1565 int scroll;
[67ebf21]1566 wchar_t ch;
[76fca31]1567 unsigned int row, col;
1568
1569 if ((vport->cursor_active) || (anims_enabled))
[d7baee6]1570 callid = async_get_call_timeout(&call, 250000);
[d3f2cad]1571 else
1572 callid = async_get_call(&call);
[76fca31]1573
[d552ab9]1574 mouse_hide();
[49d072e]1575 if (!callid) {
[bd02038]1576 cursor_blink(vport);
[1fd7700]1577 anims_tick();
[a3d2939]1578 mouse_show();
[49d072e]1579 continue;
1580 }
[76fca31]1581
[90f5d64]1582 if (shm_handle(callid, &call, vp))
1583 continue;
[76fca31]1584
[429acb9]1585 if (pixmap_handle(callid, &call, vp))
1586 continue;
[76fca31]1587
[1fd7700]1588 if (anim_handle(callid, &call, vp))
1589 continue;
[76fca31]1590
1591 switch (IPC_GET_METHOD(call)) {
[a2ae4f4]1592 case IPC_M_PHONE_HUNGUP:
[76fca31]1593 client_connected = false;
1594
1595 /* Cleanup other viewports */
[00bb6965]1596 for (i = 1; i < MAX_VIEWPORTS; i++)
[76fca31]1597 vport->initialized = false;
1598
1599 /* Exit thread */
1600 return;
1601
[a2ae4f4]1602 case FB_PUTCHAR:
[67ebf21]1603 ch = IPC_GET_ARG1(call);
[a2ae4f4]1604 row = IPC_GET_ARG2(call);
1605 col = IPC_GET_ARG3(call);
[76fca31]1606
1607 if ((col >= vport->cols) || (row >= vport->rows)) {
[a2ae4f4]1608 retval = EINVAL;
1609 break;
1610 }
[b74959bd]1611 ipc_answer_0(callid, EOK);
[76fca31]1612
[67ebf21]1613 draw_char(vport, ch, col, row);
[76fca31]1614
1615 /* Message already answered */
1616 continue;
[a2ae4f4]1617 case FB_CLEAR:
[76fca31]1618 vport_clear(vport);
1619 cursor_show(vport);
1620 retval = EOK;
[a2ae4f4]1621 break;
[76fca31]1622 case FB_CURSOR_GOTO:
[88c3151]1623 row = IPC_GET_ARG1(call);
1624 col = IPC_GET_ARG2(call);
[76fca31]1625
1626 if ((col >= vport->cols) || (row >= vport->rows)) {
[88c3151]1627 retval = EINVAL;
1628 break;
1629 }
[76fca31]1630 retval = EOK;
1631
[bd02038]1632 cursor_hide(vport);
[88c3151]1633 vport->cur_col = col;
1634 vport->cur_row = row;
[76fca31]1635 cursor_show(vport);
1636 break;
[88c3151]1637 case FB_CURSOR_VISIBILITY:
[bd02038]1638 cursor_hide(vport);
[49d072e]1639 vport->cursor_active = IPC_GET_ARG1(call);
[76fca31]1640 cursor_show(vport);
1641 retval = EOK;
[88c3151]1642 break;
[a2ae4f4]1643 case FB_GET_CSIZE:
[b74959bd]1644 ipc_answer_2(callid, EOK, vport->rows, vport->cols);
[88c3151]1645 continue;
1646 case FB_SCROLL:
[76fca31]1647 scroll = IPC_GET_ARG1(call);
1648 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
[88c3151]1649 retval = EINVAL;
1650 break;
1651 }
[bd02038]1652 cursor_hide(vport);
[76fca31]1653 vport_scroll(vport, scroll);
1654 cursor_show(vport);
1655 retval = EOK;
[e92aabf]1656 break;
[88c3151]1657 case FB_VIEWPORT_SWITCH:
1658 i = IPC_GET_ARG1(call);
[76fca31]1659 if (i >= MAX_VIEWPORTS) {
[88c3151]1660 retval = EINVAL;
1661 break;
1662 }
[76fca31]1663 if (!viewports[i].initialized) {
[88c3151]1664 retval = EADDRNOTAVAIL;
1665 break;
1666 }
[bd02038]1667 cursor_hide(vport);
[88c3151]1668 vp = i;
1669 vport = &viewports[vp];
[76fca31]1670 cursor_show(vport);
1671 retval = EOK;
[88c3151]1672 break;
1673 case FB_VIEWPORT_CREATE:
[76fca31]1674 retval = vport_create(IPC_GET_ARG1(call) >> 16,
[b74959bd]1675 IPC_GET_ARG1(call) & 0xffff,
1676 IPC_GET_ARG2(call) >> 16,
1677 IPC_GET_ARG2(call) & 0xffff);
[88c3151]1678 break;
1679 case FB_VIEWPORT_DELETE:
1680 i = IPC_GET_ARG1(call);
[76fca31]1681 if (i >= MAX_VIEWPORTS) {
[88c3151]1682 retval = EINVAL;
1683 break;
1684 }
[76fca31]1685 if (!viewports[i].initialized) {
[88c3151]1686 retval = EADDRNOTAVAIL;
1687 break;
1688 }
[76fca31]1689 viewports[i].initialized = false;
1690 if (viewports[i].bgpixel)
1691 free(viewports[i].bgpixel);
1692 if (viewports[i].backbuf)
1693 free(viewports[i].backbuf);
1694 retval = EOK;
[88c3151]1695 break;
1696 case FB_SET_STYLE:
[9805cde]1697 retval = fb_set_style(vport, IPC_GET_ARG1(call));
1698 break;
1699 case FB_SET_COLOR:
1700 retval = fb_set_color(vport, IPC_GET_ARG1(call),
1701 IPC_GET_ARG2(call), IPC_GET_ARG3(call));
1702 break;
1703 case FB_SET_RGB_COLOR:
1704 vport->attr.fg_color = IPC_GET_ARG1(call);
1705 vport->attr.bg_color = IPC_GET_ARG2(call);
[76fca31]1706 retval = EOK;
[88c3151]1707 break;
1708 case FB_GET_RESOLUTION:
[b74959bd]1709 ipc_answer_2(callid, EOK, screen.xres, screen.yres);
[a2ae4f4]1710 continue;
[830ac99]1711 case FB_POINTER_MOVE:
[76fca31]1712 pointer_enabled = true;
[2ce520c]1713 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
[76fca31]1714 retval = EOK;
[830ac99]1715 break;
[ebfabf6]1716 case FB_SCREEN_YIELD:
1717 case FB_SCREEN_RECLAIM:
[10270a8]1718 retval = EOK;
1719 break;
[a2ae4f4]1720 default:
1721 retval = ENOENT;
1722 }
[b74959bd]1723 ipc_answer_0(callid, retval);
[a2ae4f4]1724 }
[afa6e74]1725}
1726
[76fca31]1727/** Initialization of framebuffer
1728 *
1729 */
1730int fb_init(void)
[a2ae4f4]1731{
[da0c91e7]1732 async_set_client_connection(fb_client_connection);
[a2ae4f4]1733
[76fca31]1734 void *fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1735 unsigned int fb_offset = sysinfo_value("fb.offset");
1736 unsigned int fb_width = sysinfo_value("fb.width");
1737 unsigned int fb_height = sysinfo_value("fb.height");
1738 unsigned int fb_scanline = sysinfo_value("fb.scanline");
1739 unsigned int fb_visual = sysinfo_value("fb.visual");
1740
1741 unsigned int fbsize = fb_scanline * fb_height;
1742 void *fb_addr = as_get_mappable_page(fbsize);
1743
[ae318d3]1744 if (physmem_map(fb_ph_addr + fb_offset, fb_addr,
1745 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
1746 return -1;
[76fca31]1747
1748 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
[2bc137c2]1749 return 0;
1750
1751 return -1;
[a2ae4f4]1752}
[da0c91e7]1753
[76fca31]1754/**
[ce5bcb4]1755 * @}
1756 */
Note: See TracBrowser for help on using the repository browser.