Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3744 → Rev 3745

/branches/sparc/uspace/srv/fb/fb.c
71,8 → 71,13
#define MAX_PIXMAPS 256 /**< Maximum number of saved pixmaps */
#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
 
/** Function to render a pixel from a RGB value. */
typedef void (*rgb_conv_t)(void *, uint32_t);
 
/** Function to draw a glyph. */
typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
 
struct {
uint8_t *fb_addr;
99,10 → 104,22
unsigned int cols;
unsigned int rows;
/* Style and glyphs for text printing */
/*
* Style and glyphs for text printing
*/
 
/** Current style. */
style_t style;
 
/** Pre-rendered mask for rendering glyphs. Different viewports
* might use different drawing functions depending on whether their
* scanlines are aligned on a word boundary.*/
uint8_t *glyphs;
 
uint8_t *bgpixel;
 
/** Glyph drawing function for this viewport. */
dg_t dglyph;
/* Auto-cursor position */
bool cursor_active;
139,6 → 156,15
 
static bool client_connected = false; /**< Allow only 1 connection */
 
static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color);
 
static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
unsigned int row);
 
 
#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
219,8 → 245,42
= ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
}
 
/** Draw a filled rectangle.
*
* @note Need real implementation that does not access VRAM twice.
*/
static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
unsigned int y1, uint32_t color)
{
unsigned int x, y;
unsigned int copy_bytes;
 
/** Redraw viewport
uint8_t *sp, *dp;
uint8_t cbuf[4];
 
if (y0 >= y1 || x0 >= x1) return;
screen.rgb_conv(cbuf, color);
 
sp = &screen.fb_addr[FB_POS(x0, y0)];
dp = sp;
 
/* Draw the first line. */
for (x = x0; x < x1; x++) {
memcpy(dp, cbuf, screen.pixelbytes);
dp += screen.pixelbytes;
}
 
dp = sp + screen.scanline;
copy_bytes = (x1 - x0) * screen.pixelbytes;
 
/* Draw the remaining lines by copying. */
for (y = y0 + 1; y < y1; y++) {
memcpy(dp, sp, copy_bytes);
dp += screen.scanline;
}
}
 
