linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] fbdev: fix fillrect for 24bpp modes
@ 2009-04-13 17:09 Michal Januszewski
  2009-04-17 16:36 ` [Linux-fbdev-devel] " Krzysztof Helt
  0 siblings, 1 reply; 7+ messages in thread
From: Michal Januszewski @ 2009-04-13 17:09 UTC (permalink / raw)
  To: linux-fbdev-devel; +Cc: linux-kernel, akpm

The software fillrect routines do not work properly when the number of
pixels per machine word is not an integer.  To see that, run the following
command on a fbdev console with a 24bpp video mode, using a non-accelerated
driver such as (u)vesafb:

  reset ; echo -e '\e[41mtest\e[K'

The expected result is 'test' displayed on a line with red background.
Instead of that, 'test' has a red background, but the rest of the line
(rendered using fillrect()) contains a distored colorful pattern.

This patch fixes the problem by correctly computing rotation shifts.
It has been tested in a 24bpp mode on 32- and 64-bit little-endian
machines.

Signed-off-by: Michal Januszewski <spock@gentoo.org>
---
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 64b3576..396e676 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -9,10 +9,6 @@
  *
  * NOTES:
  *
- *  The code for depths like 24 that don't have integer number of pixels per
- *  long is broken and needs to be fixed. For now I turned these types of
- *  mode off.
- *
  *  Also need to add code to deal with cards endians that are different than
  *  the native cpu endians. I also need to deal with MSB position in the word.
  *
@@ -139,7 +135,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
 
 		// Trailing bits
 		if (last)
-			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
 	}
 }
 
@@ -297,7 +293,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 	else
 		fg = rect->color;
 
-	pat = pixel_to_pat( bpp, fg);
+	pat = pixel_to_pat(bpp, fg);
 
 	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
 	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
@@ -333,17 +329,20 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
+		r = dst_idx >> (ffs(bits) - 1);
+		pat = pat << ((left*r) % bpp) | pat >> ((right*r) % bpp);
 
-		right = bpp-left;
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index 1db6221..fa9626e 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -33,11 +33,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x0101010101010101ul*pixel;
 	case 12:
-		return 0x0001001001001001ul*pixel;
+		return 0x1001001001001001ul*pixel;
 	case 16:
 		return 0x0001000100010001ul*pixel;
 	case 24:
-		return 0x0000000001000001ul*pixel;
+		return 0x0001000001000001ul*pixel;
 	case 32:
 		return 0x0000000100000001ul*pixel;
 	default:
@@ -58,11 +58,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x01010101ul*pixel;
 	case 12:
-		return 0x00001001ul*pixel;
+		return 0x01001001ul*pixel;
 	case 16:
 		return 0x00010001ul*pixel;
 	case 24:
-		return 0x00000001ul*pixel;
+		return 0x01000001ul*pixel;
 	case 32:
 		return 0x00000001ul*pixel;
 	default:
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
index f94d6b6..024e6b9 100644
--- a/drivers/video/sysfillrect.c
+++ b/drivers/video/sysfillrect.c
@@ -124,7 +124,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
 
 		/* Trailing bits */
 		if (last)
-			*dst = comp(pat, *dst, first);
+			*dst = comp(pat, *dst, last);
 	}
 }
 
@@ -292,17 +292,20 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
+		r = dst_idx >> (ffs(bits) - 1);
+		pat = pat << ((left*r) % bpp) | pat >> ((right*r) % bpp);
 
-		right = bpp-left;
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;


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

* Re: [Linux-fbdev-devel] [PATCH] fbdev: fix fillrect for 24bpp modes
  2009-04-13 17:09 [PATCH] fbdev: fix fillrect for 24bpp modes Michal Januszewski
@ 2009-04-17 16:36 ` Krzysztof Helt
  2009-04-17 18:50   ` Andrew Morton
  0 siblings, 1 reply; 7+ messages in thread
From: Krzysztof Helt @ 2009-04-17 16:36 UTC (permalink / raw)
  To: spock; +Cc: linux-fbdev-devel, akpm, linux-kernel

On Mon, 13 Apr 2009 19:09:54 +0200
Michal Januszewski <spock@gentoo.org> wrote:

> The software fillrect routines do not work properly when the number of
> pixels per machine word is not an integer.  To see that, run the following
> command on a fbdev console with a 24bpp video mode, using a non-accelerated
> driver such as (u)vesafb:
> 
>   reset ; echo -e '\e[41mtest\e[K'
> 
> The expected result is 'test' displayed on a line with red background.
> Instead of that, 'test' has a red background, but the rest of the line
> (rendered using fillrect()) contains a distored colorful pattern.
> 
> This patch fixes the problem by correctly computing rotation shifts.
> It has been tested in a 24bpp mode on 32- and 64-bit little-endian
> machines.
> 

I can confirm the patch fixes the issue it describes if the line is not padded
or padded in a special way. See my comments below.

> Signed-off-by: Michal Januszewski <spock@gentoo.org>
> ---
> diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
> index 64b3576..396e676 100644
> --- a/drivers/video/cfbfillrect.c
> +++ b/drivers/video/cfbfillrect.c
> @@ -9,10 +9,6 @@
>   *
>   * NOTES:
>   *
> - *  The code for depths like 24 that don't have integer number of pixels per
> - *  long is broken and needs to be fixed. For now I turned these types of
> - *  mode off.
> - *
>   *  Also need to add code to deal with cards endians that are different than
>   *  the native cpu endians. I also need to deal with MSB position in the word.
>   *
> @@ -139,7 +135,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
>  
>  		// Trailing bits
>  		if (last)
> -			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
> +			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
>  	}
>  }
>  
> @@ -297,7 +293,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
>  	else
>  		fg = rect->color;
>  
> -	pat = pixel_to_pat( bpp, fg);
> +	pat = pixel_to_pat(bpp, fg);
>  
>  	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
>  	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
> @@ -333,17 +329,20 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
>  			dst_idx += p->fix.line_length*8;
>  		}
>  	} else {
> -		int right;
> -		int r;
> -		int rot = (left-dst_idx) % bpp;
> +		int right, r;
>  		void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
>  				int dst_idx, unsigned long pat, int left,
>  				int right, unsigned n, int bits) = NULL;
> -
> +#ifdef __LITTLE_ENDIAN
> +		right = left;
> +		left = bpp - right;
> +#else
> +		right = bpp - left;
> +#endif
>  		/* rotate pattern to correct start position */
> -		pat = pat << rot | pat >> (bpp-rot);
> +		r = dst_idx >> (ffs(bits) - 1);

The r is simply dst_idx / bits. Most compilers will optimize it away into 
a simple shift because the bits has only one bit set (it is number of bits in a long variable, ie. 32 or 64).

> +		pat = pat << ((left*r) % bpp) | pat >> ((right*r) % bpp);
>  

If the r = (dst_idx / bits) it is number of long words. The shift by ((left*r) % bpp) does
not make much sense (try left = 3 and r = 24 words - it is always zero but should be 3). 
It is even worse if a line is padded so line's length modulo bpp is not 
zero it does not work. A colorful pattern is produced  after the "mtest" text.

A dst_idx offset is not taken into account (it could be non-zero only for depths < 8 bits).

Kind regards,
Krzysztof


----------------------------------------------------------------------
Najlepsze dzwonki MP3 na telefon komorkowy!
Sprawdz >> http://link.interia.pl/f2128  


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

* Re: [Linux-fbdev-devel] [PATCH] fbdev: fix fillrect for 24bpp modes
  2009-04-17 16:36 ` [Linux-fbdev-devel] " Krzysztof Helt
