blob: 4a5a1ab654d753108b872722ac0b2d2b5d4c56f8 [file] [log] [blame]
/*
* Generic low-level drawing operations for a cfb frame buffer
*
* (C) Copyright 2002 Geert Uytterhoeven
*
* 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.
*/
#include "types.h"
#include "drawops.h"
#include "bitstream.h"
#include "fb.h"
#define EXP1(x) 0xffffffffU*x
#define EXP2(x) 0x55555555U*x
#define EXP4(x) 0x11111111U*0x ## x
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)
};
static u32 next_line;
int cfb_init(void)
{
if (fb_fix.type != FB_TYPE_PACKED_PIXELS || fb_var.bits_per_pixel > 32)
return 0;
next_line =
fb_fix.line_length ? fb_fix.line_length
: fb_var.xres_virtual*fb_var.bits_per_pixel/8;
return 1;
}
/*
* Expand a pixel value to a 32-bit pattern
*/
static inline u32 pixel_to_pat32(pixel_t pixel)
{
u32 pat = pixel;
switch (fb_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(pixel_t pixel, int left)
{
unsigned long pat = pixel;
u32 bpp = fb_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;
}
void cfb_draw_hline(u32 x, u32 y, u32 length, pixel_t pixel)
{
unsigned long *dst;
int dst_idx, left, right;
u32 bpp = fb_var.bits_per_pixel;
dst = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
dst_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
dst_idx += y*next_line*8+x*bpp;
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
/* FIXME For now we support 1-32 bpp only */
left = BITS_PER_LONG % bpp;
if (!left) {
u32 pat = pixel_to_pat32(pixel);
bitfill32(dst, dst_idx, pat, length*bpp);
} else {
unsigned long pat;
#if __BYTE_ORDER == __LITTLE_ENDIAN
right = left;
left = bpp-left;
#else
right = bpp-left;
#endif
pat = pixel_to_pat(pixel, (left-dst_idx) % bpp);
bitfill(dst, dst_idx, pat, left, right, length*bpp);
}
}
void cfb_fill_rect(u32 x, u32 y, u32 width, u32 height, pixel_t pixel)
{
unsigned long *dst;
int dst_idx, left, right;
u32 bpp = fb_var.bits_per_pixel;
dst = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
dst_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
dst_idx += y*next_line*8+x*bpp;
/* FIXME For now we support 1-32 bpp only */
left = BITS_PER_LONG % bpp;
if (!left) {
u32 pat = pixel_to_pat32(pixel);
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
bitfill32(dst, dst_idx, pat, width*bpp);
dst_idx += next_line*8;
}
} else {
unsigned long pat;
int r;
#if __BYTE_ORDER == __LITTLE_ENDIAN
right = left;
left = bpp-left;
#else
right = bpp-left;
#endif
pat = pixel_to_pat(pixel, (left-dst_idx) % bpp);
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
bitfill(dst, dst_idx, pat, left, right, width*bpp);
r = (next_line*8) % bpp;
pat = pat << (bpp-r) | pat >> r;
dst_idx += next_line*8;
}
}
}
void cfb_copy_rect(u32 dx, u32 dy, u32 width, u32 height, u32 sx, u32 sy)
{
unsigned long *dst, *src;
int dst_idx, src_idx;
u32 bpp = fb_var.bits_per_pixel;
int rev_copy = 0;
if (dy > sy || (dy == sy && dx > sx)) {
dy += height;
sy += height;
rev_copy = 1;
}
dst = src = (unsigned long *)((unsigned long)fb & ~(BYTES_PER_LONG-1));
dst_idx = src_idx = ((unsigned long)fb & (BYTES_PER_LONG-1))*8;
dst_idx += dy*next_line*8+dx*bpp;
src_idx += sy*next_line*8+sx*bpp;
if (rev_copy) {
while (height--) {
dst_idx -= next_line*8;
src_idx -= next_line*8;
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
src += src_idx >> SHIFT_PER_LONG;
src_idx &= (BITS_PER_LONG-1);
bitcpy_rev(dst, dst_idx, src, src_idx, width*bpp);
}
} else {
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
src += src_idx >> SHIFT_PER_LONG;
src_idx &= (BITS_PER_LONG-1);
bitcpy(dst, dst_idx, src, src_idx, width*bpp);
dst_idx += next_line*8;
src_idx += next_line*8;
}
}
}