linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Tile Blitting
@ 2003-02-23  4:42 Antonino Daplas
  2003-02-23  7:43 ` Antonino Daplas
  0 siblings, 1 reply; 12+ messages in thread
From: Antonino Daplas @ 2003-02-23  4:42 UTC (permalink / raw)
  To: James Simmons; +Cc: Linux Fbdev development list

[-- Attachment #1: Type: text/plain, Size: 1328 bytes --]

Hi James,

If fbcon will support different methods of rasterizing to the
framebuffer, it's best if display->dispsw is revived.  Currently, fbcon
supports classic blitting, but if you decide to add text mode support
(for matroxfb and sbusfb), then tile blitting needs to be supported
too.  Also, rotation will require another method, and so will texture
mapping if you ever decide to add this (Isn't this a bit overkill?!). 
The struct display is not visible to the drivers, so fbcon need to know
which dispsw to use, possibly based on a new field in struct fb_info or
the presence of the function pointer. I prefer an info->caps field so
drivers need not mangle function pointers.

Here's an updated Tile Blitting patch.  The feature is selectable via
kernel configuration (under Advanced Low Level Driver Features). 
Currently, it detects the presence of info->tileops but bit setting
info->caps should be better.

The second patch adds generic tile blitting operation, to be used only
for testing purposes since it's very slow.  It just wraps fb_imageblit
and fb_copyarea.  If anyone wants to test this, just link the driver
cfb_tileops.o, add "info->tileops = &cfb_tileops" during driver
initialization, and enable Tile Blitting support in the kernel.  

Tony

PS: reverse the "accel_putcs() optimazation patch" if applied



[-- Attachment #2: tileblit1.diff --]
[-- Type: text/x-patch, Size: 27737 bytes --]

diff -Naur linux-2.5.61-fbdev/drivers/video/console/Kconfig linux-2.5.61/drivers/video/console/Kconfig
--- linux-2.5.61-fbdev/drivers/video/console/Kconfig	2003-02-16 00:49:23.000000000 +0000
+++ linux-2.5.61/drivers/video/console/Kconfig	2003-02-23 03:19:44.000000000 +0000
@@ -136,6 +136,16 @@
 
 	  If unsure, say N.
 
+config FBCON_ADVANCED_TILEBLIT
+	bool "Support for Tile Blitting Operations"
+	depends on FBCON_ADVANCED
+	---help---
+          If you say Y, Tile Blitting support will be added.  Tile blitting is
+          a drawing operation, but its basic operating unit is a bitmap (in
+          contrast to Classic Blitting which operate on pixels).  This is 
+          necessary for drivers with Text Mode support.
+
+          If unsure, say N.
 # Guess what we need
 
 config FONT_SUN8x16
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Makefile linux-2.5.61/drivers/video/console/Makefile
--- linux-2.5.61-fbdev/drivers/video/console/Makefile	2003-02-16 00:49:23.000000000 +0000
+++ linux-2.5.61/drivers/video/console/Makefile	2003-02-23 03:19:48.000000000 +0000
@@ -16,6 +16,12 @@
 
 font-objs += $(font-objs-y)
 
+fbcon_adv-obj := fbadv.o
+
+fbcon_adv-obj-$(CONFIG_FBCON_ADVANCED_TILEBLIT) += fbcon_tileops.o
+
+fbcon_adv-objs += $(fbcon_adv-obj-y)
+
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
@@ -24,7 +30,7 @@
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
-obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o fbcon_adv.o
 
 obj-$(CONFIG_FB_STI)              += sticore.o
 
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.c linux-2.5.61/drivers/video/console/fbcon.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon.c	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon.c	2003-02-23 03:56:01.000000000 +0000
@@ -331,17 +331,120 @@
 	info->fbops->fb_fillrect(info, &region);
 }	
 
-#define FB_PIXMAPSIZE 8192
-void accel_putcs(struct vc_data *vc, struct display *p,
-			const unsigned short *s, int count, int yy, int xx)
+static void accel_putc(struct vc_data *vc, struct display *p,
+		       int c, int ypos, int xpos)
 {
 	struct fb_info *info = p->fb_info;
 	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7)/8);
+	unsigned int width = ((vc->vc_font.width + 7) >> 3);
+	struct fb_image image;
+
+	image.dx = xpos * vc->vc_font.width;
+	image.dy = real_y(p, ypos) * vc->vc_font.height;
+	image.width = vc->vc_font.width;
+	image.height = vc->vc_font.height;
+	image.fg_color = attr_fgcol(p, c);
+	image.bg_color = attr_bgcol(p, c);
+	image.depth = 0;
+	image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
+
+	info->fbops->fb_imageblit(info, &image);
+}
+
+#define FB_PIXMAPSIZE 8192
+static void putcs_unaligned(struct vc_data *vc, struct display *p,
+			    struct fb_info *info, struct fb_image *image, 
+			    int count, const unsigned short *s)
+{
+	unsigned int width = (vc->vc_font.width + 7)/8;
 	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
+	unsigned int pitch, cnt, i, j, k;
+	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+	unsigned int shift_high = 8;
+	unsigned int idx = vc->vc_font.width/8;
+	unsigned short charmask = p->charmask;
+	u8 mask, *src, *dst, *dst0;
+	
+	while (count) {
+		if (count > maxcnt) 
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		
+		dst0 = (u8 *) image->data;
+		image->width = vc->vc_font.width * cnt;
+		pitch = (image->width + 7)/8;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask) * cellsize;
+			dst = dst0;
+			mask = (u8) (0xfff << shift_high);
+			for (i = image->height; i--; ) {
+				for (j = 0; j < idx; j++) {
+					dst[j] &= mask;
+					dst[j] |= *src >> shift_low;
+					dst[j+1] = *src << shift_high;
+					src++;
+				}
+				dst[idx] &= mask;
+				dst[idx] |= *src++ >> shift_low;
+				dst += pitch;
+			}
+			shift_low += mod;
+			shift_low &= 7;
+			shift_high = 8 - shift_low;
+			dst0 += (shift_low) ? width - 1 : width;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+static void putcs_aligned(struct vc_data *vc, struct display *p,
+			  struct fb_info *info, struct fb_image *image, 
+			  int count, const unsigned short *s)
+{
+	unsigned int width = (vc->vc_font.width + 7)/8;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
+	unsigned int pitch, cnt, i, j, k;
+	unsigned short charmask = p->charmask;
+	u8 *src, *dst, *dst0;
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		dst0 = (u8 *) image->data;
+		pitch = width *cnt;
+		image->width = vc->vc_font.width * cnt;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask) * cellsize;
+			dst = dst0;
+			for (i = image->height; i--; ) {
+				for (j = 0; j < width; j++) 
+					dst[j] = *src++;
+				dst += pitch;
+			}
+			dst0 += width;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+static void accel_putcs(struct vc_data *vc, struct display *p,
+			const unsigned short *s, int count, int yy, int xx)
+{
+	static u8 pixmap[FB_PIXMAPSIZE];
+	struct fb_info *info = p->fb_info;
 	struct fb_image image;
 	u16 c = scr_readw(s);
-	static u8 pixmap[FB_PIXMAPSIZE];
 	
 	image.fg_color = attr_fgcol(p, c);
 	image.bg_color = attr_bgcol(p, c);
@@ -349,47 +452,12 @@
 	image.dy = yy * vc->vc_font.height;
 	image.height = vc->vc_font.height;
 	image.depth = 0;
+	image.data = pixmap;
 
-	if (!(vc->vc_font.width & 7)) {
-		unsigned int pitch, cnt, i, j, k;
-		unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
-		char *src, *dst, *dst0;
-
-		image.data = pixmap;
-		while (count) {
-			if (count > maxcnt) 
-				cnt = k = maxcnt;
-			else
-				cnt = k = count;
-			
-			dst0 = pixmap;
-			pitch = width * cnt;
-			image.width = vc->vc_font.width * cnt;
-			while (k--) {
-				src = p->fontdata + (scr_readw(s++)&charmask)*
-					cellsize;
-				dst = dst0;
-				for (i = image.height; i--; ) {
-					for (j = 0; j < width; j++) 
-						dst[j] = *src++;
-					dst += pitch;
-				}
-				dst0 += width;
-			}
-
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += cnt * vc->vc_font.width;
-			count -= cnt;
-		}
-	} else {
-		image.width = vc->vc_font.width;
-		while (count--) {
-			image.data = p->fontdata + 
-				(scr_readw(s++) & charmask) * cellsize;
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += vc->vc_font.width;
-		}	
-	}
+	if (!(vc->vc_font.width & 7)) 
+		putcs_aligned(vc, p, info, &image, count, s);
+	else 
+		putcs_unaligned(vc, p, info, &image, count, s);
 }
 
 void accel_clear_margins(struct vc_data *vc, struct display *p,
@@ -424,7 +492,15 @@
 	}	
 }	
 
-void accel_cursor(struct display *p, int flags, int xx, int yy)
+static struct display_switch accel_switch = {
+	.bmove =         accel_bmove,
+	.clear =         accel_clear,
+	.putc =          accel_putc,
+	.putcs =         accel_putcs,
+	.clear_margins = accel_clear_margins,
+};
+
+void fb_cursor(struct display *p, int flags, int xx, int yy)
 {
 	static char mask[64], image[64], *dest;
 	struct vc_data *vc = p->conp;
@@ -743,6 +819,13 @@
 	int i, charcnt = 256;
 	struct font_desc *font;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops)
+		p->dispsw = &tile_switch;
+	else 
+#endif
+		p->dispsw = &accel_switch;
+
 	if (con != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
 	    info->fix.type == FB_TYPE_TEXT)
 		logo = 0;
@@ -880,7 +963,7 @@
 			vc_resize(con, nr_cols, nr_rows);
 		else if (CON_IS_VISIBLE(vc) &&
 			 vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
-			accel_clear_margins(vc, p, 0);
+			p->dispsw->clear_margins(vc, p, 0);
 			update_screen(con);
 		}
 		if (save) {
@@ -977,11 +1060,11 @@
 	y_break = p->vrows - p->yscroll;
 	if (sy < y_break && sy + height - 1 >= y_break) {
 		u_int b = y_break - sy;
-		accel_clear(vc, p, real_y(p, sy), sx, b, width);
-		accel_clear(vc, p, real_y(p, sy + b), sx, height - b,
+		p->dispsw->clear(vc, p, real_y(p, sy), sx, b, width);
+		p->dispsw->clear(vc, p, real_y(p, sy + b), sx, height - b,
 				 width);
 	} else
-		accel_clear(vc, p, real_y(p, sy), sx, height, width);
+		p->dispsw->clear(vc, p, real_y(p, sy), sx, height, width);
 
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -991,10 +1074,6 @@
 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
 {
 	struct display *p = &fb_display[vc->vc_num];
-	struct fb_info *info = p->fb_info;
-	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7) >> 3);
-	struct fb_image image;
 	int redraw_cursor = 0;
 
 	if (!p->can_soft_blank && console_blanked)
@@ -1008,16 +1087,7 @@
 		redraw_cursor = 1;
 	}
 
-	image.fg_color = attr_fgcol(p, c);
-	image.bg_color = attr_bgcol(p, c);
-	image.dx = xpos * vc->vc_font.width;
-	image.dy = real_y(p, ypos) * vc->vc_font.height;
-	image.width = vc->vc_font.width;
-	image.height = vc->vc_font.height;
-	image.depth = 1;
-	image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
-
-	info->fbops->fb_imageblit(info, &image);
+	p->dispsw->putc(vc, p, c, real_y(p, ypos), xpos);
 
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -1042,7 +1112,7 @@
 		cursor_undrawn();
 		redraw_cursor = 1;
 	}
-	accel_putcs(vc, p, s, count, real_y(p, ypos), xpos);
+	p->dispsw->putcs(vc, p, s, count, real_y(p, ypos), xpos);
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
@@ -1070,7 +1140,7 @@
 
 	cursor_on = 0;
 	if (cursor_drawn)
-		accel_cursor(p, 0, p->cursor_x,
+		fb_cursor(p, 0, p->cursor_x,
 				  real_y(p, p->cursor_y));
 
 	p->cursor_x = vc->vc_x;
@@ -1084,7 +1154,7 @@
 	case CM_MOVE:
 	case CM_DRAW:
 		if (cursor_drawn)
-			accel_cursor(p, FB_CUR_SETCUR, p->cursor_x,
+			fb_cursor(p, FB_CUR_SETCUR, p->cursor_x,
 					  real_y(p, p->cursor_y));
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 		cursor_on = 1;
@@ -1106,7 +1176,7 @@
 		flag = 0;
 		if (!cursor_drawn)
 			flag = FB_CUR_SETCUR;
-		accel_cursor(p, flag, p->cursor_x,
+		fb_cursor(p, flag, p->cursor_x,
 				  real_y(p, p->cursor_y));
 		cursor_drawn ^= 1;
 		vbl_cursor_cnt = cursor_blink_rate;
@@ -1168,7 +1238,7 @@
 
 	p->yscroll += count;
 	if (p->yscroll > p->vrows - vc->vc_rows) {
-		accel_bmove(p, p->vrows - vc->vc_rows, 0, 0, 0,
+		p->dispsw->bmove(p, p->vrows - vc->vc_rows, 0, 0, 0,
 				 vc->vc_rows, vc->vc_cols);
 		p->yscroll -= p->vrows - vc->vc_rows;
 	}
@@ -1176,7 +1246,7 @@
 	info->var.yoffset = p->yscroll * vc->vc_font.height;
 	info->var.vmode &= ~FB_VMODE_YWRAP;
 	update_var(vc->vc_num, info);
-	accel_clear_margins(vc, p, 1);
+	p->dispsw->clear_margins(vc, p, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
 		scrollback_max = scrollback_phys_max;
@@ -1191,7 +1261,7 @@
 
 	p->yscroll -= count;
 	if (p->yscroll < 0) {
-		accel_bmove(p, 0, 0, p->vrows - vc->vc_rows, 0,
+		p->dispsw->bmove(p, 0, 0, p->vrows - vc->vc_rows, 0,
 				 vc->vc_rows, vc->vc_cols);
 		p->yscroll += p->vrows - vc->vc_rows;
 	}
@@ -1199,7 +1269,7 @@
 	info->var.yoffset = p->yscroll * vc->vc_font.height;
 	info->var.vmode &= ~FB_VMODE_YWRAP;
 	update_var(vc->vc_num, info);
-	accel_clear_margins(vc, p, 1);
+	p->dispsw->clear_margins(vc, p, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
 		scrollback_max = 0;
@@ -1265,7 +1335,7 @@
 			if (attr != (c & 0xff00)) {
 				attr = c & 0xff00;
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1275,7 +1345,7 @@
 			}
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1290,7 +1360,7 @@
 			d++;
 		} while (s < le);
 		if (s > start)
-			accel_putcs(vc, p, start, s - start,
+			p->dispsw->putcs(vc, p, start, s - start,
 					 real_y(p, line), x);
 		line++;
 		if (d == (u16 *) softback_end)
@@ -1323,7 +1393,7 @@
 			if (attr != (c & 0xff00)) {
 				attr = c & 0xff00;
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1333,7 +1403,7 @@
 			}
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1350,7 +1420,7 @@
 			d++;
 		} while (s < le);
 		if (s > start)
-			accel_putcs(vc, p, start, s - start,
+			p->dispsw->putcs(vc, p, start, s - start,
 					 real_y(p, line), x);
 		console_conditional_schedule();
 		if (offset > 0)
@@ -1420,9 +1490,9 @@
 			goto redraw_up;
 		switch (p->scrollmode & __SCROLL_YMASK) {
 		case __SCROLL_YMOVE:
-			accel_bmove(p, t + count, 0, t, 0,
+			p->dispsw->bmove(p, t + count, 0, t, 0,
 					 b - t - count, vc->vc_cols);
-			accel_clear(vc, p, b - count, 0, count,
+			p->dispsw->clear(vc, p, b - count, 0, count,
 					 vc->vc_cols);
 			break;
 
@@ -1471,7 +1541,7 @@
 		      redraw_up:
 			fbcon_redraw(vc, p, t, b - t - count,
 				     count * vc->vc_cols);
-			accel_clear(vc, p, real_y(p, b - count), 0,
+			p->dispsw->clear(vc, p, real_y(p, b - count), 0,
 					 count, vc->vc_cols);
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
@@ -1487,9 +1557,9 @@
 			count = vc->vc_rows;
 		switch (p->scrollmode & __SCROLL_YMASK) {
 		case __SCROLL_YMOVE:
-			accel_bmove(p, t, 0, t + count, 0,
+			p->dispsw->bmove(p, t, 0, t + count, 0,
 					 b - t - count, vc->vc_cols);
-			accel_clear(vc, p, t, 0, count, vc->vc_cols);
+			p->dispsw->clear(vc, p, t, 0, count, vc->vc_cols);
 			break;
 
 		case __SCROLL_YWRAP:
@@ -1536,7 +1606,7 @@
 		      redraw_down:
 			fbcon_redraw(vc, p, b - 1, b - t - count,
 				     -count * vc->vc_cols);
-			accel_clear(vc, p, real_y(p, t), 0, count,
+			p->dispsw->clear(vc, p, real_y(p, t), 0, count,
 					 vc->vc_cols);
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
@@ -1615,7 +1685,7 @@
 		}
 		return;
 	}
-	accel_bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height,
+	p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height,
 			 width);
 }
 
@@ -1643,8 +1713,8 @@
 		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
 		var.activate = FB_ACTIVATE_NOW;
 		fb_set_var(&var, info);
-		p->vrows = info->var.yres_virtual/fh;
 	}
+	p->vrows = info->var.yres_virtual/fh;
 	return 0;
 }
 
@@ -1654,6 +1724,13 @@
 	struct display *p = &fb_display[unit];
 	struct fb_info *info = p->fb_info;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops)
+		p->dispsw = &tile_switch;
+	else
+#endif
+		p->dispsw = &accel_switch;
+
 	if (softback_top) {
 		int l = fbcon_softback_size / vc->vc_size_row;
 		if (softback_lines)
@@ -1679,6 +1756,9 @@
 	}
 	if (info)
 		info->var.yoffset = p->yscroll = 0;
+
+        fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
+
 	switch (p->scrollmode & __SCROLL_YMASK) {
 	case __SCROLL_YWRAP:
 		scrollback_phys_max = p->vrows - vc->vc_rows;
@@ -1695,14 +1775,39 @@
 	scrollback_max = 0;
 	scrollback_current = 0;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops) {
+		struct fb_tiledata tile;
+		int err, cnt, size;
+		u8 *tiledata;
+
+		cnt = FNTCHARCNT(p->fontdata);
+		if (!cnt)
+			cnt = 256;
+		size = vc->vc_font.height * ((vc->vc_font.width + 7)/8) * cnt; 
+		tiledata = kmalloc(size, GFP_KERNEL);
+		if (tiledata == NULL)
+			return 0;
+		memcpy(tiledata, p->fontdata, size);
+		tile.tile.width = vc->vc_font.width;
+		tile.tile.height = vc->vc_font.height;
+		tile.tile.depth = 1;
+		tile.len = cnt;
+		tile.data = tiledata; 
+		err = info->tileops->fb_loadtiles(info, &tile);
+		kfree(tiledata);
+
+		if (err) return 0;
+	}
+#endif
+
 	info->currcon = unit;
 	
-        fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
 	update_var(unit, info);
 	fbcon_set_palette(vc, color_table); 	
 
 	if (vt_cons[unit]->vc_mode == KD_TEXT)
-		accel_clear_margins(vc, p, 0);
+		p->dispsw->clear_margins(vc, p, 0);
 	if (logo_shown == -2) {
 		logo_shown = fg_console;
 		/* This is protected above by initmem_freed */
@@ -1737,18 +1842,18 @@
 			height = vc->vc_rows;
 			y_break = p->vrows - p->yscroll;
 			if (height > y_break) {
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p, 0), 0,
 						 y_break,
 						 vc->vc_cols);
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p,
 						y_break),
 						0,
 						 height - y_break,
 						 vc->vc_cols);
 			} else
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p, 0), 0,
 						 height,
 						 vc->vc_cols);
@@ -1913,6 +2018,29 @@
 
 	}
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops) {
+		struct fb_tiledata tile;
+		int err, size;
+		u8 *tiledata;
+		
+		size = vc->vc_font.height * ((vc->vc_font.width + 7)/8) * cnt; 
+		tiledata = kmalloc(size, GFP_KERNEL);
+		if (tiledata == NULL)
+			return 1;
+		memcpy(tiledata, p->fontdata, size);
+		tile.tile.width = vc->vc_font.width;
+		tile.tile.height = vc->vc_font.height;
+		tile.tile.depth = 1;
+		tile.len = cnt;
+		tile.data = tiledata;
+		
+		err = info->tileops->fb_loadtiles(info, &tile);
+		kfree(tiledata);
+		if (err) return err;
+	}
+#endif
+
 	if (resize) {
 		/* reset wrap/pan */
 		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
@@ -1935,7 +2063,7 @@
 		}
 	} else if (CON_IS_VISIBLE(vc)
 		   && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
-		accel_clear_margins(vc, p, 0);
+		p->dispsw->clear_margins(vc, p, 0);
 		update_screen(vc->vc_num);
 	}
 
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.h linux-2.5.61/drivers/video/console/fbcon.h
--- linux-2.5.61-fbdev/drivers/video/console/fbcon.h	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon.h	2003-02-23 03:20:58.000000000 +0000
@@ -46,6 +46,20 @@
     unsigned int fontwidthmask;      /* 1 at (1 << (width - 1)) if width is supported */
 };
 
+struct display_switch {
+	void (*bmove)(struct display *p, int sy, int sx, 
+		      int dy, int dx, int height, int width);
+	void (*clear)(struct vc_data *vc, struct display *p, int sy,
+		      int sx, int height, int width);
+	void (*putcs)(struct vc_data *vc, struct display *p,
+		      const unsigned short *s, int count, 
+		      int yy, int xx);
+	void (*putc)(struct vc_data *vc, struct display *p, 
+		     int c, int ypos, int xpos);
+	void (*clear_margins)(struct vc_data *vc, struct display *p,
+			      int bottom_only);
+};
+
 /* drivers/video/console/fbcon.c */
 extern struct display fb_display[MAX_NR_CONSOLES];
 extern char con2fb_map[MAX_NR_CONSOLES];
@@ -120,5 +134,6 @@
 #define SCROLL_YNOPARTIAL	__SCROLL_YNOPARTIAL
 
 extern int fb_console_init(void);
+extern struct display_switch tile_switch;
 
 #endif /* _VIDEO_FBCON_H */
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon_tileops.c linux-2.5.61/drivers/video/console/fbcon_tileops.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon_tileops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon_tileops.c	2003-02-23 03:21:47.000000000 +0000
@@ -0,0 +1,118 @@
+/*
+ *  linux/drivers/video/fbcon_tileops.c -- Console Ops using Tile Blitting
+ *                                         (ie. Text Mode support)
+ *
+ *	Copyright (C) 2003 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include "fbcon.h"
+
+static void tile_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		       int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tilecopy tilerect;
+
+	tilerect.sx = sx;
+	tilerect.sy = sy;
+	tilerect.dx = dx;
+	tilerect.dy = dy;
+	tilerect.height = height;
+	tilerect.width = width;
+	
+	info->tileops->fb_tilecopy(info, &tilerect);
+}
+
+static void tile_clear(struct vc_data *vc, struct display *p, int sy,
+		       int sx, int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tilefill tilerect;
+	
+	tilerect.dx = sx;
+	tilerect.dy = sy;
+	tilerect.width = width;
+	tilerect.height = height;
+	tilerect.fg_color = attr_fgcol_ec(p, vc);
+	tilerect.bg_color = attr_bgcol_ec(p, vc);
+	tilerect.idx = vc->vc_video_erase_char & p->charmask;
+	tilerect.rop = ROP_COPY;
+
+	info->tileops->fb_tilefill(info, &tilerect);
+}
+
+static void tile_putc(struct vc_data *vc, struct display *p,
+		      int c, int ypos, int xpos)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tileblit tilerect;
+	u32 font = c & p->charmask;
+	
+	tilerect.dx = xpos;
+	tilerect.dy = ypos;
+	tilerect.width = 1;
+	tilerect.height = 1;
+	tilerect.fg_color = attr_fgcol(p, c);
+	tilerect.bg_color = attr_bgcol(p, c);
+	tilerect.data = &font;
+
+	info->tileops->fb_tileblit(info, &tilerect);
+}
+
+#define TILEMAP_SIZE 1024
+static void tile_putcs(struct vc_data *vc, struct display *p,
+			const unsigned short *s, int count, 
+			int yy, int xx)
+{
+	static u32 tilemap[TILEMAP_SIZE];
+	struct fb_info *info = p->fb_info;
+	struct fb_tileblit tilerect;
+	int maxcnt = TILEMAP_SIZE, i, cnt;
+	u16 c = scr_readw(s);
+
+	tilerect.dx = xx;
+	tilerect.dy = yy;
+	tilerect.height = 1;
+	tilerect.fg_color = attr_fgcol(p, c);
+	tilerect.bg_color = attr_bgcol(p, c);
+	tilerect.data = tilemap;
+
+	while (count) {
+		cnt = (count > maxcnt) ? maxcnt : count;
+		tilerect.width = cnt;
+		for (i = 0; i < cnt; i++) 
+			tilemap[i] = (u32) (scr_readw(s++) & p->charmask);
+		
+		info->tileops->fb_tileblit(info, &tilerect);
+		tilerect.dx += cnt;
+		count -= cnt;
+	}
+}
+
+static void tile_clear_margins(struct vc_data *vc, struct display *p,
+			       int bottom_only)
+{
+	/* Not used */
+	return;
+}
+
+struct display_switch tile_switch = {
+	.bmove =         tile_bmove,
+	.clear =         tile_clear,
+	.putc  =         tile_putc,
+	.putcs =         tile_putcs,
+	.clear_margins = tile_clear_margins,
+};
+
+EXPORT_SYMBOL(tile_switch);
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>, "
+	      "Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Tile Blitting Ops");
+MODULE_LICENSE("GPL");
diff -Naur linux-2.5.61-fbdev/drivers/video/fbmem.c linux-2.5.61/drivers/video/fbmem.c
--- linux-2.5.61-fbdev/drivers/video/fbmem.c	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/fbmem.c	2003-02-23 04:13:57.000000000 +0000
@@ -363,14 +363,14 @@
 static int ofonly __initdata = 0;
 #endif
 
+#ifdef CONFIG_LOGO
+#include <linux/linux_logo.h>
+
 static inline unsigned safe_shift(unsigned d, int n)
 {
 	return n < 0 ? d >> -n : d << n;
 }
 
-#ifdef CONFIG_FB_LOGO
-#include <linux/linux_logo.h>
-
 static void __init fb_set_logocmap(struct fb_info *info,
 				   const struct linux_logo *logo)
 {
diff -Naur linux-2.5.61-fbdev/include/linux/fb.h linux-2.5.61/include/linux/fb.h
--- linux-2.5.61-fbdev/include/linux/fb.h	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/include/linux/fb.h	2003-02-23 03:19:50.000000000 +0000
@@ -380,6 +380,77 @@
     int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
 };
 
+/* 
+ * Tile Blitting Support
+ * 
+ * In Tile Blitting, the basic unit is a Tile which is a bitmap with
+ * a predefined width and height, and optionally, other properties
+ * such as color depth, spacing, transparency,  etc.  For now, we'll 
+ * just support width, height, and color depth.
+ * 
+ * All operations are analogous to classic blitting operations which
+ * use pixels as the basic unit.  Instead of pixels, it will use tiles,
+ * instead of info->pseudo_palette, it will use tiledata, etc.
+ */
+
+struct fb_tile {
+	__u32 width;            /* tile width in pixels */
+	__u32 height;           /* tile height in scanlines */
+	__u32 depth;            /* pixel depth */
+};
+
+struct fb_tiledata {
+	struct fb_tile tile;    /* tile properties */
+	__u32 len;              /* number of tiles in the map */
+	__u8  *data;            /* packed tile data */
+};
+
+struct fb_tileblit {
+	__u32 dx;               /* destination x origin, in tiles */
+	__u32 dy;               /* destination y origin, in tiles */
+	__u32 width;            /* destination window width, in tiles */
+	__u32 height;           /* destination window height, in tiles */
+	__u32 fg_color;         /* fg_color if monochrome */
+	__u32 bg_color;         /* bg_color if monochrome */
+	__u32 *data;            /* tile map - array of indices to tiledata */
+};
+
+struct fb_tilecopy {
+	__u32 dx;               /* destination window origin... */
+	__u32 dy;               /* in tiles */
+	__u32 width;            /* destination width, in tiles */
+	__u32 height;           /* destination height, in tiles */
+	__u32 sx;               /* source window origin ... */
+	__u32 sy;               /* in tiles */
+};
+
+struct fb_tilefill {
+	__u32 dx;               /* destination window origin ... */
+	__u32 dy;               /* in tiles */
+	__u32 width;            /* destination width in tiles */
+	__u32 height;           /* destination height in tiles */
+	__u32 fg_color;         /* fg_color if monochrome */
+	__u32 bg_color;         /* bg_color if monochrome */
+	__u32 rop;              /* rop operation */
+	__u32 idx;              /* index to current tiledata */
+};
+
+struct fb_tileops {
+    /* upload tile data to driver and make it current... the driver
+     * must copy the contents of tiledata.data, not just the pointer to it */
+    int (*fb_loadtiles)(struct fb_info *info, 
+			const struct fb_tiledata *tileinfo);
+    /* blit tiles to destination from a tilemap */
+    void (*fb_tileblit)(struct fb_info *info, 
+			const struct fb_tileblit *tilemap);
+    /* copy tiles from one region of fb memory to another */
+    void (*fb_tilecopy)(struct fb_info *info, const struct fb_tilecopy *area);
+    /* fill a region of fb memory with a tile */
+    void (*fb_tilefill)(struct fb_info *info, 
+			const struct fb_tilefill *region);
+    /* If driver is to support tile blitting, all hooks above are required */
+};
+
 struct fb_info {
    kdev_t node;
    int flags;
@@ -391,6 +462,7 @@
    struct fb_cursor cursor;		/* Current cursor */	
    struct fb_cmap cmap;                 /* Current cmap */
    struct fb_ops *fbops;
+   struct fb_tileops *tileops;          /* Tile blitting */
    char *screen_base;                   /* Virtual address */
    struct vc_data *display_fg;		/* Console visible on this display */
    int currcon;				/* Current VC. */	

[-- Attachment #3: cfb_tileops.diff --]
[-- Type: text/x-patch, Size: 3875 bytes --]

diff -Naur linux-2.5.61-fbdev/cfb_tileops.c linux-2.5.61/cfb_tileops.c
--- linux-2.5.61-fbdev/cfb_tileops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.61/cfb_tileops.c	2003-02-23 04:17:36.000000000 +0000
@@ -0,0 +1,130 @@
+/*
+ *  Generic TileBLT function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  June 1999 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ * NOTES:
+ *
+ *  This is a test program to implement Tile Blitting using classical blitting
+ *  routines.  This is naturally slower, so don't use this for your default
+ *  operations.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+static struct fb_tiledata cfb_tileinfo;
+static u8 *cfb_tiledata = NULL;
+
+static int cfb_loadtiles(struct fb_info *info, 
+			 const struct fb_tiledata *tileinfo)
+{
+	u32 size = (tileinfo->tile.width + 7)/8 * tileinfo->tile.height;
+
+	size *= tileinfo->len;
+	if (cfb_tiledata) {
+		if (info->fbops->fb_sync)
+			info->fbops->fb_sync(info);
+		kfree(cfb_tiledata);
+		cfb_tiledata = NULL;
+	}
+			
+	cfb_tiledata = kmalloc(size, GFP_KERNEL);
+	if (cfb_tiledata == NULL)
+		return 1;
+	cfb_tileinfo = *tileinfo;
+	cfb_tileinfo.data = cfb_tiledata;
+	memcpy(cfb_tiledata, tileinfo->data, size);
+
+	return 0;
+}
+
+static void cfb_tileblit(struct fb_info *info, 
+			 const struct fb_tileblit *tilemap)
+{
+	struct fb_image image;
+	u32 width = cfb_tileinfo.tile.width;
+	u32 height = cfb_tileinfo.tile.height;
+	u32 cellsize = (width + 7)/8 * height;
+	int i;
+
+	image.dx = tilemap->dx * width;
+	image.dy = tilemap->dy * height;
+	image.width = width;
+	image.height = tilemap->height * height;
+	image.fg_color = tilemap->fg_color;
+	image.bg_color = tilemap->bg_color;
+	image.depth = 0;
+
+	for (i = 0; i < tilemap->width; i++) {
+		image.data = cfb_tileinfo.data + (tilemap->data[i] * cellsize);
+		info->fbops->fb_imageblit(info, &image);
+		image.dx += width;
+	}
+}
+
+static void cfb_tilefill(struct fb_info *info, 
+			 const struct fb_tilefill *tilerect)
+{
+	struct fb_image image;
+	u32 width = cfb_tileinfo.tile.width;
+	u32 height = cfb_tileinfo.tile.height;
+	u32 dx, dy, i, j;
+
+	dx = tilerect->dx * width;
+	dy = tilerect->dy * height;
+	image.width = width;
+	image.height = height;
+	image.fg_color = tilerect->fg_color;
+	image.bg_color = tilerect->bg_color;
+	image.data = cfb_tileinfo.data + 
+		tilerect->idx * ((width + 7)/8 * height);
+	image.depth = 0;
+
+	for (i = 0; i < tilerect->height; i++) {
+		image.dy = dy;
+		for (j = 0; j < tilerect->width; j++) {
+			image.dx = dx;
+			info->fbops->fb_imageblit(info, &image);
+			dx += width;
+		}
+		dy += height;
+	}
+}
+
+static void cfb_tilecopy(struct fb_info *info, const struct fb_tilecopy *tileregion)
+{
+	struct fb_copyarea area;
+	u32 width = cfb_tileinfo.tile.width;
+	u32 height = cfb_tileinfo.tile.height;
+
+	area.dx = tileregion->dx * width;
+	area.dy = tileregion->dy * height;
+	area.sx = tileregion->sx * width;
+	area.sy = tileregion->sy * height;
+	area.width = tileregion->width * width;
+	area.height = tileregion->height * height;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+struct fb_tileops cfb_tileops = {
+	.fb_loadtiles = cfb_loadtiles,
+	.fb_tileblit  = cfb_tileblit,
+	.fb_tilecopy  = cfb_tilecopy,
+	.fb_tilefill  = cfb_tilefill,
+};
+
+EXPORT_SYMBOL(cfb_tileops);
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>, "
+	      "Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Low Level Tile Blitting Ops");
+MODULE_LICENSE("GPL");
+
+ 	

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-23  4:42 [PATCH] Tile Blitting Antonino Daplas
@ 2003-02-23  7:43 ` Antonino Daplas
  2003-02-23 11:07   ` Antonino Daplas
  0 siblings, 1 reply; 12+ messages in thread
From: Antonino Daplas @ 2003-02-23  7:43 UTC (permalink / raw)
  To: Antonino Daplas; +Cc: James Simmons, Linux Fbdev development list

[-- Attachment #1: Type: text/plain, Size: 375 bytes --]

On Sun, 2003-02-23 at 12:42, Antonino Daplas wrote:

> Here's an updated Tile Blitting patch.  The feature is selectable via
> kernel configuration (under Advanced Low Level Driver Features). 
> Currently, it detects the presence of info->tileops but bit setting
> info->caps should be better.

Stupid me :-(, the patch does not work properly.  Try this one instead.

Tony



[-- Attachment #2: tileblit1.diff --]
[-- Type: text/x-patch, Size: 32864 bytes --]

diff -Naur linux-2.5.61-fbdev/drivers/video/console/Kconfig linux-2.5.61/drivers/video/console/Kconfig
--- linux-2.5.61-fbdev/drivers/video/console/Kconfig	2003-02-16 00:49:23.000000000 +0000
+++ linux-2.5.61/drivers/video/console/Kconfig	2003-02-23 06:42:26.000000000 +0000
@@ -136,6 +136,16 @@
 
 	  If unsure, say N.
 
+config FBCON_ADVANCED_TILEBLIT
+	bool "Support for Tile Blitting Operations"
+	depends on FBCON_ADVANCED
+	---help---
+          If you say Y, Tile Blitting support will be added.  Tile blitting is
+          a drawing operation, but its basic operating unit is a bitmap (in
+          contrast to Classic Blitting which operate on pixels).  This is 
+          necessary for drivers with Text Mode support.
+
+          If unsure, say N.
 # Guess what we need
 
 config FONT_SUN8x16
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Makefile linux-2.5.61/drivers/video/console/Makefile
--- linux-2.5.61-fbdev/drivers/video/console/Makefile	2003-02-16 00:49:23.000000000 +0000
+++ linux-2.5.61/drivers/video/console/Makefile	2003-02-23 07:01:01.000000000 +0000
@@ -16,6 +16,10 @@
 
 font-objs += $(font-objs-y)
 
+fbcon_adv-objs := fbcon_accelops.o
+fbcon_adv-objs-$(CONFIG_FBCON_ADVANCED_TILEBLIT) += fbcon_tileops.o
+fbcon_adv-objs += $(fbcon_adv-objs-y)
+
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
@@ -24,7 +28,7 @@
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
-obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o fbcon_adv.o
 
 obj-$(CONFIG_FB_STI)              += sticore.o
 
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.c linux-2.5.61/drivers/video/console/fbcon.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon.c	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon.c	2003-02-23 06:45:15.000000000 +0000
@@ -295,136 +295,7 @@
 	take_over_console(&fb_con, unit, unit, fbcon_is_default);
 }
 
-/*
- * Accelerated handlers.
- */
-void accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
-			int height, int width)
-{
-	struct fb_info *info = p->fb_info;
-	struct vc_data *vc = p->conp;
-	struct fb_copyarea area;
-
-	area.sx = sx * vc->vc_font.width;
-	area.sy = sy * vc->vc_font.height;
-	area.dx = dx * vc->vc_font.width;
-	area.dy = dy * vc->vc_font.height;
-	area.height = height * vc->vc_font.height;
-	area.width = width * vc->vc_font.width;
-
-	info->fbops->fb_copyarea(info, &area);
-}
-
-void accel_clear(struct vc_data *vc, struct display *p, int sy,
-			int sx, int height, int width)
-{
-	struct fb_info *info = p->fb_info;
-	struct fb_fillrect region;
-
-	region.color = attr_bgcol_ec(p, vc);
-	region.dx = sx * vc->vc_font.width;
-	region.dy = sy * vc->vc_font.height;
-	region.width = width * vc->vc_font.width;
-	region.height = height * vc->vc_font.height;
-	region.rop = ROP_COPY;
-
-	info->fbops->fb_fillrect(info, &region);
-}	
-
-#define FB_PIXMAPSIZE 8192
-void accel_putcs(struct vc_data *vc, struct display *p,
-			const unsigned short *s, int count, int yy, int xx)
-{
-	struct fb_info *info = p->fb_info;
-	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7)/8);
-	unsigned int cellsize = vc->vc_font.height * width;
-	struct fb_image image;
-	u16 c = scr_readw(s);
-	static u8 pixmap[FB_PIXMAPSIZE];
-	
-	image.fg_color = attr_fgcol(p, c);
-	image.bg_color = attr_bgcol(p, c);
-	image.dx = xx * vc->vc_font.width;
-	image.dy = yy * vc->vc_font.height;
-	image.height = vc->vc_font.height;
-	image.depth = 0;
-
-	if (!(vc->vc_font.width & 7)) {
-		unsigned int pitch, cnt, i, j, k;
-		unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
-		char *src, *dst, *dst0;
-
-		image.data = pixmap;
-		while (count) {
-			if (count > maxcnt) 
-				cnt = k = maxcnt;
-			else
-				cnt = k = count;
-			
-			dst0 = pixmap;
-			pitch = width * cnt;
-			image.width = vc->vc_font.width * cnt;
-			while (k--) {
-				src = p->fontdata + (scr_readw(s++)&charmask)*
-					cellsize;
-				dst = dst0;
-				for (i = image.height; i--; ) {
-					for (j = 0; j < width; j++) 
-						dst[j] = *src++;
-					dst += pitch;
-				}
-				dst0 += width;
-			}
-
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += cnt * vc->vc_font.width;
-			count -= cnt;
-		}
-	} else {
-		image.width = vc->vc_font.width;
-		while (count--) {
-			image.data = p->fontdata + 
-				(scr_readw(s++) & charmask) * cellsize;
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += vc->vc_font.width;
-		}	
-	}
-}
-
-void accel_clear_margins(struct vc_data *vc, struct display *p,
-				int bottom_only)
-{
-	struct fb_info *info = p->fb_info;
-	unsigned int cw = vc->vc_font.width;
-	unsigned int ch = vc->vc_font.height;
-	unsigned int rw = info->var.xres % cw;
-	unsigned int bh = info->var.yres % ch;
-	unsigned int rs = info->var.xres - rw;
-	unsigned int bs = info->var.yres - bh;
-	struct fb_fillrect region;
-
-	region.color = attr_bgcol_ec(p, vc);
-	region.rop = ROP_COPY;
-
-	if (rw & !bottom_only) {
-		region.dx = info->var.xoffset + rs;
-		region.dy = 0;
-		region.width = rw;
-		region.height = info->var.yres_virtual;
-		info->fbops->fb_fillrect(info, &region);
-	}
-
-	if (bh) {
-		region.dx = info->var.xoffset;
-		region.dy = info->var.yoffset + bs;
-		region.width = rs;
-		region.height = bh;
-		info->fbops->fb_fillrect(info, &region);
-	}	
-}	
-
-void accel_cursor(struct display *p, int flags, int xx, int yy)
+void fb_cursor(struct display *p, int flags, int xx, int yy)
 {
 	static char mask[64], image[64], *dest;
 	struct vc_data *vc = p->conp;
@@ -743,6 +614,13 @@
 	int i, charcnt = 256;
 	struct font_desc *font;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops)
+		p->dispsw = &tile_switch;
+	else 
+#endif
+		p->dispsw = &accel_switch;
+
 	if (con != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
 	    info->fix.type == FB_TYPE_TEXT)
 		logo = 0;
@@ -880,7 +758,7 @@
 			vc_resize(con, nr_cols, nr_rows);
 		else if (CON_IS_VISIBLE(vc) &&
 			 vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
-			accel_clear_margins(vc, p, 0);
+			p->dispsw->clear_margins(vc, p, 0);
 			update_screen(con);
 		}
 		if (save) {
@@ -977,11 +855,11 @@
 	y_break = p->vrows - p->yscroll;
 	if (sy < y_break && sy + height - 1 >= y_break) {
 		u_int b = y_break - sy;
-		accel_clear(vc, p, real_y(p, sy), sx, b, width);
-		accel_clear(vc, p, real_y(p, sy + b), sx, height - b,
+		p->dispsw->clear(vc, p, real_y(p, sy), sx, b, width);
+		p->dispsw->clear(vc, p, real_y(p, sy + b), sx, height - b,
 				 width);
 	} else
-		accel_clear(vc, p, real_y(p, sy), sx, height, width);
+		p->dispsw->clear(vc, p, real_y(p, sy), sx, height, width);
 
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -991,10 +869,6 @@
 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
 {
 	struct display *p = &fb_display[vc->vc_num];
-	struct fb_info *info = p->fb_info;
-	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7) >> 3);
-	struct fb_image image;
 	int redraw_cursor = 0;
 
 	if (!p->can_soft_blank && console_blanked)
@@ -1008,16 +882,7 @@
 		redraw_cursor = 1;
 	}
 
-	image.fg_color = attr_fgcol(p, c);
-	image.bg_color = attr_bgcol(p, c);
-	image.dx = xpos * vc->vc_font.width;
-	image.dy = real_y(p, ypos) * vc->vc_font.height;
-	image.width = vc->vc_font.width;
-	image.height = vc->vc_font.height;
-	image.depth = 1;
-	image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
-
-	info->fbops->fb_imageblit(info, &image);
+	p->dispsw->putc(vc, p, c, real_y(p, ypos), xpos);
 
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -1042,7 +907,7 @@
 		cursor_undrawn();
 		redraw_cursor = 1;
 	}
-	accel_putcs(vc, p, s, count, real_y(p, ypos), xpos);
+	p->dispsw->putcs(vc, p, s, count, real_y(p, ypos), xpos);
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
@@ -1070,7 +935,7 @@
 
 	cursor_on = 0;
 	if (cursor_drawn)
-		accel_cursor(p, 0, p->cursor_x,
+		fb_cursor(p, 0, p->cursor_x,
 				  real_y(p, p->cursor_y));
 
 	p->cursor_x = vc->vc_x;
@@ -1084,7 +949,7 @@
 	case CM_MOVE:
 	case CM_DRAW:
 		if (cursor_drawn)
-			accel_cursor(p, FB_CUR_SETCUR, p->cursor_x,
+			fb_cursor(p, FB_CUR_SETCUR, p->cursor_x,
 					  real_y(p, p->cursor_y));
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 		cursor_on = 1;
@@ -1106,7 +971,7 @@
 		flag = 0;
 		if (!cursor_drawn)
 			flag = FB_CUR_SETCUR;
-		accel_cursor(p, flag, p->cursor_x,
+		fb_cursor(p, flag, p->cursor_x,
 				  real_y(p, p->cursor_y));
 		cursor_drawn ^= 1;
 		vbl_cursor_cnt = cursor_blink_rate;
@@ -1168,7 +1033,7 @@
 
 	p->yscroll += count;
 	if (p->yscroll > p->vrows - vc->vc_rows) {
-		accel_bmove(p, p->vrows - vc->vc_rows, 0, 0, 0,
+		p->dispsw->bmove(p, p->vrows - vc->vc_rows, 0, 0, 0,
 				 vc->vc_rows, vc->vc_cols);
 		p->yscroll -= p->vrows - vc->vc_rows;
 	}
@@ -1176,7 +1041,7 @@
 	info->var.yoffset = p->yscroll * vc->vc_font.height;
 	info->var.vmode &= ~FB_VMODE_YWRAP;
 	update_var(vc->vc_num, info);
-	accel_clear_margins(vc, p, 1);
+	p->dispsw->clear_margins(vc, p, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
 		scrollback_max = scrollback_phys_max;
@@ -1191,7 +1056,7 @@
 
 	p->yscroll -= count;
 	if (p->yscroll < 0) {
-		accel_bmove(p, 0, 0, p->vrows - vc->vc_rows, 0,
+		p->dispsw->bmove(p, 0, 0, p->vrows - vc->vc_rows, 0,
 				 vc->vc_rows, vc->vc_cols);
 		p->yscroll += p->vrows - vc->vc_rows;
 	}
@@ -1199,7 +1064,7 @@
 	info->var.yoffset = p->yscroll * vc->vc_font.height;
 	info->var.vmode &= ~FB_VMODE_YWRAP;
 	update_var(vc->vc_num, info);
-	accel_clear_margins(vc, p, 1);
+	p->dispsw->clear_margins(vc, p, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
 		scrollback_max = 0;
@@ -1265,7 +1130,7 @@
 			if (attr != (c & 0xff00)) {
 				attr = c & 0xff00;
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1275,7 +1140,7 @@
 			}
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1290,7 +1155,7 @@
 			d++;
 		} while (s < le);
 		if (s > start)
-			accel_putcs(vc, p, start, s - start,
+			p->dispsw->putcs(vc, p, start, s - start,
 					 real_y(p, line), x);
 		line++;
 		if (d == (u16 *) softback_end)
@@ -1323,7 +1188,7 @@
 			if (attr != (c & 0xff00)) {
 				attr = c & 0xff00;
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1333,7 +1198,7 @@
 			}
 			if (c == scr_readw(d)) {
 				if (s > start) {
-					accel_putcs(vc, p, start,
+					p->dispsw->putcs(vc, p, start,
 							 s - start,
 							 real_y(p, line),
 							 x);
@@ -1350,7 +1215,7 @@
 			d++;
 		} while (s < le);
 		if (s > start)
-			accel_putcs(vc, p, start, s - start,
+			p->dispsw->putcs(vc, p, start, s - start,
 					 real_y(p, line), x);
 		console_conditional_schedule();
 		if (offset > 0)
@@ -1420,9 +1285,9 @@
 			goto redraw_up;
 		switch (p->scrollmode & __SCROLL_YMASK) {
 		case __SCROLL_YMOVE:
-			accel_bmove(p, t + count, 0, t, 0,
+			p->dispsw->bmove(p, t + count, 0, t, 0,
 					 b - t - count, vc->vc_cols);
-			accel_clear(vc, p, b - count, 0, count,
+			p->dispsw->clear(vc, p, b - count, 0, count,
 					 vc->vc_cols);
 			break;
 
@@ -1471,7 +1336,7 @@
 		      redraw_up:
 			fbcon_redraw(vc, p, t, b - t - count,
 				     count * vc->vc_cols);
-			accel_clear(vc, p, real_y(p, b - count), 0,
+			p->dispsw->clear(vc, p, real_y(p, b - count), 0,
 					 count, vc->vc_cols);
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
@@ -1487,9 +1352,9 @@
 			count = vc->vc_rows;
 		switch (p->scrollmode & __SCROLL_YMASK) {
 		case __SCROLL_YMOVE:
-			accel_bmove(p, t, 0, t + count, 0,
+			p->dispsw->bmove(p, t, 0, t + count, 0,
 					 b - t - count, vc->vc_cols);
-			accel_clear(vc, p, t, 0, count, vc->vc_cols);
+			p->dispsw->clear(vc, p, t, 0, count, vc->vc_cols);
 			break;
 
 		case __SCROLL_YWRAP:
@@ -1536,7 +1401,7 @@
 		      redraw_down:
 			fbcon_redraw(vc, p, b - 1, b - t - count,
 				     -count * vc->vc_cols);
-			accel_clear(vc, p, real_y(p, t), 0, count,
+			p->dispsw->clear(vc, p, real_y(p, t), 0, count,
 					 vc->vc_cols);
 			scr_memsetw((unsigned short *) (vc->vc_origin +
 							vc->vc_size_row *
@@ -1615,7 +1480,7 @@
 		}
 		return;
 	}
-	accel_bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height,
+	p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height,
 			 width);
 }
 
@@ -1643,8 +1508,8 @@
 		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
 		var.activate = FB_ACTIVATE_NOW;
 		fb_set_var(&var, info);
-		p->vrows = info->var.yres_virtual/fh;
 	}
+	p->vrows = info->var.yres_virtual/fh;
 	return 0;
 }
 
@@ -1654,6 +1519,13 @@
 	struct display *p = &fb_display[unit];
 	struct fb_info *info = p->fb_info;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops)
+		p->dispsw = &tile_switch;
+	else
+#endif
+		p->dispsw = &accel_switch;
+
 	if (softback_top) {
 		int l = fbcon_softback_size / vc->vc_size_row;
 		if (softback_lines)
@@ -1679,6 +1551,9 @@
 	}
 	if (info)
 		info->var.yoffset = p->yscroll = 0;
+
+        fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
+
 	switch (p->scrollmode & __SCROLL_YMASK) {
 	case __SCROLL_YWRAP:
 		scrollback_phys_max = p->vrows - vc->vc_rows;
@@ -1695,14 +1570,39 @@
 	scrollback_max = 0;
 	scrollback_current = 0;
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops) {
+		struct fb_tiledata tile;
+		int err, cnt, size;
+		u8 *tiledata;
+
+		cnt = FNTCHARCNT(p->fontdata);
+		if (!cnt)
+			cnt = 256;
+		size = vc->vc_font.height * ((vc->vc_font.width + 7)/8) * cnt; 
+		tiledata = kmalloc(size, GFP_KERNEL);
+		if (tiledata == NULL)
+			return 0;
+		memcpy(tiledata, p->fontdata, size);
+		tile.tile.width = vc->vc_font.width;
+		tile.tile.height = vc->vc_font.height;
+		tile.tile.depth = 1;
+		tile.len = cnt;
+		tile.data = tiledata; 
+		err = info->tileops->fb_loadtiles(info, &tile);
+		kfree(tiledata);
+
+		if (err) return 0;
+	}
+#endif
+
 	info->currcon = unit;
 	
-        fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
 	update_var(unit, info);
 	fbcon_set_palette(vc, color_table); 	
 
 	if (vt_cons[unit]->vc_mode == KD_TEXT)
-		accel_clear_margins(vc, p, 0);
+		p->dispsw->clear_margins(vc, p, 0);
 	if (logo_shown == -2) {
 		logo_shown = fg_console;
 		/* This is protected above by initmem_freed */
@@ -1737,18 +1637,18 @@
 			height = vc->vc_rows;
 			y_break = p->vrows - p->yscroll;
 			if (height > y_break) {
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p, 0), 0,
 						 y_break,
 						 vc->vc_cols);
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p,
 						y_break),
 						0,
 						 height - y_break,
 						 vc->vc_cols);
 			} else
-				accel_clear(vc, p,
+				p->dispsw->clear(vc, p,
 						 real_y(p, 0), 0,
 						 height,
 						 vc->vc_cols);
@@ -1913,6 +1813,29 @@
 
 	}
 
+#ifdef CONFIG_FBCON_ADVANCED_TILEBLIT
+	if (info->tileops) {
+		struct fb_tiledata tile;
+		int err, size;
+		u8 *tiledata;
+		
+		size = vc->vc_font.height * ((vc->vc_font.width + 7)/8) * cnt; 
+		tiledata = kmalloc(size, GFP_KERNEL);
+		if (tiledata == NULL)
+			return 1;
+		memcpy(tiledata, p->fontdata, size);
+		tile.tile.width = vc->vc_font.width;
+		tile.tile.height = vc->vc_font.height;
+		tile.tile.depth = 1;
+		tile.len = cnt;
+		tile.data = tiledata;
+		
+		err = info->tileops->fb_loadtiles(info, &tile);
+		kfree(tiledata);
+		if (err) return err;
+	}
+#endif
+
 	if (resize) {
 		/* reset wrap/pan */
 		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
@@ -1935,7 +1858,7 @@
 		}
 	} else if (CON_IS_VISIBLE(vc)
 		   && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
-		accel_clear_margins(vc, p, 0);
+		p->dispsw->clear_margins(vc, p, 0);
 		update_screen(vc->vc_num);
 	}
 
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.h linux-2.5.61/drivers/video/console/fbcon.h
--- linux-2.5.61-fbdev/drivers/video/console/fbcon.h	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon.h	2003-02-23 06:45:15.000000000 +0000
@@ -46,6 +46,20 @@
     unsigned int fontwidthmask;      /* 1 at (1 << (width - 1)) if width is supported */
 };
 
+struct display_switch {
+	void (*bmove)(struct display *p, int sy, int sx, 
+		      int dy, int dx, int height, int width);
+	void (*clear)(struct vc_data *vc, struct display *p, int sy,
+		      int sx, int height, int width);
+	void (*putcs)(struct vc_data *vc, struct display *p,
+		      const unsigned short *s, int count, 
+		      int yy, int xx);
+	void (*putc)(struct vc_data *vc, struct display *p, 
+		     int c, int ypos, int xpos);
+	void (*clear_margins)(struct vc_data *vc, struct display *p,
+			      int bottom_only);
+};
+
 /* drivers/video/console/fbcon.c */
 extern struct display fb_display[MAX_NR_CONSOLES];
 extern char con2fb_map[MAX_NR_CONSOLES];
@@ -120,5 +134,7 @@
 #define SCROLL_YNOPARTIAL	__SCROLL_YNOPARTIAL
 
 extern int fb_console_init(void);
+extern struct display_switch tile_switch;
+extern struct display_switch accel_switch;
 
 #endif /* _VIDEO_FBCON_H */
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon_accelops.c linux-2.5.61/drivers/video/console/fbcon_accelops.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon_accelops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon_accelops.c	2003-02-23 07:08:50.000000000 +0000
@@ -0,0 +1,229 @@
+/*
+ *  linux/drivers/video/fbcon_defops.c -- Console Ops using Classic Blitting
+ *
+ *	Copyright (C) 2003 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include "fbcon.h"
+
+static __inline__ int real_y(struct display *p, int ypos)
+{
+	int rows = p->vrows;
+
+	ypos += p->yscroll;
+	return ypos < rows ? ypos : ypos - rows;
+}
+
+/*
+ * Accelerated handlers.
+ */
+static void accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct vc_data *vc = p->conp;
+	struct fb_copyarea area;
+
+	area.sx = sx * vc->vc_font.width;
+	area.sy = sy * vc->vc_font.height;
+	area.dx = dx * vc->vc_font.width;
+	area.dy = dy * vc->vc_font.height;
+	area.height = height * vc->vc_font.height;
+	area.width = width * vc->vc_font.width;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+static void accel_clear(struct vc_data *vc, struct display *p, int sy,
+			int sx, int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_fillrect region;
+
+	region.color = attr_bgcol_ec(p, vc);
+	region.dx = sx * vc->vc_font.width;
+	region.dy = sy * vc->vc_font.height;
+	region.width = width * vc->vc_font.width;
+	region.height = height * vc->vc_font.height;
+	region.rop = ROP_COPY;
+
+	info->fbops->fb_fillrect(info, &region);
+}	
+
+static void accel_putc(struct vc_data *vc, struct display *p,
+		       int c, int ypos, int xpos)
+{
+	struct fb_info *info = p->fb_info;
+	unsigned short charmask = p->charmask;
+	unsigned int width = ((vc->vc_font.width + 7) >> 3);
+	struct fb_image image;
+
+	image.dx = xpos * vc->vc_font.width;
+	image.dy = real_y(p, ypos) * vc->vc_font.height;
+	image.width = vc->vc_font.width;
+	image.height = vc->vc_font.height;
+	image.fg_color = attr_fgcol(p, c);
+	image.bg_color = attr_bgcol(p, c);
+	image.depth = 0;
+	image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
+
+	info->fbops->fb_imageblit(info, &image);
+}
+
+#define FB_PIXMAPSIZE 8192
+static void putcs_unaligned(struct vc_data *vc, struct display *p,
+			    struct fb_info *info, struct fb_image *image, 
+			    int count, const unsigned short *s)
+{
+	unsigned int width = (vc->vc_font.width + 7)/8;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
+	unsigned int pitch, cnt, i, j, k;
+	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+	unsigned int shift_high = 8;
+	unsigned int idx = vc->vc_font.width/8;
+	unsigned short charmask = p->charmask;
+	u8 mask, *src, *dst, *dst0;
+	
+	while (count) {
+		if (count > maxcnt) 
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		
+		dst0 = (u8 *) image->data;
+		image->width = vc->vc_font.width * cnt;
+		pitch = (image->width + 7)/8;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask) * cellsize;
+			dst = dst0;
+			mask = (u8) (0xfff << shift_high);
+			for (i = image->height; i--; ) {
+				for (j = 0; j < idx; j++) {
+					dst[j] &= mask;
+					dst[j] |= *src >> shift_low;
+					dst[j+1] = *src << shift_high;
+					src++;
+				}
+				dst[idx] &= mask;
+				dst[idx] |= *src++ >> shift_low;
+				dst += pitch;
+			}
+			shift_low += mod;
+			shift_low &= 7;
+			shift_high = 8 - shift_low;
+			dst0 += (shift_low) ? width - 1 : width;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+static void putcs_aligned(struct vc_data *vc, struct display *p,
+			  struct fb_info *info, struct fb_image *image, 
+			  int count, const unsigned short *s)
+{
+	unsigned int width = (vc->vc_font.width + 7)/8;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
+	unsigned int pitch, cnt, i, j, k;
+	unsigned short charmask = p->charmask;
+	u8 *src, *dst, *dst0;
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		dst0 = (u8 *) image->data;
+		pitch = width *cnt;
+		image->width = vc->vc_font.width * cnt;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask) * cellsize;
+			dst = dst0;
+			for (i = image->height; i--; ) {
+				for (j = 0; j < width; j++) 
+					dst[j] = *src++;
+				dst += pitch;
+			}
+			dst0 += width;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+static void accel_putcs(struct vc_data *vc, struct display *p,
+			const unsigned short *s, int count, int yy, int xx)
+{
+	static u8 pixmap[FB_PIXMAPSIZE];
+	struct fb_info *info = p->fb_info;
+	struct fb_image image;
+	u16 c = scr_readw(s);
+	
+	image.fg_color = attr_fgcol(p, c);
+	image.bg_color = attr_bgcol(p, c);
+	image.dx = xx * vc->vc_font.width;
+	image.dy = yy * vc->vc_font.height;
+	image.height = vc->vc_font.height;
+	image.depth = 0;
+	image.data = pixmap;
+
+	if (!(vc->vc_font.width & 7)) 
+		putcs_aligned(vc, p, info, &image, count, s);
+	else 
+		putcs_unaligned(vc, p, info, &image, count, s);
+}
+
+static void accel_clear_margins(struct vc_data *vc, struct display *p,
+				int bottom_only)
+{
+	struct fb_info *info = p->fb_info;
+	unsigned int cw = vc->vc_font.width;
+	unsigned int ch = vc->vc_font.height;
+	unsigned int rw = info->var.xres % cw;
+	unsigned int bh = info->var.yres % ch;
+	unsigned int rs = info->var.xres - rw;
+	unsigned int bs = info->var.yres - bh;
+	struct fb_fillrect region;
+
+	region.color = attr_bgcol_ec(p, vc);
+	region.rop = ROP_COPY;
+
+	if (rw & !bottom_only) {
+		region.dx = info->var.xoffset + rs;
+		region.dy = 0;
+		region.width = rw;
+		region.height = info->var.yres_virtual;
+		info->fbops->fb_fillrect(info, &region);
+	}
+
+	if (bh) {
+		region.dx = info->var.xoffset;
+		region.dy = info->var.yoffset + bs;
+		region.width = rs;
+		region.height = bh;
+		info->fbops->fb_fillrect(info, &region);
+	}	
+}	
+
+struct display_switch accel_switch = {
+	.bmove =         accel_bmove,
+	.clear =         accel_clear,
+	.putc =          accel_putc,
+	.putcs =         accel_putcs,
+	.clear_margins = accel_clear_margins,
+};
+
+EXPORT_SYMBOL(accel_switch);
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon_tileops.c linux-2.5.61/drivers/video/console/fbcon_tileops.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon_tileops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.5.61/drivers/video/console/fbcon_tileops.c	2003-02-23 06:42:26.000000000 +0000
@@ -0,0 +1,118 @@
+/*
+ *  linux/drivers/video/fbcon_tileops.c -- Console Ops using Tile Blitting
+ *                                         (ie. Text Mode support)
+ *
+ *	Copyright (C) 2003 James Simmons
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include "fbcon.h"
+
+static void tile_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		       int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tilecopy tilerect;
+
+	tilerect.sx = sx;
+	tilerect.sy = sy;
+	tilerect.dx = dx;
+	tilerect.dy = dy;
+	tilerect.height = height;
+	tilerect.width = width;
+	
+	info->tileops->fb_tilecopy(info, &tilerect);
+}
+
+static void tile_clear(struct vc_data *vc, struct display *p, int sy,
+		       int sx, int height, int width)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tilefill tilerect;
+	
+	tilerect.dx = sx;
+	tilerect.dy = sy;
+	tilerect.width = width;
+	tilerect.height = height;
+	tilerect.fg_color = attr_fgcol_ec(p, vc);
+	tilerect.bg_color = attr_bgcol_ec(p, vc);
+	tilerect.idx = vc->vc_video_erase_char & p->charmask;
+	tilerect.rop = ROP_COPY;
+
+	info->tileops->fb_tilefill(info, &tilerect);
+}
+
+static void tile_putc(struct vc_data *vc, struct display *p,
+		      int c, int ypos, int xpos)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_tileblit tilerect;
+	u32 font = c & p->charmask;
+	
+	tilerect.dx = xpos;
+	tilerect.dy = ypos;
+	tilerect.width = 1;
+	tilerect.height = 1;
+	tilerect.fg_color = attr_fgcol(p, c);
+	tilerect.bg_color = attr_bgcol(p, c);
+	tilerect.data = &font;
+
+	info->tileops->fb_tileblit(info, &tilerect);
+}
+
+#define TILEMAP_SIZE 1024
+static void tile_putcs(struct vc_data *vc, struct display *p,
+			const unsigned short *s, int count, 
+			int yy, int xx)
+{
+	static u32 tilemap[TILEMAP_SIZE];
+	struct fb_info *info = p->fb_info;
+	struct fb_tileblit tilerect;
+	int maxcnt = TILEMAP_SIZE, i, cnt;
+	u16 c = scr_readw(s);
+
+	tilerect.dx = xx;
+	tilerect.dy = yy;
+	tilerect.height = 1;
+	tilerect.fg_color = attr_fgcol(p, c);
+	tilerect.bg_color = attr_bgcol(p, c);
+	tilerect.data = tilemap;
+
+	while (count) {
+		cnt = (count > maxcnt) ? maxcnt : count;
+		tilerect.width = cnt;
+		for (i = 0; i < cnt; i++) 
+			tilemap[i] = (u32) (scr_readw(s++) & p->charmask);
+		
+		info->tileops->fb_tileblit(info, &tilerect);
+		tilerect.dx += cnt;
+		count -= cnt;
+	}
+}
+
+static void tile_clear_margins(struct vc_data *vc, struct display *p,
+			       int bottom_only)
+{
+	/* Not used */
+	return;
+}
+
+struct display_switch tile_switch = {
+	.bmove =         tile_bmove,
+	.clear =         tile_clear,
+	.putc  =         tile_putc,
+	.putcs =         tile_putcs,
+	.clear_margins = tile_clear_margins,
+};
+
+EXPORT_SYMBOL(tile_switch);
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>, "
+	      "Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Tile Blitting Ops");
+MODULE_LICENSE("GPL");
diff -Naur linux-2.5.61-fbdev/drivers/video/fbmem.c linux-2.5.61/drivers/video/fbmem.c
--- linux-2.5.61-fbdev/drivers/video/fbmem.c	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/drivers/video/fbmem.c	2003-02-23 06:42:26.000000000 +0000
@@ -363,14 +363,14 @@
 static int ofonly __initdata = 0;
 #endif
 
+#ifdef CONFIG_LOGO
+#include <linux/linux_logo.h>
+
 static inline unsigned safe_shift(unsigned d, int n)
 {
 	return n < 0 ? d >> -n : d << n;
 }
 
-#ifdef CONFIG_FB_LOGO
-#include <linux/linux_logo.h>
-
 static void __init fb_set_logocmap(struct fb_info *info,
 				   const struct linux_logo *logo)
 {
diff -Naur linux-2.5.61-fbdev/include/linux/fb.h linux-2.5.61/include/linux/fb.h
--- linux-2.5.61-fbdev/include/linux/fb.h	2003-02-22 02:34:26.000000000 +0000
+++ linux-2.5.61/include/linux/fb.h	2003-02-23 06:42:26.000000000 +0000
@@ -380,6 +380,77 @@
     int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
 };
 
+/* 
+ * Tile Blitting Support
+ * 
+ * In Tile Blitting, the basic unit is a Tile which is a bitmap with
+ * a predefined width and height, and optionally, other properties
+ * such as color depth, spacing, transparency,  etc.  For now, we'll 
+ * just support width, height, and color depth.
+ * 
+ * All operations are analogous to classic blitting operations which
+ * use pixels as the basic unit.  Instead of pixels, it will use tiles,
+ * instead of info->pseudo_palette, it will use tiledata, etc.
+ */
+
+struct fb_tile {
+	__u32 width;            /* tile width in pixels */
+	__u32 height;           /* tile height in scanlines */
+	__u32 depth;            /* pixel depth */
+};
+
+struct fb_tiledata {
+	struct fb_tile tile;    /* tile properties */
+	__u32 len;              /* number of tiles in the map */
+	__u8  *data;            /* packed tile data */
+};
+
+struct fb_tileblit {
+	__u32 dx;               /* destination x origin, in tiles */
+	__u32 dy;               /* destination y origin, in tiles */
+	__u32 width;            /* destination window width, in tiles */
+	__u32 height;           /* destination window height, in tiles */
+	__u32 fg_color;         /* fg_color if monochrome */
+	__u32 bg_color;         /* bg_color if monochrome */
+	__u32 *data;            /* tile map - array of indices to tiledata */
+};
+
+struct fb_tilecopy {
+	__u32 dx;               /* destination window origin... */
+	__u32 dy;               /* in tiles */
+	__u32 width;            /* destination width, in tiles */
+	__u32 height;           /* destination height, in tiles */
+	__u32 sx;               /* source window origin ... */
+	__u32 sy;               /* in tiles */
+};
+
+struct fb_tilefill {
+	__u32 dx;               /* destination window origin ... */
+	__u32 dy;               /* in tiles */
+	__u32 width;            /* destination width in tiles */
+	__u32 height;           /* destination height in tiles */
+	__u32 fg_color;         /* fg_color if monochrome */
+	__u32 bg_color;         /* bg_color if monochrome */
+	__u32 rop;              /* rop operation */
+	__u32 idx;              /* index to current tiledata */
+};
+
+struct fb_tileops {
+    /* upload tile data to driver and make it current... the driver
+     * must copy the contents of tiledata.data, not just the pointer to it */
+    int (*fb_loadtiles)(struct fb_info *info, 
+			const struct fb_tiledata *tileinfo);
+    /* blit tiles to destination from a tilemap */
+    void (*fb_tileblit)(struct fb_info *info, 
+			const struct fb_tileblit *tilemap);
+    /* copy tiles from one region of fb memory to another */
+    void (*fb_tilecopy)(struct fb_info *info, const struct fb_tilecopy *area);
+    /* fill a region of fb memory with a tile */
+    void (*fb_tilefill)(struct fb_info *info, 
+			const struct fb_tilefill *region);
+    /* If driver is to support tile blitting, all hooks above are required */
+};
+
 struct fb_info {
    kdev_t node;
    int flags;
@@ -391,6 +462,7 @@
    struct fb_cursor cursor;		/* Current cursor */	
    struct fb_cmap cmap;                 /* Current cmap */
    struct fb_ops *fbops;
+   struct fb_tileops *tileops;          /* Tile blitting */
    char *screen_base;                   /* Virtual address */
    struct vc_data *display_fg;		/* Console visible on this display */
    int currcon;				/* Current VC. */	

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-23  7:43 ` Antonino Daplas
@ 2003-02-23 11:07   ` Antonino Daplas
  2003-02-26 20:11     ` James Simmons
  0 siblings, 1 reply; 12+ messages in thread
