Commit 2a66d9e5 authored by James Simmons's avatar James Simmons

[FBDEV] Enhanced data buffer management for drawing very large images.

parent f6f9b577
......@@ -134,8 +134,6 @@ static void fbcon_free_font(struct display *);
static int fbcon_set_origin(struct vc_data *);
static int cursor_drawn;
#define FBCON_PIXMAPSIZE 8192
#define CURSOR_DRAW_DELAY (1)
/* # VBL ints between cursor state changes */
......@@ -300,83 +298,6 @@ void set_con2fb_map(int unit, int newidx)
/*
* drawing helpers
*/
static inline void sysmove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
dst[j] = *src++;
dst += d_pitch;
}
}
static inline void iomove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
info->pixmap.outbuf(*src++, dst+j);
dst += d_pitch;
}
}
static inline void sysmove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high,
u32 shift_low, u32 mod, u32 idx,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
dst[j] &= mask;
dst[j] |= *src >> shift_low;
dst[j+1] = *src << shift_high;
src++;
}
dst[idx] &= mask;
dst[idx] |= *src >> shift_low;
if (shift_high < mod)
dst[idx+1] = *src<<shift_high;
src++;
dst += d_pitch;
}
}
static inline void iomove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high,
u32 shift_low,u32 mod, u32 idx,
struct fb_info *info)
{
int i, j;
u8 tmp;
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
tmp = info->pixmap.inbuf(dst+j);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+j);
info->pixmap.outbuf(*src << shift_high, dst+j+1);
src++;
}
tmp = info->pixmap.inbuf(dst+idx);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+idx);
if (shift_high < mod)
info->pixmap.outbuf(*src<<shift_high, dst+idx+1);
src++;
dst += d_pitch;
}
}
static void putcs_unaligned(struct vc_data *vc, struct display *p,
struct fb_info *info, struct fb_image *image,
int count, const unsigned short *s)
......@@ -392,14 +313,6 @@ static void putcs_unaligned(struct vc_data *vc, struct display *p,
unsigned int idx = vc->vc_font.width/8;
unsigned short charmask = p->charmask;
u8 mask, *src, *dst, *dst0;
void (*move_data)(u8 *dst, u8 *src, u32 d_pitch, u32 height, u32 mask,
u32 shift_high, u32 shift_low, u32 mod, u32 idx,
struct fb_info *info);
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_unaligned;
else
move_data = sysmove_buf_unaligned;
while (count) {
if (count > maxcnt)
......@@ -419,14 +332,13 @@ static void putcs_unaligned(struct vc_data *vc, struct display *p,
cellsize;
dst = dst0;
mask = (u8) (0xfff << shift_high);
move_data(dst, src, pitch, image->height, mask,
shift_high, shift_low, mod, idx, info);
move_buf_unaligned(info, dst, src, pitch, image->height, mask,
shift_high, shift_low, mod, idx);
shift_low += mod;
dst0 += (shift_low >= 8) ? width : width - 1;
shift_low &= 7;
shift_high = 8 - shift_low;
}
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
......@@ -444,15 +356,8 @@ static void putcs_aligned(struct vc_data *vc, struct display *p,
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int pitch, cnt, size, k;
unsigned short charmask = p->charmask;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch,
u32 height, struct fb_info *info);
u8 *src, *dst, *dst0;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_aligned;
else
move_data = sysmove_buf_aligned;
while (count) {
if (count > maxcnt)
cnt = k = maxcnt;
......@@ -466,13 +371,11 @@ static void putcs_aligned(struct vc_data *vc, struct display *p,
dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
image->data = dst0;
while (k--) {
src = p->fontdata + (scr_readw(s++) & charmask)*
cellsize;
src = p->fontdata + (scr_readw(s++) & charmask)* cellsize;
dst = dst0;
move_data(dst, src, pitch, width, image->height, info);
move_buf_aligned(info, dst, src, pitch, width, image->height);
dst0 += width;
}
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
......@@ -523,15 +426,8 @@ static void accel_putc(struct vc_data *vc, struct display *p,
unsigned int size, pitch;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch,
u32 height, struct fb_info *info);
u8 *src, *dst;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_aligned;
else
move_data = sysmove_buf_aligned;
image.dx = xpos * vc->vc_font.width;
image.dy = ypos * vc->vc_font.height;
image.width = vc->vc_font.width;
......@@ -549,7 +445,7 @@ static void accel_putc(struct vc_data *vc, struct display *p,
image.data = dst;
src = p->fontdata + (c & charmask) * vc->vc_font.height * width;
move_data(dst, src, pitch, width, image.height, info);
move_buf_aligned(info, dst, src, pitch, width, image.height);
info->fbops->fb_imageblit(info, &image);
}
......@@ -775,18 +671,6 @@ static const char *fbcon_startup(void)
vc->vc_cols = info->var.xres/vc->vc_font.width;
vc->vc_rows = info->var.yres/vc->vc_font.height;
if (info->pixmap.addr == NULL) {
info->pixmap.addr = kmalloc(FBCON_PIXMAPSIZE, GFP_KERNEL);
if (!info->pixmap.addr)
return NULL;
info->pixmap.size = FBCON_PIXMAPSIZE;
info->pixmap.buf_align = 1;
info->pixmap.scan_align = 1;
info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
info->pixmap.offset = 0;
spin_lock_init(&info->pixmap.lock);
/* We trust the mode the driver supplies. */
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);
......
......@@ -382,6 +382,7 @@ static struct {
};
#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
#define FBPIXMAPSIZE 8192
extern const char *global_mode_option;
......@@ -395,7 +396,59 @@ static int ofonly __initdata = 0;
#endif
/*
* we need to lock this section since fbcon_cursor
* Drawing helpers.
*/
u8 sys_inbuf(u8 *src)
{
return *src;
}
void sys_outbuf(u8 src, u8 *dst)
{
*dst = src;
}
void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
info->pixmap.outbuf(*src++, dst+j);
dst += d_pitch;
}
}
void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high, u32 shift_low,
u32 mod, u32 idx)
{
int i, j;
u8 tmp;
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
tmp = info->pixmap.inbuf(dst+j);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+j);
info->pixmap.outbuf(*src << shift_high, dst+j+1);
src++;
}
tmp = info->pixmap.inbuf(dst+idx);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+idx);
if (shift_high < mod)
info->pixmap.outbuf(*src<<shift_high, dst+idx+1);
src++;
dst += d_pitch;
}
}
/*
* we need to lock this section since fb_cursor
* may use fb_imageblit()
*/
u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
......@@ -1152,6 +1205,23 @@ register_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
break;
fb_info->node = mk_kdev(FB_MAJOR, i);
if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;
if (fb_info->pixmap.outbuf == NULL)
fb_info->pixmap.outbuf = sys_outbuf;
if (fb_info->pixmap.inbuf == NULL)
fb_info->pixmap.inbuf = sys_inbuf;
spin_lock_init(&fb_info->pixmap.lock);
registered_fb[i] = fb_info;
sprintf(name_buf, "fb/%d", i);
devfs_register(NULL, name_buf, DEVFS_FL_DEFAULT,
......@@ -1180,6 +1250,9 @@ unregister_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
return -EINVAL;
devfs_remove("fb/%d", i);
if (fb_info->pixmap.addr)
kfree(fb_info->pixmap.addr);
registered_fb[i]=NULL;
num_registered_fb--;
return 0;
......@@ -1297,5 +1370,7 @@ EXPORT_SYMBOL(fb_set_var);
EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned);
MODULE_LICENSE("GPL");
......@@ -17,30 +17,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
static inline void sysmove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch,
u32 height, struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
dst[j] = *src++;
dst += d_pitch;
}
}
static inline void iomove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch,
u32 height, struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
info->pixmap.outbuf(*src++, dst+j);
dst += d_pitch;
}
}
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
static u8 src[64];
......@@ -49,16 +25,8 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
unsigned dsize = ((cursor->image.width + 7)/8) * cursor->image.height;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch,
u32 d_pitch, u32 height,
struct fb_info *info);
u8 *dst;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf;
else
move_data = sysmove_buf;
s_pitch = (cursor->image.width + 7)/8;
d_pitch = (s_pitch + scan_align) & ~scan_align;
size = d_pitch * cursor->image.height + buf_align;
......@@ -83,11 +51,11 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
}
break;
}
move_data(dst, src, d_pitch, s_pitch, cursor->image.height,
info);
move_buf_aligned(info, dst, src, d_pitch, s_pitch,
cursor->image.height);
} else {
move_data(dst, cursor->dest, s_pitch, d_pitch,
cursor->image.height, info);
move_buf_aligned(info, dst, cursor->dest, s_pitch, d_pitch,
cursor->image.height);
}
image.bg_color = cursor->image.bg_color;
......@@ -98,7 +66,6 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
image.height = cursor->image.height;
image.depth = cursor->image.depth;
if (info->fbops->fb_imageblit)
info->fbops->fb_imageblit(info, &image);
return 0;
}
......
......@@ -482,6 +482,11 @@ extern int unregister_framebuffer(struct fb_info *fb_info);
extern int fb_prepare_logo(struct fb_info *fb_info);
extern int fb_show_logo(struct fb_info *fb_info);
extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size);
extern void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high, u32 shift_low,
u32 mod, u32 idx);
extern void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height);
extern struct fb_info *registered_fb[FB_MAX];
extern int num_registered_fb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment