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