linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Antonino Daplas <adaplas@pol.net>
To: fbdev <linux-fbdev-devel@lists.sourceforge.net>
Subject: RFC: Optimizing putcs()
Date: 06 Aug 2002 06:04:19 +0800	[thread overview]
Message-ID: <1028584418.556.29.camel@daplas> (raw)

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

With fbcon-accel and the new drawing functions in linux-2.5, console
performance degraded compared to the linux-2.4 implementation.  This is
because putcs() has to to do 1 fb_imageblit() per character to be
drawn.  

This can be optimized by letting putcs() initially construct the row of
text to be drawn into an offscreen buffer, then do a single
fb_imageblit() in the end.  Performance wil increase for several
reasons:

	1. Drawing can be done in "bursts" instead of "trickles"

	2. For drivers that support accelerated drawing functions, the
offscreen buffer can be optionally placed in graphics (or AGP) memory,
which is better suited for most hardware that can only do blit's from
video memory to video memory.
	
	3.  Some level of asynchronicity can be achieved, ie, the hardware can
be blitting while fbcon-accel is constructing bitmaps.  This would
require "walking" the offscreen buffer, and support for hardware
graphics sync'ing on demand.

I have included a patch for 2.5.27 that implements it in fbcon-accel. 
It's preliminary, but I have tested it with cfb_imageblit and with
hardware imageblit, with buffers in System or Video memory.  

The code is also present for hardware syncing on demand, though
unimplemented.

For drivers that uses cfb_imageblit or similar, a code such as the one
below can be inserted during initialization:

info->pixmap.addr = (unsigned long) kmalloc(BUFFER_SIZE, GFP_KERNEL);
info->pixmap.size = BUFFER_SIZE;
info->pixmap.offset = 0;
info->pixmap.buf_align = 1;
info->pixmap.scan_align = 1;

Some benchmarks:

time cat /usr/src/linux/MAINTAINERS (40K text file)
mode: 1024x768@8bpp, y-panning disabled.

cfb_imageblit - no offscreen buffer (default)

real    0m13.586s
user    0m0.001s
sys     0m13.585s

cfb_imageblit - with offscreen buffer in system memory

real    0m10.708s
user    0m0.001s
sys     0m10.707s

hardware imageblit - no offscreen buffer

real    0m6.036s
user    0m0.001s
sys     0m6.035s

hardware imageblit - with offscreen buffer in graphics memory

real    0m3.160s
user    0m0.001s
sys     0m3.160s

hardware imageblit - graphics offscreen buffer + hardware sync on demand

real    0m1.843s
user    0m0.000s
sys     0m1.843s

Tony