From: Antonino Daplas @ 2003-02-23 11:07 UTC (permalink / raw)
  To: Antonino Daplas; +Cc: James Simmons, Linux Fbdev development list

On Sun, 2003-02-23 at 15:43, Antonino Daplas wrote:
> On Sun, 2003-02-23 at 12:42, Antonino Daplas wrote:
> 
> > Here's an updated Tile Blitting patch.  The feature is selectable via
> > kernel configuration (under Advanced Low Level Driver Features). 
> > Currently, it detects the presence of info->tileops but bit setting
> > info->caps should be better.
> 
> Stupid me :-(, the patch does not work properly.  Try this one instead.
> 

The optimization logic is flawed :-(  Please apply this patch also.

Tony

diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon_accelops.c linux-2.5.61/drivers/video/console/fbcon_accelops.c
--- linux-2.5.61-fbdev/drivers/video/console/fbcon_accelops.c	2003-02-23 18:47:53.000000000 +0800
+++ linux-2.5.61/drivers/video/console/fbcon_accelops.c	2003-02-23 18:52:23.000000000 +0800
@@ -113,13 +113,16 @@
 					src++;
 				}
 				dst[idx] &= mask;
-				dst[idx] |= *src++ >> shift_low;
+				dst[idx] |= *src >> shift_low;
+ 				if (shift_high < mod)
+					dst[idx+1] = *src << shift_high;
+				src++;
 				dst += pitch;
 			}
 			shift_low += mod;