/** Redraw viewport.
*
* @param vport Viewport to redraw
*
227,48 → 287,31
*/
static void vport_redraw(viewport_t *vport)
{
unsigned int row;
unsigned int row, col;
 
for (row = 0; row < vport->rows; row++) {
unsigned int y = vport->y + ROW2Y(row);
unsigned int yd;
for (yd = 0; yd < FONT_SCANLINES; yd++) {
unsigned int x;
unsigned int col;
for (col = 0, x = vport->x; col < vport->cols; col++, x += FONT_WIDTH)
memcpy(&screen.fb_addr[FB_POS(x, y + yd)],
&vport->glyphs[GLYPH_POS(vport->backbuf[BB_POS(vport, col, row)], yd, false)],
screen.glyphscanline);
for (col = 0; col < vport->cols; col++) {
draw_vp_glyph(vport, false, col, row);
}
}
 
if (COL2X(vport->cols) < vport->width) {
unsigned int y;
for (y = 0; y < vport->height; y++) {
unsigned int x;
for (x = COL2X(vport->cols); x < vport->width; x++)
memcpy(&screen.fb_addr[FB_POS(x, y)], vport->bgpixel, screen.pixelbytes);
}
draw_filled_rect(
vport->x + COL2X(vport->cols), vport->y,
vport->x + vport->width, vport->y + vport->height,
vport->style.bg_color);
}
 
if (ROW2Y(vport->rows) < vport->height) {
unsigned int y;
for (y = ROW2Y(vport->rows); y < vport->height; y++) {
unsigned int x;
for (x = 0; x < vport->width; x++)
memcpy(&screen.fb_addr[FB_POS(x, y)], vport->bgpixel, screen.pixelbytes);
}
draw_filled_rect(
vport->x, vport->y + ROW2Y(vport->rows),
vport->x + vport->width, vport->y + vport->height,
vport->style.bg_color);
}
}
 
 
/** Clear viewport
/** Clear viewport.
*
* @param vport Viewport to clear
*
279,8 → 322,7
vport_redraw(vport);
}
 
 
/** Scroll viewport by given number of lines
/** Scroll viewport by the specified number of lines.
*
* @param vport Viewport to scroll
* @param lines Number of lines to scroll
288,43 → 330,52
*/
static void vport_scroll(viewport_t *vport, int lines)
{
unsigned int row;
unsigned int row, col;
unsigned int x, y;
uint8_t glyph;
 
/*
* Redraw.
*/
 
y = vport->y;
for (row = 0; row < vport->rows; row++) {
unsigned int y = vport->y + ROW2Y(row);
unsigned int yd;
for (yd = 0; yd < FONT_SCANLINES; yd++) {
unsigned int x;
unsigned int col;
for (col = 0, x = vport->x; col < vport->cols; col++, x += FONT_WIDTH) {
uint8_t glyph;
if ((row + lines >= 0) && (row + lines < vport->rows)) {
if (vport->backbuf[BB_POS(vport, col, row)] == vport->backbuf[BB_POS(vport, col, row + lines)])
continue;
glyph = vport->backbuf[BB_POS(vport, col, row + lines)];
} else
glyph = 0;
memcpy(&screen.fb_addr[FB_POS(x, y + yd)],
&vport->glyphs[GLYPH_POS(glyph, yd, false)], screen.glyphscanline);
x = vport->x;
for (col = 0; col < vport->cols; col++) {
if ((row + lines >= 0) && (row + lines < vport->rows)) {
glyph = vport->backbuf[BB_POS(vport, col, row + lines)];
 
if (vport->backbuf[BB_POS(vport, col, row)] == glyph) {
x += FONT_WIDTH;
continue;
}
} else {
glyph = 0;
}
 
(*vport->dglyph)(x, y, false, vport->glyphs, glyph,
vport->style.fg_color, vport->style.bg_color);
x += FONT_WIDTH;
}
y += FONT_SCANLINES;
}
 
/*
* Scroll backbuffer.
*/
 
if (lines > 0) {
memcpy(vport->backbuf, vport->backbuf + vport->cols * lines, vport->cols * (vport->rows - lines));
memset(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)], 0, vport->cols * lines);
memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
vport->cols * (vport->rows - lines));
memset(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
0, vport->cols * lines);
} else {
memcpy(vport->backbuf - vport->cols * lines, vport->backbuf, vport->cols * (vport->rows + lines));
memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
vport->cols * (vport->rows + lines));
memset(vport->backbuf, 0, - vport->cols * lines);
}
}
 
 
/** Render glyphs
*
* Convert glyphs from device independent font
346,18 → 397,11
for (x = 0; x < FONT_WIDTH; x++) {
screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
(fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
? vport->style.fg_color : vport->style.bg_color);
? 0xffffff : 0x000000);
uint32_t curcolor;
if (y < FONT_SCANLINES - 2)
curcolor =
(fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
? vport->style.fg_color : vport->style.bg_color;
else
curcolor = vport->style.fg_color;
screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes], curcolor);
screen.rgb_conv(&vport->glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
(fb_font[glyph * FONT_SCANLINES + y] & (1 << (7 - x)))
? 0x000000 : 0xffffff);
}
}
}
392,6 → 436,7
unsigned int rows = height / FONT_SCANLINES;
unsigned int bbsize = cols * rows;
unsigned int glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
unsigned int word_size = sizeof(unsigned long);
uint8_t *backbuf = (uint8_t *) malloc(bbsize);
if (!backbuf)
427,7 → 472,24
viewports[i].glyphs = glyphs;
viewports[i].bgpixel = bgpixel;
 
/*
* Conditions necessary to select aligned version:
*
* - word size is divisible by pixelbytes
* - cell scanline size is divisible by word size
* - cell scanlines are word-aligned
*/
if ((word_size % screen.pixelbytes) == 0 &&
(FONT_WIDTH * screen.pixelbytes) % word_size == 0 &&
(x * screen.pixelbytes) % word_size == 0 &&
screen.scanline % word_size == 0) {
 
viewports[i].dglyph = draw_glyph_aligned;
} else {
viewports[i].dglyph = draw_glyph_fallback;
}
 
