[PATCH] cfbimgblt: Allow generic BitBLT functions to work with swapped pixel order in bytes.

Pavel Pisa <[email protected]> Thu, 30 Aug 2007 19:28:11 +0200
Newsgroups gmane.linux.fbdev.user
Message-ID <[email protected]>
Hello Antonino and others,

the generic BLT functions binds unconditionally byte endian with
pixels in byte order. Unfortunately there are more devices which
can work only in unsupported pixels layout. One of them is
Freescale MX1 found on PiMX1 board when used in 4 bpp monochromatic
mode. Curiously Microwindows and Qt-embedded take this layout
as default one and works without problems. Linux console output
is funny on the other hand.

I would like to know, if suggested solution is at least remotely
acceptable for mainline in future. It would be probably good
to add some flag to struct fb_info.var which would enable swapping.
This would allow code to be generic even if
  CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
is selected. If option is disabled, then there should be
zero overhead, all abundant code should be removed by compiller.

If this is acceptable, I try to add support for rectangle
and copy in future, but this do not seems to be critical for
console. Normal fonts widths are multiples of 8 so problems
are not seen.

Best wishes

             Pavel Pisa

===================================================================

The next patch allows generic frame-buffer code to correctly write texts
and blit images for 1, 2 and 4 bit per pixel frame-buffer organizations
when pixels in bytes are organized to in opposite order than bytes
in long type.

Overhead should be reasonable. If option is not selected, than compiler
should eliminate completely all overhead.

Signed-off-by: Pavel Pisa <[email protected]>

 drivers/video/Kconfig     |   10 +++++++++
 drivers/video/cfbimgblt.c |   48 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 52 insertions(+), 6 deletions(-)

Index: linux-2.6.23-git/drivers/video/cfbimgblt.c
===================================================================
--- linux-2.6.23-git.orig/drivers/video/cfbimgblt.c
+++ linux-2.6.23-git/drivers/video/cfbimgblt.c
@@ -75,6 +75,20 @@ static const u32 cfb_tab32[] = {
 #define FB_WRITEL fb_writel
 #define FB_READL  fb_readl
 
+#define FB_SHIFTED_PIXELS_MASK(index, bswapmask) ({ \
+		u32 _m; \
+		u32 _indx = (index); \
+		if (!bswapmask) { \
+			_m = FB_SHIFT_HIGH(~(u32)0, _indx); \
+		} else { \
+			_m = 0xff << FB_LEFT_POS(8); \
+			_m = FB_SHIFT_LOW(_m, _indx & (bswapmask)) & _m; \
+			_m = FB_SHIFT_HIGH(_m, _indx & ~(bswapmask)); \
+			_m |= FB_SHIFT_HIGH(~(u32)0, (_indx + bswapmask) & ~(bswapmask)); \
+		} \
+		_m; \
+	})
+
 static inline void color_imageblit(const struct fb_image *image, 
 				   struct fb_info *p, u8 __iomem *dst1, 
 				   u32 start_index,
@@ -87,6 +101,17 @@ static inline void color_imageblit(const
 	u32 null_bits = 32 - bpp;
 	u32 *palette = (u32 *) p->pseudo_palette;
 	const u8 *src = image->data;
+	u32 bswapmask = 0;
+
+#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
+	if (bpp < 8) {
+		/*
+		 * Reversed order of pixel layout in bytes
+		 * works only for 1, 2 and 4 bpp
+		 */
+		bswapmask = 7 - bpp + 1;
+	}
+#endif
 
 	dst2 = (u32 __iomem *) dst1;
 	for (i = image->height; i--; ) {
@@ -96,7 +121,7 @@ static inline void color_imageblit(const
 		val = 0;
 		
 		if (start_index) {
-			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
+			u32 start_mask = ~FB_SHIFTED_PIXELS_MASK(start_index, bswapmask);
 			val = FB_READL(dst) & start_mask;
 			shift = start_index;
 		}
@@ -107,7 +132,7 @@ static inline void color_imageblit(const
 			else
 				color = *src;
 			color <<= FB_LEFT_POS(bpp);
-			val |= FB_SHIFT_HIGH(color, shift);
+			val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
 			if (shift >= null_bits) {
 				FB_WRITEL(val, dst++);
 	
@@ -119,7 +144,7 @@ static inline void color_imageblit(const
 			src++;
 		}
 		if (shift) {
-			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+			u32 end_mask = FB_SHIFTED_PIXELS_MASK(shift, bswapmask);
 
 			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
 		}
@@ -147,6 +172,17 @@ static inline void slow_imageblit(const 
 	u32 spitch = (image->width+7)/8;
 	const u8 *src = image->data, *s;
 	u32 i, j, l;
+	u32 bswapmask = 0;
+
+#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
+	if (bpp < 8) {
+		/*
+		 * Reversed order of pixel layout in bytes
+		 * works only for 1, 2 and 4 bpp
+		 */
+		bswapmask = 7 - bpp + 1;
+	}
+#endif
 	
 	dst2 = (u32 __iomem *) dst1;
 	fgcolor <<= FB_LEFT_POS(bpp);
@@ -161,7 +197,7 @@ static inline void slow_imageblit(const 
 
 		/* write leading bits */
 		if (start_index) {
-			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
+			u32 start_mask = ~FB_SHIFTED_PIXELS_MASK(start_index, bswapmask);
 			val = FB_READL(dst) & start_mask;
 			shift = start_index;
 		}
@@ -169,7 +205,7 @@ static inline void slow_imageblit(const 
 		while (j--) {
 			l--;
 			color = (*s & (1 << l)) ? fgcolor : bgcolor;
-			val |= FB_SHIFT_HIGH(color, shift);
+			val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
 			
 			/* Did the bitshift spill bits to the next long? */
 			if (shift >= null_bits) {
@@ -184,7 +220,7 @@ static inline void slow_imageblit(const 
 
 		/* write trailing bits */
  		if (shift) {
-			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+			u32 end_mask = FB_SHIFTED_PIXELS_MASK(shift, bswapmask);
 
 			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
 		}
Index: linux-2.6.23-git/drivers/video/Kconfig
===================================================================
--- linux-2.6.23-git.orig/drivers/video/Kconfig
+++ linux-2.6.23-git/drivers/video/Kconfig
@@ -103,6 +103,15 @@ config FB_CFB_IMAGEBLIT
 	  blitting. This is used by drivers that don't provide their own
 	  (accelerated) version.
 
+config FB_CFB_REV_PIXELS_IN_BYTE
+	bool
+	depends on FB
+	default n
+	---help---
+	  Allow generic frame-buffer functions to work on displays with 1, 2 and 4
+	  bits per pixel depths which has opposite order of pixels in byte order
+	  to bytes in long order.
+
 config FB_SYS_FILLRECT
 	tristate
 	depends on FB
@@ -348,6 +357,7 @@ config FB_IMX
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select FB_CFB_REV_PIXELS_IN_BYTE
 
 config FB_CYBER2000
 	tristate "CyberPro 2000/2010/5000 support"

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/