Index: uspace/srv/fb/fb.c
===================================================================
--- uspace/srv/fb/fb.c	(revision edf577420a2b19c935ca2388aefc25ab2e2e5f0e)
+++ uspace/srv/fb/fb.c	(revision 68a44422c7d096a2c997e7a52bf936872f5a646c)
@@ -72,5 +72,10 @@
 #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 {
@@ -100,8 +105,20 @@
 	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 */
@@ -140,6 +157,9 @@
 static bool client_connected = false;  /**< Allow only 1 connection */
 
-static void draw_glyph(unsigned int x, unsigned int y, bool cursor,
-    uint8_t *glyphs, uint8_t glyph);
+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);
@@ -334,5 +354,6 @@
 			}
 
-			draw_glyph(x, y, false, vport->glyphs, glyph);
+			(*vport->dglyph)(x, y, false, vport->glyphs, glyph,
+			    vport->style.fg_color, vport->style.bg_color);
 			x += FONT_WIDTH;
 		}
@@ -377,16 +398,9 @@
 				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);
 			}
 		}
@@ -423,4 +437,5 @@
 	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);
@@ -458,5 +473,22 @@
 	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;
@@ -535,21 +567,130 @@
 
 
-/** Draw a glyph.
- *
- * @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.
- *
- */
-static void draw_glyph(unsigned int x, unsigned int y, bool cursor,
-    uint8_t *glyphs, uint8_t glyph)
-{
-	unsigned int yd;
-	
-	for (yd = 0; yd < FONT_SCANLINES; yd++)
-		memcpy(&screen.fb_addr[FB_POS(x, y + yd)],
-		    &glyphs[GLYPH_POS(glyph, yd, cursor)], screen.glyphscanline);
+/** 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;
+	}
 }
 
@@ -570,7 +711,8 @@
 	
 	glyph = vport->backbuf[BB_POS(vport, col, row)];
-	draw_glyph(x, y, cursor, vport->glyphs, glyph);
-}
-
+
+	(*vport->dglyph)(x, y, cursor, vport->glyphs, glyph,
+	    vport->style.fg_color, vport->style.bg_color);
+}
 
 /** Hide cursor if it is shown
@@ -1339,5 +1481,4 @@
 			vport->style.fg_color = IPC_GET_ARG1(call);
 			vport->style.bg_color = IPC_GET_ARG2(call);
-			render_glyphs(vport);
 			retval = EOK;
 			break;