+			dst0 += (shift_low >= 8) ? width : width - 1;
 			shift_low &= 7;
 			shift_high = 8 - shift_low;
-			dst0 += (shift_low) ? width - 1 : width;
 		}
 		
 		info->fbops->fb_imageblit(info, image);



-------------------------------------------------------
This SF.net email is sponsored by: SlickEdit Inc. Develop an edge.
The most comprehensive and flexible code editor you can use.
Code faster. C/C++, C#, Java, HTML, XML, many more. FREE 30-Day Trial.
www.slickedit.com/sourceforge

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-23 11:07   ` Antonino Daplas
@ 2003-02-26 20:11     ` James Simmons
  2003-02-27  0:35       ` Antonino Daplas
  0 siblings, 1 reply; 12+ messages in thread
From: James Simmons @ 2003-02-26 20:11 UTC (permalink / raw)
  To: Antonino Daplas; +Cc: Linux Fbdev development list


Boy this has been tricky to handle. I have been thinking about how to 
handle image blitting from normal memory to texture mappings to tiles.
Then after that I have to make it abstract to fit all these models. 
Pretty much I have come to the conclusion that we have two models.

Model 1: Consistent mappings. 

	In this model we allocate one time a buffer to store image data.
	The fbcon classic is loadfont. It could also be creating texures
	and saving it in a permentant texture map buffer that is present 
        on the card. Same for tiles. We create a bunch of tiles and save 
        them somewhere. We then use a index of some kind later to draw 
	the image.

Model 2: Streaming mappings. 

	This model has us create a temporary memory pool to store data 
	then draw it. After drawing is complete we release the memory. 
	

As you can see the standard imageblit function falls into model 2. At 
present we allocate a static buffer :-( Now for a PCI DMA based card we 
want a hook to allocate a chunck of memory via pci_alloc_consittent. To 
free the memory we use pci_free_consistent. Also for AGP there could be 
hooks just for it. So model 2 can be broken into 2 parts.

A) Memory mangement. We first allocate the memory needed. After drawing
   the image free the memory.

B) Draw the image. This occurs between the two events in A.


Now for model 1. A example would be the matrox fbdev driver for fast 
fonts. We allocate a region to store the font images before using them.
This buffer is pretty much permanent. Then we use indices to tell which
section of the allocated buffer to have the graphics engine use. 


So this is the model I have come up with. The tricky part I haven't 
figured out yet is working with irqs and how to relate fbcon with it. 
Comments?




-------------------------------------------------------
This SF.net email is sponsored by: Scholarships for Techies!
Can't afford IT training? All 2003 ictp students receive scholarships.
Get hands-on training in Microsoft, Cisco, Sun, Linux/UNIX, and more.
www.ictp.com/training/sourceforge.asp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-26 20:11     ` James Simmons
@ 2003-02-27  0:35       ` Antonino Daplas
  2003-02-27  1:18         ` James Simmons
  0 siblings, 1 reply; 12+ messages in thread