viewports[i].cur_col = 0;
viewports[i].cur_row = 0;
viewports[i].cursor_active = false;
504,8 → 566,136
}
 
 
/** Draw glyph at given position relative to viewport
/** Draw a glyph, takes advantage of alignment.
*
* This version can only be used if the following conditions are met:
*
* - word size is divisible by pixelbytes
* - cell scanline size is divisible by word size
* - cell scanlines are word-aligned
*
* It makes use of the pre-rendered mask to process (possibly) several
* pixels at once (word size / pixelbytes pixels at a time are processed)
* making it very fast. Most notably this version is not applicable at 24 bits
* per pixel.
*
* @param x x coordinate of top-left corner on screen.
* @param y y coordinate of top-left corner on screen.
* @param cursor Draw glyph with cursor
* @param glyphs Pointer to font bitmap.
* @param glyph Code of the glyph to draw.
* @param fg_color Foreground color.
* @param bg_color Backgroudn color.
*/
static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color)
{
unsigned int i, yd;
unsigned long fg_buf, bg_buf;
unsigned long *maskp, *dp;
unsigned long mask;
unsigned int ww, d_add;
 
/*
* Prepare a pair of words, one filled with foreground-color
* pattern and the other filled with background-color pattern.
*/
for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
screen.rgb_conv(&((uint8_t *)&fg_buf)[i * screen.pixelbytes],
fg_color);
screen.rgb_conv(&((uint8_t *)&bg_buf)[i * screen.pixelbytes],
bg_color);
}
 
 
/* Pointer to the current position in the mask. */
maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
 
/* Pointer to the current position on the screen. */
dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
 
/* Width of the character cell in words. */
ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
 
/* Offset to add when moving to another screen scanline. */
d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
 
for (yd = 0; yd < FONT_SCANLINES; yd++) {
/*
* Now process the cell scanline, combining foreground
* and background color patters using the pre-rendered mask.
*/
for (i = 0; i < ww; i++) {
mask = *maskp++;
*dp++ = (fg_buf & mask) | (bg_buf & ~mask);
}
 
/* Move to the beginning of the next scanline of the cell. */
dp = (unsigned long *) ((uint8_t *) dp + d_add);
}
}
 
/** Draw a glyph, fallback version.
*
* This version does not make use of the pre-rendered mask, it uses
* the font bitmap directly. It works always, but it is slower.
*
* @param x x coordinate of top-left corner on screen.
* @param y y coordinate of top-left corner on screen.
* @param cursor Draw glyph with cursor
* @param glyphs Pointer to font bitmap.
* @param glyph Code of the glyph to draw.
* @param fg_color Foreground color.
* @param bg_color Backgroudn color.
*/
void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
uint8_t *glyphs, uint8_t glyph, uint32_t fg_color, uint32_t bg_color)
{
unsigned int i, j, yd;
uint8_t fg_buf[4], bg_buf[4];
uint8_t *dp, *sp;
unsigned int d_add;
uint8_t b;
 
/* Pre-render 1x the foreground and background color pixels. */
if (cursor) {
screen.rgb_conv(fg_buf, bg_color);
screen.rgb_conv(bg_buf, fg_color);
} else {
screen.rgb_conv(fg_buf, fg_color);
screen.rgb_conv(bg_buf, bg_color);
}
 
/* Pointer to the current position on the screen. */
dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
 
/* Offset to add when moving to another screen scanline. */
d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
 
for (yd = 0; yd < FONT_SCANLINES; yd++) {
/* Byte containing bits of the glyph scanline. */
b = fb_font[glyph * FONT_SCANLINES + yd];
 
for (i = 0; i < FONT_WIDTH; i++) {
/* Choose color based on the current bit. */
sp = (b & 0x80) ? fg_buf : bg_buf;
 
/* Copy the pixel. */
for (j = 0; j < screen.pixelbytes; j++) {
*dp++ = *sp++;
}
 
/* Move to the next bit. */
b = b << 1;
}
/* Move to the beginning of the next scanline of the cell. */
dp += d_add;
}
}
 
