From: Mikulas P. <mpa...@re...> - 2009-06-17 10:16:25
|
On my card, the accelerator corrupts display if its line length is not multiple of 64 bytes. Misaligned lines in the drawn recrangle are shifted left, as if the accelerator thought that every line begins on 64-byte boundary. For example, in 800x600x8 (scanlines are aligned on 32 bytes) every odd scanline is drawn shifted by 32 bytes to the left. The card is ATI Technologies Inc 3D Rage Pro 215GP (rev 5c) onboard on Sparc64 Ultra 5. This patch disables accelerator if scanline is not multiple of 64 bytes. I don't have any other cards to test. If someone tests that his card doesn't have this bug, he can whitelist it. (note: if you find a better place where to disable the accelerator on non-conforming modes, do it there) Signed-off-by: Mikulas Patocka <mpa...@re... --- drivers/video/aty/mach64_accel.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) Index: linux-2.6.30-fast/drivers/video/aty/mach64_accel.c =================================================================== --- linux-2.6.30-fast.orig/drivers/video/aty/mach64_accel.c 2009-06-17 08:49:01.000000000 +0200 +++ linux-2.6.30-fast/drivers/video/aty/mach64_accel.c 2009-06-17 10:46:03.000000000 +0200 @@ -35,6 +35,14 @@ static u32 rotation24bpp(u32 dx, u32 dir return ((rotation << 8) | DST_24_ROTATION_ENABLE); } +static inline int no_accel(struct fb_info *info) +{ + /* + * The lines must be aligned on 64-byte boundary. + */ + return (info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3)) & 63; +} + void aty_reset_engine(const struct atyfb_par *par) { /* reset engine */ @@ -199,7 +207,7 @@ void atyfb_copyarea(struct fb_info *info return; if (!area->width || !area->height) return; - if (!par->accel_flags) { + if (!par->accel_flags || no_accel(info)) { cfb_copyarea(info, area); return; } @@ -245,7 +253,7 @@ void atyfb_fillrect(struct fb_info *info return; if (!rect->width || !rect->height) return; - if (!par->accel_flags) { + if (!par->accel_flags || no_accel(info)) { cfb_fillrect(info, rect); return; } @@ -285,7 +293,7 @@ void atyfb_imageblit(struct fb_info *inf return; if (!image->width || !image->height) return; - if (!par->accel_flags || + if (!par->accel_flags || no_accel(info) || (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { cfb_imageblit(info, image); return; |