From: Antonino Daplas @ 2003-02-27  0:35 UTC (permalink / raw)
  To: James Simmons; +Cc: Linux Fbdev development list

On Thu, 2003-02-27 at 04:11, James Simmons wrote:
> 
> Boy this has been tricky to handle. I have been thinking about how to 
> handle image blitting from normal memory to texture mappings to tiles.
> Then after that I have to make it abstract to fit all these models. 
> Pretty much I have come to the conclusion that we have two models.
> 
> Model 1: Consistent mappings. 
> 
> 	In this model we allocate one time a buffer to store image data.
> 	The fbcon classic is loadfont. It could also be creating texures
> 	and saving it in a permentant texture map buffer that is present 
>         on the card. Same for tiles. We create a bunch of tiles and save 
>         them somewhere. We then use a index of some kind later to draw 
> 	the image.
> 
> Model 2: Streaming mappings. 
> 
> 	This model has us create a temporary memory pool to store data 
> 	then draw it. After drawing is complete we release the memory. 
> 	
> 
> As you can see the standard imageblit function falls into model 2. At 
> present we allocate a static buffer :-( Now for a PCI DMA based card we 
> want a hook to allocate a chunck of memory via pci_alloc_consittent. To 
> free the memory we use pci_free_consistent. Also for AGP there could be 
> hooks just for it. So model 2 can be broken into 2 parts.
> 
> A) Memory mangement. We first allocate the memory needed. After drawing
>    the image free the memory.
> 
> B) Draw the image. This occurs between the two events in A.
> 