/** Draw glyph at specified position in viewport.
*
* @param vport Viewport identification
* @param cursor Draw glyph with cursor
* @param col Screen position relative to viewport
512,20 → 702,19
* @param row Screen position relative to viewport
*
*/
static void draw_glyph(viewport_t *vport, bool cursor, unsigned int col, unsigned int row)
static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
unsigned int row)
{
unsigned int x = vport->x + COL2X(col);
unsigned int y = vport->y + ROW2Y(row);
unsigned int yd;
uint8_t glyph;
uint8_t glyph = vport->backbuf[BB_POS(vport, col, row)];
for (yd = 0; yd < FONT_SCANLINES; yd++)
memcpy(&screen.fb_addr[FB_POS(x, y + yd)],
&vport->glyphs[GLYPH_POS(glyph, yd, cursor)], screen.glyphscanline);
glyph = vport->backbuf[BB_POS(vport, col, row)];
 
(*vport->dglyph)(x, y, cursor, vport->glyphs, glyph,
vport->style.fg_color, vport->style.bg_color);
}
 
 
/** Hide cursor if it is shown
*
*/
532,7 → 721,7
static void cursor_hide(viewport_t *vport)
{
if ((vport->cursor_active) && (vport->cursor_shown)) {
draw_glyph(vport, false, vport->cur_col, vport->cur_row);
draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
vport->cursor_shown = false;
}
}
545,7 → 734,7
{
/* Do not check for cursor_shown */
if (vport->cursor_active) {
draw_glyph(vport, true, vport->cur_col, vport->cur_row);
draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
vport->cursor_shown = true;
}
}
579,7 → 768,7
cursor_hide(vport);
vport->backbuf[BB_POS(vport, col, row)] = c;
draw_glyph(vport, false, col, row);
draw_vp_glyph(vport, false, col, row);
vport->cur_col = col;
vport->cur_row = row;
616,7 → 805,7
if (glyph != data[i].character) {
vport->backbuf[BB_POS(vport, col, row)] = data[i].character;
draw_glyph(vport, false, col, row);
draw_vp_glyph(vport, false, col, row);
}
}
cursor_show(vport);
930,7 → 1119,7
if ((pointer_shown) || (!pointer_enabled))
return;
/* Save image under the cursor */
/* Save image under the pointer. */
if (pointer_vport == -1) {
pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
if (pointer_vport < 0)
945,7 → 1134,7
else
copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
/* Draw cursor */
/* Draw mouse pointer. */
for (i = 0; i < pointer_height; i++)
for (j = 0; j < pointer_width; j++) {
bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
966,7 → 1155,7
 
static void mouse_hide(void)
{
/* Restore image under the cursor */
/* Restore image under the pointer. */
if (pointer_shown) {
draw_pixmap(pointer_vport, pointer_pixmap);
pointer_shown = 0;
1291,7 → 1480,6
case FB_SET_STYLE:
vport->style.fg_color = IPC_GET_ARG1(call);
vport->style.bg_color = IPC_GET_ARG2(call);
render_glyphs(vport);
retval = EOK;
break;
case FB_GET_RESOLUTION: