Console Rotation
PATCH 1/1 Console Rotation
The patch (fb_drawing.diff) is an optional replacement to cfbimgblt.c, cfbfillrect.c and cfbcopyarea.c. Rotating the display CW or CCW will expose some of the limitations (alignment and access) of the current drawing functions because fontheight is very variable. This also fixes software clipping.
cfbcopyarea.c is just a 'copy 'n paste' of Geert's version I leached from fbutils (I hope this is okay with you, Geert :) The only changes are using FB_WRITEL and FB_READL where appropriate.
Tony
<<------------------------------------------------------------------->>
drivers/video/cfbcopyarea.c +342 -165
@@ -28,22 +28,319 @@#include <asm/io.h> #include <video/fbcon.h> +#include "fbcon-rotate.h" + +#define LONG_MASK (BITS_PER_LONG - 1) +#if BITS_PER_LONG ==32 -#define FB_READ fb_readl -#define FB_WRITE fb_writel +#define FB_WRITEL fb_writel +#define FB_READL fb_readl +#define SHIFT_PER_LONG 5 +#define BYTES_PER_LONG 4#else -#define FB_READ fb_readq -#define FB_WRITE fb_writeq +#define FB_WRITEL fb_writeq +#define FB_READL fb_readq(x) +#define SHIFT_PER_LONG 6 +#define BYTES_PER_LONG 8#endif +static void bitcpy (unsigned long *dst,int dst_idx,const unsigned long *src, +int src_idx,unsigned long n) +{ +unsigned long first, last; +int shift = dst_idx-src_idx, left, right; +unsigned long d0, d1; +int m; + +if (!n) +return ; + + shift = dst_idx-src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) %BITS_PER_LONG )); + +if (!shift) { +// Same alignment for source and dest + +if (dst_idx+n <=BITS_PER_LONG ) { +// Single word +if (last) + first &= last; +FB_WRITEL ((*src & first) | (FB_READL (dst) & ~first), dst); + }else { +// Multiple destination words +// Leading bits +if (first) { + +FB_WRITEL ((*src & first) | (FB_READL (dst) & ~first), dst); + dst++; + src++; + n -=BITS_PER_LONG -dst_idx; + } + +// Main chunk + n /=BITS_PER_LONG ; +while (n >=8 ) { +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); +FB_WRITEL (*src++, dst++); + n -=8 ; + } +while (n--) +FB_WRITEL (*src++, dst++); +// Trailing bits +if (last) +FB_WRITEL ((*src & last) | (FB_READL (dst) & ~last), dst); + } + }else { +// Different alignment for source and dest + + right = shift & (BITS_PER_LONG -1 ); + left = -shift & (BITS_PER_LONG -1 ); + +if (dst_idx+n <=BITS_PER_LONG ) { +// Single destination word +if (last) + first &= last; +if (shift >0 ) { +// Single source word +FB_WRITEL (((*src >> right) & first) | (FB_READL (dst) & ~first), dst); + }else if (src_idx+n <=BITS_PER_LONG ) { +// Single source word +FB_WRITEL (((*src << left) & first) | (FB_READL (dst) & ~first), dst); + }else { +// 2 source words + d0 = *src++; + d1 = *src; +FB_WRITEL (((d0 << left | d1 >> right) & first) | (FB_READL (dst) & ~first), dst); + } + }else { +// Multiple destination words + d0 = *src++; +// Leading bits +if (shift >0 ) { +// Single source word +FB_WRITEL (((d0 >> right) & first) | (FB_READL (dst) & ~first), dst); + dst++; + n -=BITS_PER_LONG -dst_idx; + }else { +// 2 source words + d1 = *src++; +FB_WRITEL (((d0 << left | d1 >> right) & first) | (FB_READL (dst) & ~first), dst); + d0 = d1; + dst++; + n -=BITS_PER_LONG -dst_idx; + } + +// Main chunk + m = n %BITS_PER_LONG ; + n /=BITS_PER_LONG ; +while (n >=4 ) { + d1 = *src++; +FB_WRITEL (d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = *src++; +FB_WRITEL (d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = *src++; +FB_WRITEL (d0 << left | d1 >> right, dst++); + d0 = d1; + d1 = *src++; +FB_WRITEL (d0 << left | d1 >> right, dst++); + d0 = d1; + n -=4 ; + } +while (n--) { + d1 = *src++; +FB_WRITEL (d0 << left | d1 >> right, dst++); + d0 = d1; + } + +// Trailing bits +if (last) { +if (m <= right) { +// Single source word +FB_WRITEL (((d0 << left) & last) | (FB_READL (dst) & ~last), dst); + }else { +// 2 source words + d1 = *src; +FB_WRITEL (((d0 << left | d1 >> right) & last) | (FB_READL (dst) & ~last), dst); + } + } + } + } +} + +static void bitcpy_rev (unsigned long *dst,int dst_idx, +const unsigned long *src,int src_idx,unsigned long n) +{ +unsigned long first, last; +int shift = dst_idx-src_idx, left, right; +unsigned long d0, d1; +int m; + +if (!n) +return ; + + dst += (n-1 )/BITS_PER_LONG ; + src += (n-1 )/BITS_PER_LONG ; +if ((n-1 ) %BITS_PER_LONG ) { + dst_idx += (n-1 ) %BITS_PER_LONG ; + dst += dst_idx >>SHIFT_PER_LONG ; + dst_idx &=BITS_PER_LONG -1 ; + src_idx += (n-1 ) %BITS_PER_LONG ; + src += src_idx >>SHIFT_PER_LONG ; + src_idx &=BITS_PER_LONG -1 ; + } + + shift = dst_idx-src_idx; + first = ~0UL << (BITS_PER_LONG -1 -dst_idx); + last = ~(~0UL << (BITS_PER_LONG -1 -((dst_idx-n) %BITS_PER_LONG ))); + +if (!shift) { +// Same alignment for source and dest + +if ((unsigned long )dst_idx+1 >= n) { +// Single word +if (last) + first &= last; +FB_WRITEL ((*src & first) | (FB_READL (dst) & ~first), dst); + }else { +// Multiple destination words +// Leading bits +if (first) { +FB_WRITEL ((*src & first) | (FB_READL (dst) & ~first), dst); + dst--; + src--; + n -= dst_idx+1 ; + } + +// Main chunk + n /=BITS_PER_LONG ; +while (n >=8 ) { +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); +FB_WRITEL (*src--, dst--); + n -=8 ; + } +while (n--) +FB_WRITEL (*src--, dst--); + +// Trailing bits +if (last) +FB_WRITEL ((*src & last) | (FB_READL (dst) & ~last), dst); + } + }else { +// Different alignment for source and dest + + right = shift & (BITS_PER_LONG -1 ); + left = -shift & (BITS_PER_LONG -1 ); + +if ((unsigned long )dst_idx+1 >= n) { +// Single destination word +if (last) + first &= last; +if (shift <0 ) { +// Single source word +FB_WRITEL ((*src << left & first) | (FB_READL (dst) & ~first), dst); + }else if (1 +(unsigned long )src_idx >= n) { +// Single source word +FB_WRITEL (((*src >> right) & first) | (FB_READL (dst) & ~first), dst); + }else { +// 2 source words + d0 = *src--; + d1 = *src; +FB_WRITEL (((d0 >> right | d1 << left) & first) | (FB_READL (dst) & ~first), dst); + } + }else { +// Multiple destination words + d0 = *src--; +// Leading bits +if (shift <0 ) { +// Single source word +FB_WRITEL (((d0 << left) & first) | (FB_READL (dst) & ~first), dst); + dst--; + n -= dst_idx+1 ; + }else { +// 2 source words + d1 = *src--; +FB_WRITEL (((d0 >> right | d1 << left) & first) | (FB_READL (dst) & ~first), dst); + d0 = d1; + dst--; + n -= dst_idx+1 ; + } + +// Main chunk + m = n %BITS_PER_LONG ; + n /=BITS_PER_LONG ; +while (n >=4 ) { + d1 = *src--; +FB_WRITEL (d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = *src--; +FB_WRITEL (d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = *src--; +FB_WRITEL (d0 >> right | d1 << left, dst--); + d0 = d1; + d1 = *src--; +FB_WRITEL (d0 >> right | d1 << left, dst--); + d0 = d1; + n -=4 ; + } +while (n--) { + d1 = *src--; +FB_WRITEL (d0 >> right | d1 << left, dst--); + d0 = d1; + } + +// Trailing bits +if (last) { +if (m <= left) { +// Single source word +FB_WRITEL (((d0 >> right) & last) | (FB_READL (dst) & ~last), dst); + }else { +// 2 source words + d1 = *src; +FB_WRITEL (((d0 >> right | d1 << left) & last) | + (FB_READL (dst) & ~last), dst); + } + } + } + } +} +void cfb_copyarea (struct fb_info *p,struct fb_copyarea *area) { -int x2, y2, lineincr, shift, shift_right, shift_left, old_dx, old_dy; -int j, linesize = p->fix.line_length, bpl =sizeof (unsigned long ); -unsigned long start_index, end_index, start_mask, end_mask, last; +int x2, y2, old_dx, old_dy, vxres, vyres; +unsigned long next_line = p->fix.line_length; +int dst_idx =0 , src_idx =0 , rev_copy =0 ;unsigned long *dst =NULL , *src =NULL ; -char *src1, *dst1; -int tmp, height; + + vxres = p->var.xres_virtual; + vyres = p->var.yres_virtual; +#ifdef FBCON_HAS_ROTATE +if (p->var.vmode & (FB_VMODE_ROTATE_CW |FB_VMODE_ROTATE_CCW )) { + vxres = p->var.yres_virtual; + vyres = p->var.xres_virtual; + } +#endif + +if (area->dx > vxres || + area->sx > vxres || + area->dy > vyres || + area->sy > vyres) +return ;/* clip the destination */ old_dx = area->dx;
@@ -57,8 +354,8 @@ y2 = area->dy + area->height; area->dx = area->dx >0 ? area->dx :0 ; area->dy = area->dy >0 ? area->dy :0 ; - x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual; - y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; area->width = x2 - area->dx; area->height = y2 - area->dy;
@@ -66,165 +363,45 @@ area->sx += (area->dx - old_dx); area->sy += (area->dy - old_dy); - height = area->height; -/* the source must be completely inside the virtual screen */ if (area->sx <0 || area->sy <0 || - (area->sx + area->width) > p->var.xres_virtual || - (area->sy + area->height) > p->var.yres_virtual) + (area->sx + area->width) > vxres || + (area->sy + area->height) > vyres)return ; -if (area->dy < area->sy - || (area->dy == area->sy && area->dx < area->sx)) { -/* start at the top */ - src1 = p->screen_base + area->sy * linesize + - ((area->sx * p->var.bits_per_pixel) >>3 ); - dst1 = p->screen_base + area->dy * linesize + - ((area->dx * p->var.bits_per_pixel) >>3 ); - lineincr = linesize; - }else { -/* start at the bottom */ - src1 = p->screen_base + (area->sy + area->height-1 ) * linesize - + (((area->sx + area->width -1 ) * p->var.bits_per_pixel) >>3 ); - dst1 = p->screen_base + (area->dy + area->height-1 ) * linesize - + (((area->dx + area->width -1 ) * p->var.bits_per_pixel) >>3 ); - lineincr = -linesize; +if (area->dy > area->sy || (area->dy == area->sy && area->dx > area->sx)) { + area->dy += area->height; + area->sy += area->height; + rev_copy =1 ; } - -if ((BITS_PER_LONG % p->var.bits_per_pixel) ==0 ) { -int ppw =BITS_PER_LONG / p->var.bits_per_pixel; -int n = ((area->width * p->var.bits_per_pixel) >>3 ); - - start_index = ((unsigned long ) src1 & (bpl -1 )); - end_index = ((unsigned long ) (src1 + n) & (bpl -1 )); - shift = ((unsigned long ) dst1 & (bpl -1 )) - - ((unsigned long ) src1 & (bpl -1 )); - start_mask = end_mask =0 ; - -if (start_index) { - start_mask =-1 >> (start_index <<3 ); - n -= (bpl - start_index); + + dst = src = (unsigned long *)((unsigned long )p->screen_base & ~(BYTES_PER_LONG -1 )); + dst_idx = src_idx = (unsigned long )p->screen_base & (BYTES_PER_LONG -1 ); + dst_idx += area->dy*next_line*8 +area->dx*p->var.bits_per_pixel; + src_idx += area->sy*next_line*8 +area->sx*p->var.bits_per_pixel; + +if (rev_copy) { +while (area->height--) { + dst_idx -= next_line*8 ; + src_idx -= next_line*8 ; + dst += dst_idx >>SHIFT_PER_LONG ; + dst_idx &= (BYTES_PER_LONG -1 ); + src += src_idx >>SHIFT_PER_LONG ; + src_idx &= (BYTES_PER_LONG -1 ); +bitcpy_rev ((unsigned long *)dst, dst_idx, (unsigned long *)src, + src_idx, area->width*p->var.bits_per_pixel); } - -if (end_index) { - end_mask =-1 << ((bpl - end_index) <<3 ); - n -= end_index; - } - n /= bpl; - -if (n <=0 ) { -if (start_mask) { -if (end_mask) - end_mask &= start_mask; -else - end_mask = start_mask; - start_mask =0 ; - } - n =0 ; - } - -if (shift) { -if (shift >0 ) { -/* dest is over to right more */ - shift_right = - shift * p->var.bits_per_pixel; - shift_left = - (ppw - shift) * p->var.bits_per_pixel; - }else { -/* source is to the right more */ - shift_right = - (ppw + shift) * p->var.bits_per_pixel; - shift_left = - -shift * p->var.bits_per_pixel; - } -/* general case, positive increment */ -if (lineincr >0 ) { -if (shift <0 ) - n++; -do { - dst = (unsigned long *) dst1; - src = (unsigned long *) src1; - - last = (FB_READ (src) & start_mask); - -if (shift >0 ) -FB_WRITE (FB_READ (dst) | (last >> shift_right), dst); -for (j =0 ; j < n; j++) { - dst++; - tmp =FB_READ (src); - src++; -FB_WRITE ((last << shift_left) | (tmp >> shift_right), dst); - last = tmp; - src++; - } -FB_WRITE (FB_READ (dst) | (last << shift_left), dst); - src1 += lineincr; - dst1 += lineincr; - }while (--height); - }else { -/* general case, negative increment */ -if (shift >0 ) - n++; -do { - dst = (unsigned long *) dst1; - src = (unsigned long *) src1; - - last = (FB_READ (src) & end_mask); - -if (shift <0 ) -FB_WRITE (FB_READ (dst) | (last >> shift_right), dst); -for (j =0 ; j < n; j++) { - dst--; - tmp =FB_READ (src); - src--; -FB_WRITE ((tmp << shift_left) | (last >> shift_right), dst); - last = tmp; - src--; - } -FB_WRITE (FB_READ (dst) | (last >> shift_right), dst); - src1 += lineincr; - dst1 += lineincr; - }while (--height); - } - }else { -/* no shift needed */ -if (lineincr >0 ) { -/* positive increment */ -do { - dst = (unsigned long *) (dst1 - start_index); - src = (unsigned long *) (src1 - start_index); - -if (start_mask) -FB_WRITE (FB_READ (src) | start_mask, dst); - -for (j =0 ; j < n; j++) { -FB_WRITE (FB_READ (src), dst); - dst++; - src++; - } - -if (end_mask) -FB_WRITE (FB_READ (src) | end_mask, dst); - src1 += lineincr; - dst1 += lineincr; - }while (--height); - }else { -/* negative increment */ -do { - dst = (unsigned long *) dst1; - src = (unsigned long *) src1; - -if (start_mask) -FB_WRITE (FB_READ (src) | start_mask, dst); -for (j =0 ; j < n; j++) { -FB_WRITE (FB_READ (src), dst); - dst--; - src--; - } - src1 += lineincr; - dst1 += lineincr; - }while (--height); - } + } +else { +while (area->height--) { + dst += dst_idx >>SHIFT_PER_LONG ; + dst_idx &= (BYTES_PER_LONG -1 ); + src += src_idx >>SHIFT_PER_LONG ; + src_idx &= (BYTES_PER_LONG -1 ); +bitcpy ((unsigned long *)dst, dst_idx, (unsigned long *)src, + src_idx, area->width*p->var.bits_per_pixel); + dst_idx += next_line*8 ; + src_idx += next_line*8 ; } } -} +}
drivers/video/cfbfillrect.c +139 -140
307 lines not on this page · raw message
drivers/video/cfbimgblt.c +286 -66
389 lines not on this page · raw message
-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old cell phone? Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
Quoted 3 lines · Antonino Daplas
cfbcopyarea.cis just a 'copy 'n paste' of Geert's version I leached from fbutils (I hope this is okay with you, Geert :) The only changes are usingFB_WRITELandFB_READLwhere appropriate.
Of course (actually that was my intention ;-)
Did you measure any noticeable differences (performance-wise) with the old routines?
BTW, expect a fillrect() for arbitrary bitdepths soon...
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: OSDN - Tired of that same old cell phone? Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
Quoted 6 lines · Geert Uytterhoeven
Quoted 3 lines · Antonino Daplas
cfbcopyarea.cis just a 'copy 'n paste' of Geert's version I leached from fbutils (I hope this is okay with you, Geert :) The only changes are usingFB_WRITELandFB_READLwhere appropriate.Of course (actually that was my intention ;-)
Thanks.
Quoted 4 lines
Did you measure any noticeable differences (performance-wise) with the old routines?
Yes, but not by much, something like less than a second. But I haven't really done a test where the primary operation is copyarea... Will this be affected by the the setting of display->scrollmode? I use SCROLL_YREDRAW.
Quoted 1 line
BTW, expect a
fillrect()for arbitrary bitdepths soon...
This is good :) The one I included should do that too, but it is terribly inefficient.
Tony
-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old cell phone? Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
Quoted 13 lines · Antonino Daplas
Quoted 6 lines · Geert Uytterhoeven
Quoted 3 lines · Antonino Daplas
cfbcopyarea.cis just a 'copy 'n paste' of Geert's version I leached from fbutils (I hope this is okay with you, Geert :) The only changes are usingFB_WRITELandFB_READLwhere appropriate.Of course (actually that was my intention ;-)
Thanks.
Quoted 4 lines
Did you measure any noticeable differences (performance-wise) with the old routines?
Quoted 8 lines
Yes, but not by much, something like less than a second. But I haven't really done a test where the primary operation is copyarea... Will this be affected by the the setting of
display->scrollmode? I useSCROLL_YREDRAW.Quoted 1 line
BTW, expect a
fillrect()for arbitrary bitdepths soon...This is good :) The one I included should do that too, but it is terribly inefficient.
The fillrect() for arbitrary bitdepths is in fbtest now. I also added fast support for planar screens. Well, now I can start porting amifb to the accel framework.
So far I tested fbtest on
- PPC (atyfb on 3D RAGE II+, cfb)
- m68k (amifb on Amiga AGA, planar)
- Alpha (tgafb on DEC UDB with 8-bit TGA, cfb)
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
Quoted 5 lines · Geert Uytterhoeven
The
fillrect()for arbitrary bitdepths is in fbtest now. I also added fast support for planar screens. Well, now I can start porting amifb to the accel framework.
I modified your fillrect for cfbfillrect.c. Just added support for ROP_XOR.
Here's also some rudimentary benchmarks:
fill/copy a 256x256 rectangle 1000 times (8bpp):
old new copyarea 4.930s 5.151s fillrect(ROP_COPY) 0.136s 0.256s fillrect(ROP_XOR) 4.059s 3.903s
Tony
/*
* Generic fillrect for frame buffers with packed pixels of any depth. *
* Copyright (C) 2000 James Simmons ([email protected])
*
* This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details.
*
* NOTES:
* ++Tony: Based on fbtest (cfb.c bitstream.c) by Geert Uytterhoeven. *
*/
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
#include <video/fbcon.h>
#if BITS_PER_LONG == 32
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
#define BYTES_PER_LONG 4
#define SHIFT_PER_LONG 5
#else
#define FB_WRITEL fb_writeq
#define FB_READL fb_readq
#define BYTES_PER_LONG 8
#define SHIFT_PER_LONG 6
#endif
#define EXP1(x) 0xffffffffU*x
#define EXP2(x) 0x55555555U*x
#define EXP4(x) 0x11111111U*0x ## x
typedef u32 pixel_t;
static const u32 bpp1tab[2] = {
EXP1(0), EXP1(1)
};static const u32 bpp2tab[4] = {
EXP2(0), EXP2(1), EXP2(2), EXP2(3)
};static const u32 bpp4tab[16] = {
EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
}; /*
* Compose two values, using a bitmask as decision value
* This is equivalent to (a & mask) | (b & ~mask) */
static inline unsigned long comp(unsigned long a, unsigned long b,
unsigned long mask)
{
return ((a ^ b) & mask) ^ b;
}static inline u32 pixel_to_pat32(const struct fb_info *p, pixel_t pixel)
{
u32 pat = pixel;
switch (p->var.bits_per_pixel) {
case 1:
pat = bpp1tab[pat];
break;
case 2:
pat = bpp2tab[pat];
break;
case 4:
pat = bpp4tab[pat];
break;
case 8:
pat |= pat << 8;
// Fall through
case 16:
pat |= pat << 16;
// Fall through
case 32:
break;
}
return pat;
} /*
* Expand a pixel value to a generic 32/64-bit pattern and rotate it to
* the correct start position
*/
static inline unsigned long pixel_to_pat(const struct fb_info *p, pixel_t pixel, int left)
{
unsigned long pat = pixel;
u32 bpp = p->var.bits_per_pixel;
int i;
/* expand pixel value */
for (i = bpp; i < BITS_PER_LONG; i *= 2)
pat |= pat << i;
/* rotate pattern to correct start position */
pat = pat << left | pat >> (bpp-left);
return pat;
} /*
* Unaligned 32-bit pattern fill using 32/64-bit memory accesses
*/void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
{
unsigned long val = pat;
unsigned long first, last;
if (!n)
return;#if BITS_PER_LONG == 64
val |= val << 32;
#endif
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
dst++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
n -= 8;
}
while (n--)
FB_WRITEL(val, dst++);
// Trailing bits
if (last)
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
}
} /*
* Unaligned generic pattern fill using 32/64-bit memory accesses
* The pattern must have been expanded to a full 32/64-bit value
* Left/right are the appropriate shifts to convert to the pattern to be
* used for the next 32/64-bit word
*/
void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left,
int right, u32 n)
{
unsigned long first, last;
if (!n)
return;
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
dst++;
pat = pat << left | pat >> right;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 4) {
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
n -= 4;
}
while (n--) {
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
}
// Trailing bits
if (last)
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
}
}void bitfill32_xor(unsigned long *dst, int dst_idx, u32 pat, u32 n)
{
unsigned long val = pat, dat;
unsigned long first, last;
if (!n)
return;#if BITS_PER_LONG == 64
val |= val << 32;
#endif
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
dst++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
n -= 8;
}
while (n--) {
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
}
// Trailing bits
if (last) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
}
}
} /*
* Unaligned generic pattern fill using 32/64-bit memory accesses
* The pattern must have been expanded to a full 32/64-bit value
* Left/right are the appropriate shifts to convert to the pattern to be
* used for the next 32/64-bit word
*/
void bitfill_xor(unsigned long *dst, int dst_idx, unsigned long pat, int left,
int right, u32 n)
{
unsigned long first, last, dat;
if (!n)
return;
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
dst++;
pat = pat << left | pat >> right;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 4) {
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
n -= 4;
}
while (n--) {
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
}
// Trailing bits
if (last) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
}
}
}void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect)
{
unsigned long height, fg;
unsigned long x2, y2, vxres, vyres;
unsigned long *dst;
int dst_idx, left;
u32 bpp = p->var.bits_per_pixel;
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
if (!rect->width || !rect->height ||
rect->dx > vxres ||
rect->dy > vyres)
return;
/* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly. */
x2 = rect->dx + rect->width;
y2 = rect->dy + rect->height;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
rect->width = x2 - rect->dx;
height = y2 - rect->dy;
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR )
fg = ((u32 *) (p->pseudo_palette))[rect->color];
else
fg = rect->color;
dst = (unsigned long *)((unsigned long)p->screen_base & ~(BYTES_PER_LONG-1));
dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8;
dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
/* FIXME For now we support 1-32 bpp only */
left = BITS_PER_LONG % bpp;
if (!left) {
u32 pat = pixel_to_pat32(p, fg);
void (*fill_op32)(unsigned long *dst, int dst_idx, u32 pat, u32 n) = NULL;
switch (rect->rop) {
case ROP_XOR:
fill_op32 = bitfill32_xor;
break;
case ROP_COPY:
default:
fill_op32 = bitfill32;
break;
}
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
fill_op32(dst, dst_idx, pat, rect->width*bpp);
dst_idx += p->fix.line_length*8;
}
} else {
unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp);
int right = bpp-left;
int r;
void (*fill_op)(unsigned long *dst, int dst_idx, unsigned long pat,
int left, int right, u32 n) = NULL;
switch (rect->rop) {
case ROP_XOR:
fill_op = bitfill_xor;
break;
case ROP_COPY:
default:
fill_op = bitfill;
break;
}
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
fill_op(dst, dst_idx, pat, left, right, rect->width*bpp);
r = (p->fix.line_length*8) % bpp;
pat = pat << (bpp-r) | pat >> r;
dst_idx += p->fix.line_length*8;
}
}
}Quoted 8 lines · Antonino Daplas
Quoted 4 lines · Geert Uytterhoeven
The
fillrect()for arbitrary bitdepths is in fbtest now. I also added fast support for planar screens. Well, now I can start porting amifb to the accel framework.I modified your fillrect for
cfbfillrect.c. Just added support forROP_XOR.
Quoted 8 lines
Here's also some rudimentary benchmarks:
fill/copy a 256x256 rectangle 1000 times (8bpp):
old new copyarea 4.930s 5.151s fillrect(ROP_COPY) 0.136s 0.256s fillrect(ROP_XOR) 4.059s 3.903s
Yes, there is still room for optimization...
If next_line is a multiple of BYTES_PER_LONG, there's no need to recalculate the first and last masks.
Even if next_line is not a multiple of BYTES_PER_LONG, the first and last masks are periodic, and can be precalculated and put in a table (4 entries on 32-bit and 8 entries on 64-bit).
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