For model 2, do we have to allocate/deallocate per iteration?  First, we
are not dealing with large-sized bitmaps here (a single character at
most will have 64 bytes).  Secondly, we cannot deallocate the memory
until the GPU is done rendering.  This means we have to synchronize for
each imageblit, further slowing it down.  Modern GPU's have deep
pipelines, let's take advantage of it.

So, how about letting the driver allocate the memory for us, and this
will last throughout the lifetime of the driver?  This also becomes a
consistent mapping.  The main difference is, we treat this memory as a a
ringbuffer, ie:

Memory is at address p, size N. 

The first bitmap, in terms of time of arrival, (bitmap1) will be at 'p',
bitmap2 at 'p+size1', bitmap 3 at 'p+size1+size2' and so on and so
forth.  Once fbcon reaches the end of the buffer, 'p+N', it calls
fb_sync() and start all over again, at 'p'.

The advantages of the above are:

	1. no need to allocate/deallocate memory which is disproportionately
more expansive relative to the bitmap sizes fbcon is dealing with.

	2. no chance of memory becoming unavailable during
memory-starved/emergency states.

	3. the whole process is very fast and asynchronous.  The GPU can be
rendering, while the CPU is preparing the bitmap.  The only time fbcon
synchronizes is during the "wrap-around".

