Skip to contentSkip to conversation

Tile Blitting

PATCH In review Antonino Daplas 4 participants 12 messages Feb 23, 2003 – Mar 3, 2003

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Tile Blitting

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

drivers/video/console/Kconfig +10 -0
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Kconfig linux-2.5.61/drivers/video/console/Kconfig
@@ -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
drivers/video/console/Makefile +7 -1
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Makefile linux-2.5.61/drivers/video/console/Makefile
@@ -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
 
drivers/video/console/fbcon.c +220 -92

543 lines not on this page · raw message

drivers/video/console/fbcon.h +15 -0
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.h linux-2.5.61/drivers/video/console/fbcon.h
@@ -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 */
drivers/video/console/fbcon_tileops.c +118 -0

118 lines not on this page · raw message

drivers/video/fbmem.c +3 -3
diff -Naur linux-2.5.61-fbdev/drivers/video/fbmem.c linux-2.5.61/drivers/video/fbmem.c
@@ -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)
 {
include/linux/fb.h +72 -0

84 lines not on this page · raw message

cfb_tileops.c +130 -0

130 lines not on this page · raw message

#1 lore raw
Quoted 4 lines · Antonino Daplas

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

drivers/video/console/Kconfig +10 -0
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Kconfig linux-2.5.61/drivers/video/console/Kconfig
@@ -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
drivers/video/console/Makefile +5 -1
diff -Naur linux-2.5.61-fbdev/drivers/video/console/Makefile linux-2.5.61/drivers/video/console/Makefile
@@ -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
 
drivers/video/console/fbcon.c +99 -176

487 lines not on this page · raw message

drivers/video/console/fbcon.h +16 -0
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon.h linux-2.5.61/drivers/video/console/fbcon.h
@@ -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 */
drivers/video/console/fbcon_accelops.c +229 -0

229 lines not on this page · raw message

drivers/video/console/fbcon_tileops.c +118 -0

118 lines not on this page · raw message

drivers/video/fbmem.c +3 -3
diff -Naur linux-2.5.61-fbdev/drivers/video/fbmem.c linux-2.5.61/drivers/video/fbmem.c
@@ -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)
 {
include/linux/fb.h +72 -0

84 lines not on this page · raw message

#2 lore raw
Quoted 9 lines · Antonino Daplas
Quoted 4 lines · Antonino Daplas

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

drivers/video/console/fbcon_accelops.c +5 -2
diff -Naur linux-2.5.61-fbdev/drivers/video/console/fbcon_accelops.c linux-2.5.61/drivers/video/console/fbcon_accelops.c
@@ -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

#3 lore raw

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

#4 lore raw
Quoted 27 lines · James Simmons

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.

Quoted 5 lines

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

#5 lore raw
Quoted 2 lines

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?

Quoted 4 lines

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.

Quoted 12 lines

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'.

Quoted 7 lines

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.

Quoted 6 lines

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.

Quoted 3 lines

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.

Quoted 5 lines

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.

Quoted 20 lines

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.

Quoted 7 lines

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

#6 lore raw
Quoted 8 lines · James Simmons
Quoted 3 lines

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".

Quoted 8 lines
Quoted 5 lines

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.

Quoted 3 lines

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

drivers/video/console/fbcon.c +244 -99
diff -Naur linux-2.5.61/drivers/video/console/fbcon.c linux/drivers/video/console/fbcon.c
@@ -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;
drivers/video/fbmem.c +26 -0
diff -Naur linux-2.5.61/drivers/video/fbmem.c linux/drivers/video/fbmem.c
@@ -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");
drivers/video/softcursor.c +60 -12

97 lines not on this page · raw message

include/linux/fb.h +19 -0
diff -Naur linux-2.5.61/include/linux/fb.h linux/include/linux/fb.h
@@ -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;
 
drivers/video/riva/fbdev.c +35 -47

133 lines not on this page · raw message

#7 lore raw
Quoted 8 lines · Antonino Daplas
Quoted 6 lines · James Simmons
Quoted 5 lines

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.

Quoted 8 lines
Quoted 2 lines

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?

Signature · 9 lines
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
#8 lore raw
Quoted 19 lines · Antonino Daplas
Quoted 8 lines · James Simmons
Quoted 7 lines
Quoted 6 lines

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.

Quoted 8 lines
Quoted 2 lines

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.

Quoted 4 lines

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

#9 lore raw
Quoted 18 lines · James Simmons
Quoted 18 lines · Antonino Daplas
Quoted 16 lines · James Simmons
Quoted 9 lines
Quoted 6 lines

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.

Quoted 8 lines
Quoted 4 lines

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 -- [email protected]

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

#10 lore raw
Quoted 24 lines · Geert Uytterhoeven
Quoted 23 lines · James Simmons
Quoted 22 lines · Antonino Daplas
Quoted 8 lines · James Simmons
Quoted 7 lines
Quoted 6 lines

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.

Quoted 8 lines
Quoted 2 lines

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?

Quoted 6 lines
Quoted 3 lines

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

#11 lore raw
In reply to Michel Dänzer
Quoted 18 lines · Michel Dänzer
Quoted 8 lines · Antonino Daplas
Quoted 6 lines · James Simmons
Quoted 5 lines

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.

Quoted 8 lines
Quoted 2 lines

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.

Quoted 5 lines

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