[-- Attachment #2: fb-pixmap.diff --]
[-- Type: text/x-patch, Size: 5107 bytes --]

diff -Naur linux-2.5.27/drivers/video/fbcon-accel.c linux/drivers/video/fbcon-accel.c
--- linux-2.5.27/drivers/video/fbcon-accel.c	Mon Aug  5 21:15:56 2002
+++ linux/drivers/video/fbcon-accel.c	Mon Aug  5 21:17:22 2002
@@ -70,9 +70,47 @@
 	image.width = fontwidth(p);
 	image.height = fontheight(p);
 	image.depth = 1;
-	image.data = p->fontdata + (c & charmask)*fontheight(p)*width;
+	if (!info->pixmap.addr) {
+		image.data = p->fontdata + (c & charmask)*fontheight(p)*width;
+		info->fbops->fb_imageblit(info, &image);
+	}
+	else {
+		unsigned int d_size, d_pitch, i, j; 
+		unsigned int scan_align = (info->pixmap.scan_align) ? info->pixmap.scan_align - 1 : 0;
+		unsigned int buf_align = (info->pixmap.buf_align) ? info->pixmap.buf_align - 1 : 0;
+		char *d_addr, *s_addr;
+
+		d_pitch = (width + scan_align) & ~scan_align;
+		d_size = d_pitch * image.height;
+
+		if (d_size > info->pixmap.size) {
+			BUG();
+			return;
+		}
+		
+		info->pixmap.offset = (info->pixmap.offset + buf_align) & ~buf_align;
 
-	info->fbops->fb_imageblit(info, &image);
+		if (info->pixmap.offset + d_size > info->pixmap.size) {
+#if 0
+			/* Some form of hardware sync'ing may be necessary here */
+			if (info->fbops->fb_sync) 
+				info->fbops->fb_sync(info);
+#endif
+			info->pixmap.offset = 0;
+		}
+		s_addr = p->fontdata + (c & charmask)*fontheight(p)*width;
+		image.data = (char *) (info->pixmap.addr + info->pixmap.offset);
+		d_addr = image.data;
+
+		for (i = image.height; i--; ) {
+			for (j = 0; j < width; j++) 
+				d_addr[j] = *s_addr++;
+			d_addr += d_pitch;
+		}
+
+		info->fbops->fb_imageblit(info, &image);
+		info->pixmap.offset += d_size;
+	}
 }
 
 void fbcon_accel_putcs(struct vc_data *vc, struct display *p,
@@ -87,15 +125,61 @@
 	image.bg_color = attr_bgcol(p, *s);
 	image.dx = xx * fontwidth(p);
 	image.dy = yy * fontheight(p);
-	image.width = fontwidth(p);
 	image.height = fontheight(p);
 	image.depth = 1;
+	if (!info->pixmap.addr) {
+		image.width = fontwidth(p);
+		while (count--) {
+			image.data = p->fontdata +
+				(scr_readw(s++) & charmask) * fontheight(p) * width;
+			info->fbops->fb_imageblit(info, &image);
+			image.dx += fontwidth(p);
+		}
+	}
+	else {
+		unsigned int d_pitch, d_size, i, j; 
+		unsigned int scan_align = (info->pixmap.scan_align) ? info->pixmap.scan_align - 1 : 0;
+		unsigned int buf_align = (info->pixmap.buf_align) ? info->pixmap.buf_align - 1 : 0;
+		char *s_addr, *d_addr, *d_addr0;
+
+		d_pitch = (width * count) + scan_align;
+		d_pitch &= ~scan_align;
+		d_size = d_pitch * image.height;
+
+		if (d_size > info->pixmap.size) {
+			BUG();
+			return;
+		}
+
+		info->pixmap.offset = (info->pixmap.offset + buf_align) & ~buf_align;
+
+		if (info->pixmap.offset + d_size > info->pixmap.size) { 
+#if 0
+			/* Some form of hardware sync'ing may be necessary here */
+			if (info->fbops->fb_sync)
+				info->fbops->fb_sync(info);
+#endif
+			info->pixmap.offset = 0;
+		}
+
+		image.width = fontwidth(p) * count;
+		image.data = (char *) (info->pixmap.addr + info->pixmap.offset);
+		d_addr = image.data;
+
+		while (count--) {
+			s_addr = p->fontdata + 
+				(scr_readw(s++) & charmask) * fontheight(p) * width;
+			d_addr0 = d_addr;
+			for (i = image.height; i--; ) {
+				for (j = 0; j < width; j++)
+					d_addr0[j] = *s_addr++;
+				d_addr0 += d_pitch;
+			}
+			d_addr += width;
+		}
 
-	while (count--) {
-		image.data = p->fontdata +
-			(scr_readw(s++) & charmask) * fontheight(p) * width;
 		info->fbops->fb_imageblit(info, &image);
-		image.dx += fontwidth(p);
+		info->pixmap.offset += d_size;
 	}
 }
 
diff -Naur linux-2.5.27/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.5.27/include/linux/fb.h	Mon Aug  5 21:16:16 2002
+++ linux/include/linux/fb.h	Mon Aug  5 21:17:48 2002
@@ -291,6 +291,14 @@
 	char  *data;	/* Pointer to image data */
 };
 
+struct fb_pixmap {
+	__u32 addr;         /* buffer pointer (system or video), NULL if none */
+	__u32 offset;       /* offset to buffer */
+	__u32 size;         /* size of buffer */
+	__u32 buf_align;    /* buffer start alignment */
+	__u32 scan_align;   /* scanline alignment, should be <= buf_align */
+};
+
 #ifdef __KERNEL__
 
 #if 1 /* to go away in 2.5.0 */
@@ -359,6 +367,10 @@
     int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
     /* switch to/from raster image mode */
     int (*fb_rasterimg)(struct fb_info *info, int start);
+#if 0 
+    /* wait for blit idle, optional */
+    void (*fb_sync)(struct fb_info *info);	 
+#endif
 };
 
 struct fb_info {
@@ -371,6 +383,7 @@
    struct fb_fix_screeninfo fix;        /* Current fix */
    struct fb_monspecs monspecs;         /* Current Monitor specs */
    struct fb_cmap cmap;                 /* Current cmap */
+   struct fb_pixmap pixmap;             /* Offscreen pixmap */
    struct fb_ops *fbops;
    char *screen_base;                   /* Virtual address */
    struct display *disp;		/* initial display variable */

             reply	other threads:[~2002-08-05 22:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-08-05 22:04 Antonino Daplas [this message]
2002-08-06 20:08 ` RFC: Optimizing putcs() Geert Uytterhoeven
2002-08-07  0:17   ` Antonino Daplas
2002-08-07  5:25 ` Antonino Daplas
     [not found] <20020806054957.44715.qmail@web13004.mail.yahoo.com>
2002-08-06 18:11 ` Antonino Daplas
2002-08-08 18:31   ` James Simmons

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1028584418.556.29.camel@daplas \
    --to=adaplas@pol.net \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).