This is actually the initial patch that I submitted to you months ago,
but you rejected it.  That's why I came up with the simpler
implementation (statically allocated buffer).  As Geert and DaveM has
mentioned to me, the current implementation might not be thread-safe
(although I see more of a concurrency problem between CPU and GPU).
Thus, the restriction that the buffer must be completely copied by the
driver before returning.  And because of this restriction, an extra copy
which might be unnecessary cannot be avoided (this was noted by Petr).

Treating the buffer as a ringbuffer, we eliminate these restrictions.

So:

struct fb_pixmap {
	__u8 *addr;
	__u32 size;
	__u32 tail;
	__u32 buf_align;
	__u32 scan_align;
	__u32 flags;
}

a. addr - pointer to memory

b. tail - this is the current offset to the buffer

c. buf_align - start alignment per bitmap

d. scan_align - alignment for each scanline, cfb_imageblit requires 1,
i810fb, 2, rivafb and tgafb(?) 4. 

e. flags = location of buffer (system or graphics/pci/dma) so fbcon can
choose how to access the memory.

The structure is prepared by the driver at initialization. If it chooses
not too, addr should be NULL and fbcon will just allocate memory for it,
and use default values (size = 8K, buf_align = 1, scan_align = 1, flags
= system).

Tony



-------------------------------------------------------
This SF.net email is sponsored by: Scholarships for Techies!
Can't afford IT training? All 2003 ictp students receive scholarships.
Get hands-on training in Microsoft, Cisco, Sun, Linux/UNIX, and more.
www.ictp.com/training/sourceforge.asp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27  0:35       ` Antonino Daplas
@ 2003-02-27  1:18         ` James Simmons
  2003-02-27 14:15           ` Antonino Daplas
  0 siblings, 1 reply; 12+ messages in thread
From: James Simmons @ 2003-02-27  1:18 UTC (permalink / raw)
  To: Antonino Daplas; +Cc: Linux Fbdev development list


> For model 2, do we have to allocate/deallocate per iteration?  

I'm looking at the streaming DMA model used by filesystem buffers being 
written/read by a SCSI device. You are right tho. If you use pci_dma_sync 
then you don't need to create and remove the mappings. The question is 
there any hardware to limited where we have to create/destory mapping 
constantly? 

> Secondly, we cannot deallocate the memory
> until the GPU is done rendering.  This means we have to synchronize for
> each imageblit, further slowing it down.  Modern GPU's have deep
> pipelines, let's take advantage of it.

Okay good point.
 
> So, how about letting the driver allocate the memory for us, and this
> will last throughout the lifetime of the driver?  This also becomes a
> consistent mapping.  The main difference is, we treat this memory as a a
> ringbuffer, ie:
> 
> Memory is at address p, size N. 
> 
> The first bitmap, in terms of time of arrival, (bitmap1) will be at 'p',
> bitmap2 at 'p+size1', bitmap 3 at 'p+size1+size2' and so on and so
> forth.  Once fbcon reaches the end of the buffer, 'p+N', it calls
> fb_sync() and start all over again, at 'p'.
> 
> The advantages of the above are:
> 
> 	1. no need to allocate/deallocate memory which is disproportionately
> more expansive relative to the bitmap sizes fbcon is dealing with.
> 
> 	2. no chance of memory becoming unavailable during
> memory-starved/emergency states.

Very good. 

> 	3. the whole process is very fast and asynchronous.  The GPU can be
> rendering, while the CPU is preparing the bitmap.  The only time fbcon
> synchronizes is during the "wrap-around".

> This is actually the initial patch that I submitted to you months ago,
> but you rejected it.  

Well I was wrong :-( I rejected because I was hoping to keep the api 
object orientated (rectangle and bitmap/pixmaps). Now I see that without 
this kind of solution we end up with a bigger mess. I admit I made the 
wrong judgement call on this. 

> As Geert and DaveM has
> mentioned to me, the current implementation might not be thread-safe
> (although I see more of a concurrency problem between CPU and GPU).

I agree I see more of a problem with CPU GPU syncing issue. I do have a 
fix in BK with allocating and deallocating continuely but it is the wrong
approach.

> Thus, the restriction that the buffer must be completely copied by the
> driver before returning.  And because of this restriction, an extra copy
> which might be unnecessary cannot be avoided (this was noted by Petr).
> 
> Treating the buffer as a ringbuffer, we eliminate these restrictions.

I didn't realize that the below was a ringbuffer implementation. The name
threw me off. 

> So:
> 
> struct fb_pixmap {
> 	__u8 *addr;
> 	__u32 size;
> 	__u32 tail;
> 	__u32 buf_align;
> 	__u32 scan_align;
> 	__u32 flags;
> }
> 
> a. addr - pointer to memory
> 
> b. tail - this is the current offset to the buffer
> 
> c. buf_align - start alignment per bitmap
> 
> d. scan_align - alignment for each scanline, cfb_imageblit requires 1,
> i810fb, 2, rivafb and tgafb(?) 4. 
> 
> e. flags = location of buffer (system or graphics/pci/dma) so fbcon can
> choose how to access the memory.
> 
> The structure is prepared by the driver at initialization. If it chooses
> not too, addr should be NULL and fbcon will just allocate memory for it,
> and use default values (size = 8K, buf_align = 1, scan_align = 1, flags
> = system).

Do you still have the original patch?



-------------------------------------------------------
This SF.net email is sponsored by: Scholarships for Techies!
Can't afford IT training? All 2003 ictp students receive scholarships.
Get hands-on training in Microsoft, Cisco, Sun, Linux/UNIX, and more.
www.ictp.com/training/sourceforge.asp

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27  1:18         ` James Simmons
@ 2003-02-27 14:15           ` Antonino Daplas
  2003-02-27 18:25             ` Michel Dänzer
  0 siblings, 1 reply; 12+ messages in thread
From: Antonino Daplas @ 2003-02-27 14:15 UTC (permalink / raw)
  To: James Simmons; +Cc: Linux Fbdev development list

[-- Attachment #1: Type: text/plain, Size: 3071 bytes --]

On Thu, 2003-02-27 at 09:18, James Simmons wrote:
> > As Geert and DaveM has
> > mentioned to me, the current implementation might not be thread-safe
> > (although I see more of a concurrency problem between CPU and GPU).
> 
> I agree I see more of a problem with CPU GPU syncing issue. I do have a 
> fix in BK with allocating and deallocating continuely but it is the wrong
> approach.
> 

We can avoid concurrency problems by assigning different sections of the
buffer per call to fb_imageblit(). There is really no need to map/unmap
or allocate/deallocate buffers unless you do not trust the drivers to
behave :-).  The buffer will not be exposed to userland, unlike DRM
which has to implement "map->user access->unmap->pass to hardware".
 
> > Thus, the restriction that the buffer must be completely copied by the
> > driver before returning.  And because of this restriction, an extra copy
> > which might be unnecessary cannot be avoided (this was noted by Petr).
> > 
> > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> 
> I didn't realize that the below was a ringbuffer implementation. The name
> threw me off. 

Well, it's not strictly a ringbuffer implementation.  This would require
a head and tail pointer where fbcon will adjust the tail and the
driver/hardware will adjust the head.  This will be very difficult to
implement in a device independent manner.  So we just cheat by issuing
an fb_sync() per loop to flush all pending commands.

> 
> Do you still have the original patch?
> 

Here's a revised one. Driver's can choose to fill up the following
structure, or leave it empty:

#define FB_PIXMAP_DEFAULT 1     /* used internally by fbcon */
#define FB_PIXMAP_SYSTEM  2     /* memory is in system RAM  */
#define FB_PIXMAP_IO      4     /* memory is iomapped       */
#define FB_PIXMAP_SYNC    256   /* set if GPU can DMA       */

struct fb_pixmap {
        __u8  *addr; 
	__u32 size;  
	__u32 offset;
	__u32 buf_align; 
	__u32 scan_align; 
	__u32 flags; 
	void (*outbuf)(u8 dst, u8 *addr); 
	u8   (*inbuf) (u8 *addr);
	unsigned long lock_flags;
	spinlock_t lock; 
};

The buffer can be anywhere, system or io.  If it's in special memory
(ie, offscreen graphics), access methods must be specified (outbuf,
inbuf).  If the buffer is DMA'able by the GPU, then FB_PIXMAP_SYNC must
be set (it issues an fb_sync()), otherwise leave it cleared (ie soft
accels). The buf_align and scan_align are hardware specific.  This will
let fbcon format the bitmap into a form acceptable by the hardware.  The
modified rivafb sets the alignment according to its needs, which greatly
simplified the rivafb_imageblit() function.

The spinlock may be necessary because fbcon_cursor, which is called via
timer or interrupt, might also use fb_imageblit().  You can change it to
a more appropriate locking method if you want.

The patch should work without driver breakage.  

Diff is against linux-2.5.61 + your fbdev.diff.gz + my accel_putcs
optimization patch + Geert's logo updates.  I know you already applied
them all in your tree.

Tony
 


[-- Attachment #2: pixmap2.diff --]
[-- Type: text/x-patch, Size: 17922 bytes --]

diff -Naur linux-2.5.61/drivers/video/console/fbcon.c linux/drivers/video/console/fbcon.c
--- linux-2.5.61/drivers/video/console/fbcon.c	2003-02-27 09:28:55.000000000 +0000
+++ linux/drivers/video/console/fbcon.c	2003-02-27 11:40:39.000000000 +0000
@@ -134,6 +134,8 @@
 static int fbcon_set_origin(struct vc_data *);
 static int cursor_drawn;
 
+#define FBCON_PIXMAPSIZE 8192
+
 #define CURSOR_DRAW_DELAY		(1)
 
 /* # VBL ints between cursor state changes */
@@ -296,8 +298,191 @@
 }
 
 /*
+ * drawing helpers
+ */
+static inline void sysmove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch, 
+				       u32 s_pitch, u32 height, 
+				       struct fb_info *info)
+{
+	int i, j;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < s_pitch; j++) 
+			dst[j] = *src++;
+		dst += d_pitch;
+	}
+}
+
+static inline void iomove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch, 
+				      u32 s_pitch, u32 height,
+				      struct fb_info *info)
+{
+	int i, j;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < s_pitch; j++) 
+			info->pixmap.outbuf(*src++, dst+j);
+		dst += d_pitch;
+	}
+}
+
+static inline void sysmove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch, 
+					 u32 height, u32 mask, u32 shift_high,
+					 u32 shift_low, u32 mod, u32 idx,
+					 struct fb_info *info)
+{
+	int i, j;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < idx; j++) { 
+			dst[j] &= mask;
+			dst[j] |= *src >> shift_low;
+			dst[j+1] = *src << shift_high;
+			src++;
+		}
+		dst[idx] &= mask;
+		dst[idx] |= *src >> shift_low;
+		if (shift_high < mod)
+			dst[idx+1] = *src<<shift_high;
+		src++;
+		dst += d_pitch;
+	}
+}
+
+static inline void iomove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch, 
+					u32 height, u32 mask, u32 shift_high,
+					u32 shift_low,u32 mod, u32 idx, 
+					struct fb_info *info)
+{
+	int i, j;
+	u8 tmp;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < idx; j++) { 
+			tmp = info->pixmap.inbuf(dst+j);
+			tmp &= mask;
+			tmp |= *src >> shift_low;
+			info->pixmap.outbuf(tmp, dst+j);
+			info->pixmap.outbuf(*src << shift_high, dst+j+1);
+			src++;
+		}
+		tmp = info->pixmap.inbuf(dst+idx);
+		tmp &= mask;
+		tmp |= *src >> shift_low;
+		info->pixmap.outbuf(tmp, dst+idx);
+		if (shift_high < mod)
+			info->pixmap.outbuf(*src<<shift_high, dst+idx+1);
+		src++;
+		dst += d_pitch;
+	}
+}
+
+static void putcs_unaligned(struct vc_data *vc, struct display *p,
+			    struct fb_info *info, struct fb_image *image, 
+			    int count, const unsigned short *s)
+{
+	unsigned int width = (vc->vc_font.width + 7)/8;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = info->pixmap.size/cellsize;
+	unsigned int pitch, cnt, k;
+	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+	unsigned int shift_high = 8, size;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int idx = vc->vc_font.width/8;
+	unsigned short charmask = p->charmask;
+	u8 mask, *src, *dst, *dst0;
+	void (*move_data)(u8 *dst, u8 *src, u32 d_pitch, u32 height, u32 mask,
+			  u32 shift_high, u32 shift_low, u32 mod, u32 idx, 
+			  struct fb_info *info);
+	
+	if (info->pixmap.outbuf != NULL)
+		move_data = iomove_buf_unaligned;
+	else
+		move_data = sysmove_buf_unaligned;
+
+	while (count) {
+		if (count > maxcnt) 
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		
+		image->width = vc->vc_font.width * cnt;
+		pitch = (image->width + 7)/8 + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * vc->vc_font.height + buf_align;
+		size &= ~buf_align;
+		dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+		image->data = dst0;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask)*
+				cellsize;
+			dst = dst0;
+			mask = (u8) (0xfff << shift_high);
+			move_data(dst, src, pitch, image->height, mask,
+				  shift_high, shift_low, mod, idx, info);
+			shift_low += mod;
+			dst0 += (shift_low >= 8) ? width : width - 1;
+			shift_low &= 7;
+			shift_high = 8 - shift_low;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+static void putcs_aligned(struct vc_data *vc, struct display *p,
+			  struct fb_info *info, struct fb_image *image, 
+			  int count, const unsigned short *s)
+{
+	unsigned int width = vc->vc_font.width/8;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = info->pixmap.size/cellsize;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int pitch, cnt, size, k;
+	unsigned short charmask = p->charmask;
+	void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch, 
+			  u32 height, struct fb_info *info);
+	u8 *src, *dst, *dst0;
+
+	if (info->pixmap.outbuf != NULL)
+		move_data = iomove_buf_aligned;
+	else
+		move_data = sysmove_buf_aligned;
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+		pitch = width * cnt + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * vc->vc_font.height + buf_align;
+		size &= ~buf_align;
+		image->width = vc->vc_font.width * cnt;
+		dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+		image->data = dst0;
+		while (k--) {
+			src = p->fontdata + (scr_readw(s++) & charmask)*
+				cellsize;
+			dst = dst0;
+			move_data(dst, src, pitch, width, image->height, info);
+			dst0 += width;
+		}
+		
+		info->fbops->fb_imageblit(info, image);
+		image->dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+}
+
+/*
  * Accelerated handlers.
  */