@ 2009-04-17 18:50   ` Andrew Morton
  2009-04-18 18:52     ` [PATCH v2] " Michal Januszewski
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2009-04-17 18:50 UTC (permalink / raw)
  To: Krzysztof Helt; +Cc: spock, linux-fbdev-devel, linux-kernel

On Fri, 17 Apr 2009 18:36:17 +0200
Krzysztof Helt <krzysztof.h1@poczta.fm> wrote:

> On Mon, 13 Apr 2009 19:09:54 +0200
> Michal Januszewski <spock@gentoo.org> wrote:
> 
> ...
>
> The r is simply dst_idx / bits. Most compilers will optimize it away into 
> a simple shift because the bits has only one bit set (it is number of bits in a long variable, ie. 32 or 64).
> 
> > +		pat = pat << ((left*r) % bpp) | pat >> ((right*r) % bpp);
> >  
> 
> If the r = (dst_idx / bits) it is number of long words. The shift by ((left*r) % bpp) does
> not make much sense (try left = 3 and r = 24 words - it is always zero but should be 3). 
> It is even worse if a line is padded so line's length modulo bpp is not 
> zero it does not work. A colorful pattern is produced  after the "mtest" text.
> 
> A dst_idx offset is not taken into account (it could be non-zero only for depths < 8 bits).
> 