+
 void accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
 			int height, int width)
 {
@@ -331,22 +516,52 @@
 	info->fbops->fb_fillrect(info, &region);
 }	
 
-#define FB_PIXMAPSIZE 8192
-/*
- * FIXME: Break up this function, it's becoming too long...
- */        
-void accel_putcs(struct vc_data *vc, struct display *p,
-			const unsigned short *s, int count, int yy, int xx)
+static void accel_putc(struct vc_data *vc, struct display *p,
+		       int c, int ypos, int xpos)
 {
-	static u8 pixmap[FB_PIXMAPSIZE];
 	struct fb_image image;
 	struct fb_info *info = p->fb_info;
 	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7)/8);
-	unsigned int cellsize = vc->vc_font.height * width;
-	unsigned int pitch, cnt, i, j, k;
-	unsigned int maxcnt = FB_PIXMAPSIZE/cellsize;
-	u8 *src, *dst, *dst0;
+	unsigned int width = (vc->vc_font.width + 7)/8;
+	unsigned int size, pitch;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch, 
+			  u32 height, struct fb_info *info);
+	u8 *src, *dst;
+
+	if (info->pixmap.outbuf != NULL)
+		move_data = iomove_buf_aligned;
+	else
+		move_data = sysmove_buf_aligned;
+
+	image.dx = xpos * vc->vc_font.width;
+	image.dy = ypos * vc->vc_font.height;
+	image.width = vc->vc_font.width;
+	image.height = vc->vc_font.height;
+	image.fg_color = attr_fgcol(p, c);
+	image.bg_color = attr_bgcol(p, c);
+	image.depth = 0;
+
+	pitch = width + scan_align;
+	pitch &= ~scan_align;
+	size = pitch * vc->vc_font.height;
+	size += buf_align;
+	size &= ~buf_align;
+	dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+	image.data = dst;
+	src = p->fontdata + (c & charmask) * vc->vc_font.height * width;
+
+	move_data(dst, src, pitch, width, image.height, info);
+
+	info->fbops->fb_imageblit(info, &image);
+}
+
+void accel_putcs(struct vc_data *vc, struct display *p,
+			const unsigned short *s, int count, int yy, int xx)
+{
+	struct fb_info *info = p->fb_info;
+	struct fb_image image;
 	u16 c = scr_readw(s);
 	
 	image.fg_color = attr_fgcol(p, c);
@@ -355,80 +570,11 @@
 	image.dy = yy * vc->vc_font.height;
 	image.height = vc->vc_font.height;
 	image.depth = 0;
-	image.data = pixmap;
 
-	if (!(vc->vc_font.width & 7)) {
-		while (count) {
-			if (count > maxcnt) 
-				cnt = k = maxcnt;
-			else
-				cnt = k = count;
-			
-			dst0 = pixmap;
-			pitch = width * cnt;
-			image.width = vc->vc_font.width * cnt;
-			while (k--) {
-				src = p->fontdata + (scr_readw(s++)&charmask)*
-					cellsize;
-				dst = dst0;
-				for (i = image.height; i--; ) {
-					for (j = 0; j < width; j++) 
-						dst[j] = *src++;
-					dst += pitch;
-				}
-				dst0 += width;
-			}
-
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += cnt * vc->vc_font.width;
-			count -= cnt;
-		}
-		
-	} else {
-		unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
-		unsigned int shift_high = 8;
-		unsigned idx = vc->vc_font.width/8;
-		u8 mask;
-
-		while (count) {
-			if (count > maxcnt) 
-				cnt = k = maxcnt;
-			else
-				cnt = k = count;
-			
-			dst0 = pixmap;
-			image.width = vc->vc_font.width * cnt;
-			pitch = (image.width + 7)/8;
-			while (k--) {
-				src = p->fontdata + (scr_readw(s++)&charmask)* 
-					cellsize;
-				dst = dst0;
-				mask = (u8) (0xfff << shift_high);
-				for (i = image.height; i--; ) {
-					for (j = 0; j < idx; j++) {
-						dst[j] &= mask;
-						dst[j] |= *src >> shift_low;
-						dst[j+1] = *src << shift_high;
-						src++;
-					}
-					dst[idx] &= mask;
-					dst[idx] |= *src >> shift_low;
-					if (shift_high < mod)
-						dst[idx+1] = *src << shift_high;
-					src++;
-					dst += pitch;
-				}
-				shift_low += mod;
-				dst0 += (shift_low >= 8) ? width : width - 1;
-				shift_low &= 7;
-				shift_high = 8 - shift_low;
-			}
-			
-			info->fbops->fb_imageblit(info, &image);
-			image.dx += cnt * vc->vc_font.width;
-			count -= cnt;
-		}
-	}
+	if (!(vc->vc_font.width & 7)) 
+		putcs_aligned(vc, p, info, &image, count, s);
+	else 
+		putcs_unaligned(vc, p, info, &image, count, s);
 }
 
 void accel_clear_margins(struct vc_data *vc, struct display *p,
@@ -633,6 +779,18 @@
 	vc->vc_cols = info->var.xres/vc->vc_font.width;
 	vc->vc_rows = info->var.yres/vc->vc_font.height;
 	
+	if (info->pixmap.addr == NULL) {
+		info->pixmap.addr = kmalloc(FBCON_PIXMAPSIZE, GFP_KERNEL);
+		if (!info->pixmap.addr)
+			return NULL;
+		info->pixmap.size = FBCON_PIXMAPSIZE;
+		info->pixmap.buf_align = 1;
+		info->pixmap.scan_align = 1;
+		info->pixmap.flags = FB_PIXMAP_DEFAULT;
+	}
+	info->pixmap.offset = 0;
+	spin_lock_init(&info->pixmap.lock);
+
 	/* We trust the mode the driver supplies. */
 	if (info->fbops->fb_set_par)
 		info->fbops->fb_set_par(info);
@@ -1030,10 +1188,6 @@
 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
 {
 	struct display *p = &fb_display[vc->vc_num];
-	struct fb_info *info = p->fb_info;
-	unsigned short charmask = p->charmask;
-	unsigned int width = ((vc->vc_font.width + 7) >> 3);
-	struct fb_image image;
 	int redraw_cursor = 0;
 
 	if (!p->can_soft_blank && console_blanked)
@@ -1047,16 +1201,7 @@
 		redraw_cursor = 1;
 	}
 
-	image.fg_color = attr_fgcol(p, c);
-	image.bg_color = attr_bgcol(p, c);
-	image.dx = xpos * vc->vc_font.width;
-	image.dy = real_y(p, ypos) * vc->vc_font.height;
-	image.width = vc->vc_font.width;
-	image.height = vc->vc_font.height;
-	image.depth = 1;
-	image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
-
-	info->fbops->fb_imageblit(info, &image);
+	accel_putc(vc, p, c, real_y(p, ypos), xpos);
 
 	if (redraw_cursor)
 		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
diff -Naur linux-2.5.61/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- linux-2.5.61/drivers/video/fbmem.c	2003-02-27 09:28:25.000000000 +0000
+++ linux/drivers/video/fbmem.c	2003-02-27 14:11:03.000000000 +0000
@@ -368,6 +368,31 @@
 	return n < 0 ? d >> -n : d << n;
 }
 
+/*
+ * we need to lock this section since fbcon_cursor
+ * may use fb_imageblit()
+ */
+u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
+{
+	u32 align = info->pixmap.buf_align - 1;
+	u32 offset;
+
+	spin_lock_irqsave(&info->pixmap.lock,
+			  info->pixmap.lock_flags);
+	offset = info->pixmap.offset + align;
+	offset &= ~align;
+	if (offset + size > info->pixmap.size) {
+		if (info->fbops->fb_sync && 
+		    info->pixmap.flags & FB_PIXMAP_SYNC)
+			info->fbops->fb_sync(info);
+		offset = 0;
+	}
+	info->pixmap.offset = offset + size;
+	spin_unlock_irqrestore(&info->pixmap.lock,
+			       info->pixmap.lock_flags);
+	return offset;
+}
+
 #ifdef CONFIG_LOGO
 #include <linux/linux_logo.h>
 
@@ -1240,5 +1265,6 @@
 EXPORT_SYMBOL(fb_set_var);
 EXPORT_SYMBOL(fb_blank);
 EXPORT_SYMBOL(fb_pan_display);
+EXPORT_SYMBOL(fb_get_buffer_offset);
 
 MODULE_LICENSE("GPL");
diff -Naur linux-2.5.61/drivers/video/softcursor.c linux/drivers/video/softcursor.c
--- linux-2.5.61/drivers/video/softcursor.c	2002-12-16 02:07:59.000000000 +0000
+++ linux/drivers/video/softcursor.c	2003-02-27 11:40:28.000000000 +0000
@@ -17,30 +17,79 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+static inline void sysmove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch, 
+			       u32 height, struct fb_info *info)
+{
+	int i, j;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < s_pitch; j++) 
+			dst[j] = *src++;
+		dst += d_pitch;
+	}
+}
+
+static inline void iomove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch, 
+			      u32 height, struct fb_info *info)
+{
+	int i, j;
+	
+	for (i = height; i--; ) {
+		for (j = 0; j < s_pitch; j++) 
+			info->pixmap.outbuf(*src++, dst+j);
+		dst += d_pitch;
+	}
+}
+
 int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-	int i, size = ((cursor->image.width + 7) / 8) * cursor->image.height;
+	static u8 src[64];
 	struct fb_image image;
-	static char data[64];
+	unsigned int i, size, s_pitch, d_pitch;
+	unsigned dsize = ((cursor->image.width + 7)/8) * cursor->image.height;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, 
+			  u32 d_pitch, u32 height,
+			  struct fb_info *info);
+	u8 *dst;
+			  
+	if (info->pixmap.outbuf != NULL)
+		move_data = iomove_buf;
+	else
+		move_data = sysmove_buf;
+
+	s_pitch = (cursor->image.width + 7)/8;
+	d_pitch = (s_pitch + scan_align) & ~scan_align;
+	size = d_pitch * cursor->image.height + buf_align;
+	size &= ~buf_align;
+	dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+	image.data = dst;
 
 	if (cursor->enable) {
 		switch (cursor->rop) {
 		case ROP_XOR:
-			for (i = 0; i < size; i++)
-				data[i] = (cursor->image.data[i] &
+			for (i = 0; i < dsize; i++) {
+				src[i] =  (cursor->image.data[i] &
 					   cursor->mask[i]) ^
-				    	   cursor->dest[i];
+					   cursor->dest[i];
+			}
 			break;
 		case ROP_COPY:
 		default:
-			for (i = 0; i < size; i++)
-				data[i] =
-				    cursor->image.data[i] & cursor->mask[i];
+			for (i = 0; i < dsize; i++) {
+				src[i] = cursor->image.data[i] &
+					 cursor->mask[i];
+			}
 			break;
 		}
-	} else
-		memcpy(data, cursor->dest, size);
-
+		move_data(dst, src, d_pitch, s_pitch, cursor->image.height, 
+			  info);
+	} else {
+		move_data(dst, cursor->dest, s_pitch, d_pitch, 
+			  cursor->image.height, info);
+	}
+	  
 	image.bg_color = cursor->image.bg_color;
 	image.fg_color = cursor->image.fg_color;
 	image.dx = cursor->image.dx;
@@ -48,7 +97,6 @@
 	image.width = cursor->image.width;
 	image.height = cursor->image.height;
 	image.depth = cursor->image.depth;
-	image.data = data;
 
 	if (info->fbops->fb_imageblit)
 		info->fbops->fb_imageblit(info, &image);
diff -Naur linux-2.5.61/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.5.61/include/linux/fb.h	2003-02-27 09:22:20.000000000 +0000
+++ linux/include/linux/fb.h	2003-02-27 11:40:08.000000000 +0000
@@ -325,6 +325,23 @@
 	struct fb_image	image;	/* Cursor image */
 };
 
+#define FB_PIXMAP_DEFAULT 1     /* used internally by fbcon */
+#define FB_PIXMAP_SYSTEM  2     /* memory is in system RAM  */
+#define FB_PIXMAP_IO      4     /* memory is iomapped       */
+#define FB_PIXMAP_SYNC    256   /* set if GPU can DMA       */
+
+struct fb_pixmap {
+        __u8  *addr;                      /* pointer to memory             */  
+	__u32 size;                       /* size of buffer in bytes       */
+	__u32 offset;                     /* current offset to buffer      */
+	__u32 buf_align;                  /* byte alignment of each bitmap */
+	__u32 scan_align;                 /* alignment per scanline        */
+	__u32 flags;                      /* see FB_PIXMAP_*               */
+	void (*outbuf)(u8 dst, u8 *addr); /* access methods                */
+	u8   (*inbuf) (u8 *addr);
+	unsigned long lock_flags;         /* flags for locking             */
+	spinlock_t lock;                  /* spinlock                      */
+};
 #ifdef __KERNEL__
 
 #include <linux/fs.h>
@@ -390,6 +407,7 @@
    struct fb_monspecs monspecs;         /* Current Monitor specs */
    struct fb_cursor cursor;		/* Current cursor */	
    struct fb_cmap cmap;                 /* Current cmap */
+   struct fb_pixmap pixmap;	        /* Current pixmap */
    struct fb_ops *fbops;
    char *screen_base;                   /* Virtual address */
    struct vc_data *display_fg;		/* Console visible on this display */
@@ -464,6 +482,7 @@
 extern int unregister_framebuffer(struct fb_info *fb_info);
 extern int fb_prepare_logo(struct fb_info *fb_info);
 extern int fb_show_logo(struct fb_info *fb_info);
+extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size);
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 

[-- Attachment #3: rivafb_pixmap.diff --]
[-- Type: text/x-patch, Size: 3719 bytes --]

diff -Naur linux-2.5.61/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
--- linux-2.5.61/drivers/video/riva/fbdev.c	2003-02-27 09:22:20.000000000 +0000
+++ linux/drivers/video/riva/fbdev.c	2003-02-27 09:49:39.000000000 +0000
@@ -1383,18 +1383,16 @@
 			     const struct fb_image *image)
 {
 	struct riva_par *par = (struct riva_par *) info->par;
-	u32 fgx = 0, bgx = 0, width, mod, tmp;
+	u32 fgx = 0, bgx = 0, width, tmp;
 	u8 *cdat = (u8 *) image->data;
 	volatile u32 *d;
-	int i, j, k, size;
+	int i, size;
 
 	if (image->depth != 0) {
-		wait_for_idle(par);
 		cfb_imageblit(info, image);
 		return;
 	}
 
-	width = (image->width + 7)/8;
 	switch (info->var.bits_per_pixel) {
 	case 8:
 		fgx = image->fg_color;
@@ -1429,49 +1427,23 @@
 
 	d = &par->riva.Bitmap->MonochromeData01E;
 
-	mod = width % 4;
-
-	if (width >= 4) {
-		k = image->height;
-		while (k--) {
-			size = width / 4;
-			while (size >= 16) {
-				RIVA_FIFO_FREE(par->riva, Bitmap, 16);
-				for (i = 0; i < 16; i++) {
-					tmp = *((u32 *)cdat)++;
-					reverse_order(&tmp);
-					d[i] = tmp;
-				}
-				size -= 16;
-			}
-
-			if (size) {
-				RIVA_FIFO_FREE(par->riva, Bitmap, size);
-				for (i = 0; i < size; i++) {
-					tmp = *((u32 *) cdat)++;
-					reverse_order(&tmp);
-					d[i] = tmp;
-				}
-			}
-
-			if (mod) {
-				RIVA_FIFO_FREE(par->riva, Bitmap, 1);
-				for (i = 0; i < mod; i++)
-					((u8 *)&tmp)[i] = *cdat++;
-				reverse_order(&tmp);
-				d[i] = tmp;
-			}
+	width = (image->width + 31)/32;
+	size = width * image->height;
+	while (size >= 16) {
+		RIVA_FIFO_FREE(par->riva, Bitmap, 16);
+		for (i = 0; i < 16; i++) {
+			tmp = *((u32 *)cdat)++;
+			reverse_order(&tmp);
+			d[i] = tmp;
 		}
-	} else {
-		for (i = image->height; i > 0; i-=16) {
-			size = (i >= 16) ? 16 : i;
-			RIVA_FIFO_FREE(par->riva, Bitmap, size);
-			for (j = 0; j < size; j++) {
-				for (k = 0; k < width; k++) 
-					((u8 *) &tmp)[k] = *cdat++;
-				reverse_order(&tmp);
-				d[j] = tmp;
-			}
+		size -= 16;
+	}
+	if (size) {
+		RIVA_FIFO_FREE(par->riva, Bitmap, size);
+		for (i = 0; i < size; i++) {
+			tmp = *((u32 *) cdat)++;
+			reverse_order(&tmp);
+			d[i] = tmp;
 		}
 	}
 }
@@ -1632,6 +1604,12 @@
 
 	cmap_len = riva_get_cmap_len(&info->var);
 	fb_alloc_cmap(&info->cmap, cmap_len, 0);	
+
+	info->pixmap.size = 64 * 1024;
+	info->pixmap.buf_align = 4;
+	info->pixmap.scan_align = 4;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
 	return 0;
 }
 
@@ -1776,6 +1754,11 @@
 	memset(info, 0, sizeof(struct fb_info));
 	memset(default_par, 0, sizeof(struct riva_par));
 
+	info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
+	if (info->pixmap.addr == NULL)
+		goto err_out_kfree1;
+	memset(info->pixmap.addr, 0, 64 * 1024);
+
 	strcat(rivafb_fix.id, rci->name);
 	default_par->riva.Architecture = rci->arch_rev;
 
@@ -1805,7 +1788,7 @@
 	if (!request_mem_region(rivafb_fix.mmio_start,
 				rivafb_fix.mmio_len, "rivafb")) {
 		printk(KERN_ERR PFX "cannot reserve MMIO region\n");
-		goto err_out_kfree;
+		goto err_out_kfree2;
 	}
 
 	default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
@@ -1921,6 +1904,10 @@
 	iounmap(default_par->ctrl_base);
 err_out_free_base0:
 	release_mem_region(rivafb_fix.mmio_start, rivafb_fix.mmio_len);
+err_out_kfree2:
+	kfree(info->pixmap.addr);
+err_out_kfree1:
+	kfree(default_par);
 err_out_kfree:
 	kfree(info);
 err_out:
@@ -1954,6 +1941,7 @@
 		iounmap((caddr_t)par->riva.PRAMIN);
 		release_mem_region(info->fix.smem_start + 0x00C00000, 0x00008000);
 	}
+	kfree(info->pixmap.addr);
 	kfree(par);
 	kfree(info);
 	pci_set_drvdata(pd, NULL);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27 14:15           ` Antonino Daplas
@ 2003-02-27 18:25             ` Michel Dänzer
  2003-02-27 19:48               ` James Simmons
  2003-02-27 21:47               ` Antonino Daplas
  0 siblings, 2 replies; 12+ messages in thread
From: Michel Dänzer @ 2003-02-27 18:25 UTC (permalink / raw)
  To: Antonino Daplas; +Cc: James Simmons, Linux Fbdev development list

On Don, 2003-02-27 at 15:15, Antonino Daplas wrote: 
> On Thu, 2003-02-27 at 09:18, James Simmons wrote:
>  
> > > Thus, the restriction that the buffer must be completely copied by the
> > > driver before returning.  And because of this restriction, an extra copy
> > > which might be unnecessary cannot be avoided (this was noted by Petr).
> > > 
> > > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> > 
> > I didn't realize that the below was a ringbuffer implementation. The name
> > threw me off. 
> 
> Well, it's not strictly a ringbuffer implementation.  This would require
> a head and tail pointer where fbcon will adjust the tail and the
> driver/hardware will adjust the head.  This will be very difficult to
> implement in a device independent manner.  So we just cheat by issuing
> an fb_sync() per loop to flush all pending commands.

That still seems suboptimal though. What the DRM often does is have the
chip write an age value to a scratch register when it's done processing
something. Maybe something like that could be used to avoid waiting for
the chip to go idle at all?


-- 
Earthling Michel Dänzer (MrCooper)/ Debian GNU/Linux (powerpc) developer
XFree86 and DRI project member   /  CS student, Free Software enthusiast



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27 18:25             ` Michel Dänzer
@ 2003-02-27 19:48               ` James Simmons
  2003-03-02 12:14                 ` Geert Uytterhoeven
  2003-02-27 21:47               ` Antonino Daplas
  1 sibling, 1 reply; 12+ messages in thread
From: James Simmons @ 2003-02-27 19:48 UTC (permalink / raw)
  To: Michel Dänzer; +Cc: Antonino Daplas, Linux Fbdev development list


> On Don, 2003-02-27 at 15:15, Antonino Daplas wrote: 
> > On Thu, 2003-02-27 at 09:18, James Simmons wrote:
> >  
> > > > Thus, the restriction that the buffer must be completely copied by the
> > > > driver before returning.  And because of this restriction, an extra copy
> > > > which might be unnecessary cannot be avoided (this was noted by Petr).
> > > > 
> > > > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> > > 
> > > I didn't realize that the below was a ringbuffer implementation. The name
> > > threw me off. 
> > 
> > Well, it's not strictly a ringbuffer implementation.  This would require
> > a head and tail pointer where fbcon will adjust the tail and the
> > driver/hardware will adjust the head.  This will be very difficult to
> > implement in a device independent manner.  So we just cheat by issuing
> > an fb_sync() per loop to flush all pending commands.
> 
> That still seems suboptimal though. What the DRM often does is have the
> chip write an age value to a scratch register when it's done processing
> something. Maybe something like that could be used to avoid waiting for
> the chip to go idle at all?

Don't waste your time. I'm removing all the changes that have been done 
since 2.5.51. After that I will no longer be co-maintainter of the 
framebuffer layer. 



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27 18:25             ` Michel Dänzer
  2003-02-27 19:48               ` James Simmons
@ 2003-02-27 21:47               ` Antonino Daplas
  1 sibling, 0 replies; 12+ messages in thread
From: Antonino Daplas @ 2003-02-27 21:47 UTC (permalink / raw)
  To: Michel Dänzer; +Cc: James Simmons, Linux Fbdev development list

On Fri, 2003-02-28 at 02:25, Michel Dänzer wrote:
> On Don, 2003-02-27 at 15:15, Antonino Daplas wrote: 
> > On Thu, 2003-02-27 at 09:18, James Simmons wrote:
> >  
> > > > Thus, the restriction that the buffer must be completely copied by the
> > > > driver before returning.  And because of this restriction, an extra copy
> > > > which might be unnecessary cannot be avoided (this was noted by Petr).
> > > > 
> > > > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> > > 
> > > I didn't realize that the below was a ringbuffer implementation. The name
> > > threw me off. 
> > 
> > Well, it's not strictly a ringbuffer implementation.  This would require
> > a head and tail pointer where fbcon will adjust the tail and the
> > driver/hardware will adjust the head.  This will be very difficult to
> > implement in a device independent manner.  So we just cheat by issuing
> > an fb_sync() per loop to flush all pending commands.
> 
> That still seems suboptimal though. What the DRM often does is have the
> chip write an age value to a scratch register when it's done processing
> something. Maybe something like that could be used to avoid waiting for
> the chip to go idle at all?
> 

Yes, it is certainly suboptimal. But the fb_sync() will be done only
when the pointer wraps to the beginning of the buffer and only if the
buffer can be DMA'd by the chip.

To support these types of buffers, we can change pixmap.offset to head
and tail. The buffer is empty when head == tail.  Then, fbcon
continually adjusts the tail to tail+size, and when the chip is done
processing that particular bitmap, it will adjust the head to
head+size.  Then instead of doing an fb_sync(), fbcon will just busy
loop waiting for the buffer to have enough space for the next set of
bitmaps.

This will involve per chipset support, the reason why I did not do it
like this.  It can be added, but it will not be default behavior.

PS:  I remember that practically all drivers do some form of syncing
before each operation, and no one complained :-).

Tony  
 




-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-02-27 19:48               ` James Simmons
@ 2003-03-02 12:14                 ` Geert Uytterhoeven
  2003-03-03 21:32                   ` Antonino Daplas
  0 siblings, 1 reply; 12+ messages in thread
From: Geert Uytterhoeven @ 2003-03-02 12:14 UTC (permalink / raw)
  To: James Simmons
  Cc: Michel Dänzer, Antonino Daplas, Linux Fbdev development list

On Thu, 27 Feb 2003, James Simmons wrote:
> > On Don, 2003-02-27 at 15:15, Antonino Daplas wrote: 
> > > On Thu, 2003-02-27 at 09:18, James Simmons wrote:
> > >  
> > > > > Thus, the restriction that the buffer must be completely copied by the
> > > > > driver before returning.  And because of this restriction, an extra copy
> > > > > which might be unnecessary cannot be avoided (this was noted by Petr).
> > > > > 
> > > > > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> > > > 
> > > > I didn't realize that the below was a ringbuffer implementation. The name
> > > > threw me off. 
> > > 
> > > Well, it's not strictly a ringbuffer implementation.  This would require
> > > a head and tail pointer where fbcon will adjust the tail and the
> > > driver/hardware will adjust the head.  This will be very difficult to
> > > implement in a device independent manner.  So we just cheat by issuing
> > > an fb_sync() per loop to flush all pending commands.
> > 
> > That still seems suboptimal though. What the DRM often does is have the
> > chip write an age value to a scratch register when it's done processing
> > something. Maybe something like that could be used to avoid waiting for
> > the chip to go idle at all?
> 
> Don't waste your time. I'm removing all the changes that have been done 
> since 2.5.51. After that I will no longer be co-maintainter of the 
> framebuffer layer. 

Are you sure about that?!?!?

What about adding a pointer to a

    struct con_ops {
      set_font();
      putc();
      putcs();
    } 
    
to struct fb_info as an interim solution, until tile blitting has matured? That
would make Petr (matroxfb) and Davem (sbusfb) happy?

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Tile Blitting
  2003-03-02 12:14                 ` Geert Uytterhoeven
@ 2003-03-03 21:32                   ` Antonino Daplas
  0 siblings, 0 replies; 12+ messages in thread
From: Antonino Daplas @ 2003-03-03 21:32 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: James Simmons, Michel Dänzer, Linux Fbdev development list

On Sun, 2003-03-02 at 20:14, Geert Uytterhoeven wrote:
> On Thu, 27 Feb 2003, James Simmons wrote:
> > > On Don, 2003-02-27 at 15:15, Antonino Daplas wrote: 
> > > > On Thu, 2003-02-27 at 09:18, James Simmons wrote:
> > > >  
> > > > > > Thus, the restriction that the buffer must be completely copied by the
> > > > > > driver before returning.  And because of this restriction, an extra copy
> > > > > > which might be unnecessary cannot be avoided (this was noted by Petr).
> > > > > > 
> > > > > > Treating the buffer as a ringbuffer, we eliminate these restrictions.
> > > > > 
> > > > > I didn't realize that the below was a ringbuffer implementation. The name
> > > > > threw me off. 
> > > > 
> > > > Well, it's not strictly a ringbuffer implementation.  This would require
> > > > a head and tail pointer where fbcon will adjust the tail and the
> > > > driver/hardware will adjust the head.  This will be very difficult to
> > > > implement in a device independent manner.  So we just cheat by issuing
> > > > an fb_sync() per loop to flush all pending commands.
> > > 
> > > That still seems suboptimal though. What the DRM often does is have the
> > > chip write an age value to a scratch register when it's done processing
> > > something. Maybe something like that could be used to avoid waiting for
> > > the chip to go idle at all?
> > 
> > Don't waste your time. I'm removing all the changes that have been done 
> > since 2.5.51. After that I will no longer be co-maintainter of the 
> > framebuffer layer. 
> 
> Are you sure about that?!?!?
> 

I agree.  Actually, I'm not worried about Tile blitting.  It should be
mature since it's basically a rehash of the 2.4 API.  If I'm going to
worry about something, it's the standard accel_putcs() code, especially
if thread-safety is an issue.

Is thread-safety a real problem?  That was also my concern before, which
is why I looked at vt.c.  From what I can see, there's always an
"acquire_console_sem()" before calling any of the console methods. The
console semaphore is supposed to guarantee serialization and exclusive
access to the console (see linux/kernel/printk.c).

Tony



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2003-03-03 21:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-02-23  4:42 [PATCH] Tile Blitting Antonino Daplas
2003-02-23  7:43 ` Antonino Daplas
2003-02-23 11:07   ` Antonino Daplas
2003-02-26 20:11     ` James Simmons
2003-02-27  0:35       ` Antonino Daplas
2003-02-27  1:18         ` James Simmons
2003-02-27 14:15           ` Antonino Daplas
2003-02-27 18:25             ` Michel Dänzer
2003-02-27 19:48               ` James Simmons
2003-03-02 12:14                 ` Geert Uytterhoeven
2003-03-03 21:32                   ` Antonino Daplas
2003-02-27 21:47               ` Antonino Daplas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).