OK, thanks for checking.

Michael, I'll await a version 2 on this patch.  It looks like something
we want in 2.6.30.


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

* [PATCH v2] fbdev: fix fillrect for 24bpp modes
  2009-04-17 18:50   ` Andrew Morton
@ 2009-04-18 18:52     ` Michal Januszewski
  2009-04-20 23:07       ` Andrew Morton
  2009-04-21  5:10       ` [PATCH v2] " Krzysztof Helt
  0 siblings, 2 replies; 7+ messages in thread
From: Michal Januszewski @ 2009-04-18 18:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Krzysztof Helt, linux-fbdev-devel, linux-kernel

The software fillrect routines do not work properly when the number of
pixels per machine word is not an integer.  To see that, run the following
command on a fbdev console with a 24bpp video mode, using a non-accelerated
driver such as (u)vesafb:

  reset ; echo -e '\e[41mtest\e[K'

The expected result is 'test' displayed on a line with red background.
Instead of that, 'test' has a red background, but the rest of the line
(rendered using fillrect()) contains a distored colorful pattern.

This patch fixes the problem by correctly computing rotation shifts.
It has been tested in a 24bpp mode on 32- and 64-bit little-endian
machines.

Signed-off-by: Michał Januszewski <spock@gentoo.org>
---
This version of the patch should work correctly with modes where
line_length*8 % bpp != 0.

It also replaces the right shift by (ffs(bits) - 1) with a division
by bits, as both operations are optimized into a shift by a constant
and the latter one increases code readability.

In case this still breaks in some modes, I would appreciate a full
list of parameters describing the problem, i.e. bpp, line_length
and the top left coordinate of the rectangle that is painted
incorrectly.

diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 64b3576..faa1a39 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -9,10 +9,6 @@
  *
  * NOTES:
  *
- *  The code for depths like 24 that don't have integer number of pixels per
- *  long is broken and needs to be fixed. For now I turned these types of
- *  mode off.
- *
  *  Also need to add code to deal with cards endians that are different than
  *  the native cpu endians. I also need to deal with MSB position in the word.
  *
@@ -139,7 +135,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
 
 		// Trailing bits
 		if (last)
-			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
 	}
 }
 
@@ -281,7 +277,7 @@ bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
 
 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
-	unsigned long pat, fg;
+	unsigned long pat, pat2, fg;
 	unsigned long width = rect->width, height = rect->height;
 	int bits = BITS_PER_LONG, bytes = bits >> 3;
 	u32 bpp = p->var.bits_per_pixel;
@@ -297,7 +293,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 	else
 		fg = rect->color;
 
-	pat = pixel_to_pat( bpp, fg);
+	pat = pixel_to_pat(bpp, fg);
 
 	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
 	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
@@ -333,17 +329,16 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
-		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
-
-		right = bpp-left;
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;
@@ -357,12 +352,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> (ffs(bits) - 1);
+			dst += dst_idx / bits;
 			dst_idx &= (bits - 1);
-			fill_op(p, dst, dst_idx, pat, left, right,
+			r = dst_idx % bpp;
+			/* rotate pattern to the correct start position */
+#ifdef __LITTLE_ENDIAN
+			pat2 = pat << r | pat >> (bpp-r);
+#else
+			pat2 = pat << (bpp-r) | pat >> r;
+#endif
+			fill_op(p, dst, dst_idx, pat2, left, right,
 				width*bpp, bits);
-			r = (p->fix.line_length*8) % bpp;
-			pat = pat << (bpp-r) | pat >> r;
 			dst_idx += p->fix.line_length*8;
 		}
 	}
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index 1db6221..fa9626e 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -33,11 +33,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x0101010101010101ul*pixel;
 	case 12:
-		return 0x0001001001001001ul*pixel;
+		return 0x1001001001001001ul*pixel;
 	case 16:
 		return 0x0001000100010001ul*pixel;
 	case 24:
-		return 0x0000000001000001ul*pixel;
+		return 0x0001000001000001ul*pixel;
 	case 32:
 		return 0x0000000100000001ul*pixel;
 	default:
@@ -58,11 +58,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x01010101ul*pixel;
 	case 12:
-		return 0x00001001ul*pixel;
+		return 0x01001001ul*pixel;
 	case 16:
 		return 0x00010001ul*pixel;
 	case 24:
-		return 0x00000001ul*pixel;
+		return 0x01000001ul*pixel;
 	case 32:
 		return 0x00000001ul*pixel;
 	default:
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
index f94d6b6..ff256a4 100644
--- a/drivers/video/sysfillrect.c
+++ b/drivers/video/sysfillrect.c
@@ -124,7 +124,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
 
 		/* Trailing bits */
 		if (last)
-			*dst = comp(pat, *dst, first);
+			*dst = comp(pat, *dst, last);
 	}
 }
 
@@ -242,7 +242,7 @@ bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
 
 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
-	unsigned long pat, fg;
+	unsigned long pat, pat2, fg;
 	unsigned long width = rect->width, height = rect->height;
 	int bits = BITS_PER_LONG, bytes = bits >> 3;
 	u32 bpp = p->var.bits_per_pixel;
@@ -292,17 +292,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
-		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
-
-		right = bpp-left;
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;
@@ -317,12 +316,17 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> (ffs(bits) - 1);
+			dst += dst_idx / bits;
 			dst_idx &= (bits - 1);
-			fill_op(p, dst, dst_idx, pat, left, right,
+			r = dst_idx % bpp;
+			/* rotate pattern to the correct start position */
+#ifdef __LITTLE_ENDIAN
+			pat2 = pat << r | pat >> (bpp-r);
+#else
+			pat2 = pat << (bpp-r) | pat >> r;
+#endif
+			fill_op(p, dst, dst_idx, pat2, left, right,
 				width*bpp, bits);
-			r = (p->fix.line_length*8) % bpp;
-			pat = pat << (bpp-r) | pat >> r;
 			dst_idx += p->fix.line_length*8;
 		}
 	}

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

* Re: [PATCH v2] fbdev: fix fillrect for 24bpp modes
  2009-04-18 18:52     ` [PATCH v2] " Michal Januszewski
@ 2009-04-20 23:07       ` Andrew Morton
  2009-05-01 21:47         ` [PATCH v3] " Michal Januszewski
  2009-04-21  5:10       ` [PATCH v2] " Krzysztof Helt
  1 sibling, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2009-04-20 23:07 UTC (permalink / raw)
  To: spock; +Cc: krzysztof.h1, linux-fbdev-devel, linux-kernel

On Sat, 18 Apr 2009 20:52:34 +0200
Michal Januszewski <spock@gentoo.org> wrote:

>  		while (height--) {
> -			dst += dst_idx >> (ffs(bits) - 1);
> +			dst += dst_idx / bits;
>  			dst_idx &= (bits - 1);
> -			fill_op(p, dst, dst_idx, pat, left, right,
> +			r = dst_idx % bpp;
> +			/* rotate pattern to the correct start position */
> +#ifdef __LITTLE_ENDIAN
> +			pat2 = pat << r | pat >> (bpp-r);
> +#else
> +			pat2 = pat << (bpp-r) | pat >> r;
> +#endif
> +			fill_op(p, dst, dst_idx, pat2, left, right,
>  				width*bpp, bits);
> -			r = (p->fix.line_length*8) % bpp;
> -			pat = pat << (bpp-r) | pat >> r;
>  			dst_idx += p->fix.line_length*8;

hm, that's fairly eye-popping.

Could we do something like

	pat2 = le32_to_cpu(rol32(cpu_to_le32(pat), r));

(might be wrong, but you see what I mean...)

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

* Re: [PATCH v2] fbdev: fix fillrect for 24bpp modes
  2009-04-18 18:52     ` [PATCH v2] " Michal Januszewski
  2009-04-20 23:07       ` Andrew Morton
@ 2009-04-21  5:10       ` Krzysztof Helt
  1 sibling, 0 replies; 7+ messages in thread
From: Krzysztof Helt @ 2009-04-21  5:10 UTC (permalink / raw)
  To: spock; +Cc: Andrew Morton, linux-fbdev-devel, linux-kernel

On Sat, 18 Apr 2009 20:52:34 +0200
Michal Januszewski <spock@gentoo.org> wrote:

> The software fillrect routines do not work properly when the number of
> pixels per machine word is not an integer.  To see that, run the following
> command on a fbdev console with a 24bpp video mode, using a non-accelerated
> driver such as (u)vesafb:
> 
>   reset ; echo -e '\e[41mtest\e[K'
> 
> The expected result is 'test' displayed on a line with red background.
> Instead of that, 'test' has a red background, but the rest of the line
> (rendered using fillrect()) contains a distored colorful pattern.
> 
> This patch fixes the problem by correctly computing rotation shifts.
> It has been tested in a 24bpp mode on 32- and 64-bit little-endian
> machines.
> 
> Signed-off-by: Michał Januszewski <spock@gentoo.org>
> ---

I have tested the patch and it has worked with padded lines.

Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl>

However, there is  a comment from Andrew Morton.

Regards,
Krzysztof

----------------------------------------------------------------------
Gotowka na koncie. Otworz konto direct i wez podwojny limit.
http://link.interia.pl/f2115



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

* [PATCH v3] fbdev: fix fillrect for 24bpp modes
  2009-04-20 23:07       ` Andrew Morton
@ 2009-05-01 21:47         ` Michal Januszewski
  0 siblings, 0 replies; 7+ messages in thread
From: Michal Januszewski @ 2009-05-01 21:47 UTC (permalink / raw)
  To: Andrew Morton; +Cc: krzysztof.h1, linux-fbdev-devel, linux-kernel

The software fillrect routines do not work properly when the number of
pixels per machine word is not an integer.  To see that, run the following
command on a fbdev console with a 24bpp video mode, using a non-accelerated
driver such as (u)vesafb:

  reset ; echo -e '\e[41mtest\e[K'

The expected result is 'test' displayed on a line with red background.
Instead of that, 'test' has a red background, but the rest of the line
(rendered using fillrect()) contains a distored colorful pattern.

This patch fixes the problem by correctly computing rotation shifts.
It has been tested in a 24bpp mode on 32- and 64-bit little-endian
machines.

Signed-off-by: Michał Januszewski <spock@gentoo.org>
Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl>	
---
This is a cleanup of the version 2 of this patch.

diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 64b3576..ba9f58b 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -9,10 +9,6 @@
  *
  * NOTES:
  *
- *  The code for depths like 24 that don't have integer number of pixels per
- *  long is broken and needs to be fixed. For now I turned these types of
- *  mode off.
- *
  *  Also need to add code to deal with cards endians that are different than
  *  the native cpu endians. I also need to deal with MSB position in the word.
  *
@@ -139,7 +135,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
 
 		// Trailing bits
 		if (last)
-			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
 	}
 }
 
@@ -281,7 +277,7 @@ bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
 
 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
-	unsigned long pat, fg;
+	unsigned long pat, pat2, fg;
 	unsigned long width = rect->width, height = rect->height;
 	int bits = BITS_PER_LONG, bytes = bits >> 3;
 	u32 bpp = p->var.bits_per_pixel;
@@ -297,7 +293,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 	else
 		fg = rect->color;
 
-	pat = pixel_to_pat( bpp, fg);
+	pat = pixel_to_pat(bpp, fg);
 
 	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
 	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
@@ -333,17 +329,16 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
-		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
-
-		right = bpp-left;
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;
@@ -352,17 +347,18 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			fill_op = bitfill_unaligned;
 			break;
 		default:
-			printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+			printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
 			fill_op = bitfill_unaligned;
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> (ffs(bits) - 1);
+			dst += dst_idx / bits;
 			dst_idx &= (bits - 1);
-			fill_op(p, dst, dst_idx, pat, left, right,
+			r = dst_idx % bpp;
+			/* rotate pattern to the correct start position */
+			pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
+			fill_op(p, dst, dst_idx, pat2, left, right,
 				width*bpp, bits);
-			r = (p->fix.line_length*8) % bpp;
-			pat = pat << (bpp-r) | pat >> r;
 			dst_idx += p->fix.line_length*8;
 		}
 	}
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index 1db6221..04c01fa 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -33,11 +33,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x0101010101010101ul*pixel;
 	case 12:
-		return 0x0001001001001001ul*pixel;
+		return 0x1001001001001001ul*pixel;
 	case 16:
 		return 0x0001000100010001ul*pixel;
 	case 24:
-		return 0x0000000001000001ul*pixel;
+		return 0x0001000001000001ul*pixel;
 	case 32:
 		return 0x0000000100000001ul*pixel;
 	default:
@@ -58,11 +58,11 @@ pixel_to_pat( u32 bpp, u32 pixel)
 	case 8:
 		return 0x01010101ul*pixel;
 	case 12:
-		return 0x00001001ul*pixel;
+		return 0x01001001ul*pixel;
 	case 16:
 		return 0x00010001ul*pixel;
 	case 24:
-		return 0x00000001ul*pixel;
+		return 0x01000001ul*pixel;
 	case 32:
 		return 0x00000001ul*pixel;
 	default:
@@ -167,4 +167,17 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
 
 #endif  /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
 
+#define cpu_to_le_long _cpu_to_le_long(BITS_PER_LONG)
+#define _cpu_to_le_long(x) __cpu_to_le_long(x)
+#define __cpu_to_le_long(x) cpu_to_le##x
+
+#define le_long_to_cpu _le_long_to_cpu(BITS_PER_LONG)
+#define _le_long_to_cpu(x) __le_long_to_cpu(x)
+#define __le_long_to_cpu(x) le##x##_to_cpu
+
+static inline unsigned long rolx(unsigned long word, unsigned int shift, unsigned int x)
+{
+	return (word << shift) | (word >> (x - shift));
+}
+
 #endif /* FB_DRAW_H */
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
index f94d6b6..33ee3d3 100644
--- a/drivers/video/sysfillrect.c
+++ b/drivers/video/sysfillrect.c
@@ -124,7 +124,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
 
 		/* Trailing bits */
 		if (last)
-			*dst = comp(pat, *dst, first);
+			*dst = comp(pat, *dst, last);
 	}
 }
 
@@ -242,7 +242,7 @@ bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
 
 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
-	unsigned long pat, fg;
+	unsigned long pat, pat2, fg;
 	unsigned long width = rect->width, height = rect->height;
 	int bits = BITS_PER_LONG, bytes = bits >> 3;
 	u32 bpp = p->var.bits_per_pixel;
@@ -292,17 +292,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			dst_idx += p->fix.line_length*8;
 		}
 	} else {
-		int right;
-		int r;
-		int rot = (left-dst_idx) % bpp;
+		int right, r;
 		void (*fill_op)(struct fb_info *p, unsigned long *dst,
 				int dst_idx, unsigned long pat, int left,
 				int right, unsigned n, int bits) = NULL;
-
-		/* rotate pattern to correct start position */
-		pat = pat << rot | pat >> (bpp-rot);
-
-		right = bpp-left;
+#ifdef __LITTLE_ENDIAN
+		right = left;
+		left = bpp - right;
+#else
+		right = bpp - left;
+#endif
 		switch (rect->rop) {
 		case ROP_XOR:
 			fill_op = bitfill_unaligned_rev;
@@ -311,18 +310,19 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 			fill_op = bitfill_unaligned;
 			break;
 		default:
-			printk(KERN_ERR "cfb_fillrect(): unknown rop, "
+			printk(KERN_ERR "sys_fillrect(): unknown rop, "
 				"defaulting to ROP_COPY\n");
 			fill_op = bitfill_unaligned;
 			break;
 		}
 		while (height--) {
-			dst += dst_idx >> (ffs(bits) - 1);
+			dst += dst_idx / bits;
 			dst_idx &= (bits - 1);
-			fill_op(p, dst, dst_idx, pat, left, right,
+			r = dst_idx % bpp;
+			/* rotate pattern to the correct start position */
+			pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
+			fill_op(p, dst, dst_idx, pat2, left, right,
 				width*bpp, bits);
-			r = (p->fix.line_length*8) % bpp;
-			pat = pat << (bpp-r) | pat >> r;
 			dst_idx += p->fix.line_length*8;
 		}
 	}



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

end of thread, other threads:[~2009-05-01 21:47 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-13 17:09 [PATCH] fbdev: fix fillrect for 24bpp modes Michal Januszewski
2009-04-17 16:36 ` [Linux-fbdev-devel] " Krzysztof Helt
2009-04-17 18:50   ` Andrew Morton
2009-04-18 18:52     ` [PATCH v2] " Michal Januszewski
2009-04-20 23:07       ` Andrew Morton
2009-05-01 21:47         ` [PATCH v3] " Michal Januszewski
2009-04-21  5:10       ` [PATCH v2] " Krzysztof Helt

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