Better scrolling for fbcon

Pavel Machek (pavel@bug.ucw.cz)
Sat, 7 Aug 1999 22:41:02 +0200


Hi!

Here's my experimental code. It uses two copies to simulate circular
buffer. It is _much_ better than ypan mode. Unfortunately, I can not
get fbcon_bmove_rec+scrollback right. Please take a look,

Pavel

--- clean//include/linux/fb.h Fri Apr 30 20:29:10 1999
+++ linux/include/linux/fb.h Fri Aug 6 00:05:54 1999
@@ -276,7 +276,7 @@

struct vc_data *conp; /* pointer to console data */
struct fb_info *fb_info; /* frame buffer for this console */
- int vrows; /* number of virtual rows */
+ int vrows, total_vrows; /* number of virtual rows */
unsigned short cursor_x; /* current cursor position */
unsigned short cursor_y;
int fgcol; /* text colors */
--- clean//drivers/video/fbcon.c Tue May 18 11:13:13 1999
+++ linux/drivers/video/fbcon.c Mon Jan 1 05:05:05 1990
@@ -30,7 +30,8 @@
* Jakub Jelinek (jj@ultra.linux.cz)
*
* Random hacking by Martin Mares <mj@ucw.cz>
- *
+ * YTWICE mode by Pavel Machek <pavel@ucw.cz>
+ * (cursor does not work just right + scrollback behaves strange)
*
* The low level operations for the various display memory organizations are
* now in separate source files.
@@ -55,6 +56,7 @@
*/

#undef FBCONDEBUG
+#define YTWICE ((p->scrollmode & __SCROLL_YMASK) == __SCROLL_YTWICE)

#include <linux/config.h>
#include <linux/module.h>
@@ -209,7 +211,7 @@
static __inline__ void ypan_down(int unit, struct vc_data *conp,
struct display *p, int count);
static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width, u_int y_break);
+ int height, int width, u_int y_break, int flags);

static int fbcon_show_logo(void);

@@ -396,6 +398,9 @@
divides(fontheight(p), p->var.yres_virtual))
m = __SCROLL_YWRAP;
else if (divides(p->ypanstep, fontheight(p)) &&
+ p->var.yres_virtual >= 2*p->var.yres+fontheight(p))
+ m = __SCROLL_YTWICE;
+ else if (divides(p->ypanstep, fontheight(p)) &&
p->var.yres_virtual >= p->var.yres+fontheight(p))
m = __SCROLL_YPAN;
else if (p->scrollmode & __SCROLL_YNOMOVE)
@@ -568,6 +573,9 @@
if ((p->var.yres % fontheight(p)) &&
(p->var.yres_virtual % fontheight(p) < p->var.yres % fontheight(p)))
p->vrows--;
+ p->total_vrows = p->vrows;
+ if (YTWICE)
+ p->vrows -= p->var.yres/fontheight(p);
conp->vc_can_do_color = p->var.bits_per_pixel != 1;
conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
@@ -684,6 +692,7 @@

/* Split blits that cross physical y_wrap boundary */

+ if (!YTWICE) {
y_break = p->vrows-p->yscroll;
if (sy < y_break && sy+height-1 >= y_break) {
u_int b = y_break-sy;
@@ -691,6 +700,14 @@
p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
} else
p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
+ } else {
+ int i;
+ for (i=0; i<height; i++) {
+ p->dispsw->clear(conp, p, real_y(p, sy+i), sx, 1, width);
+ if (YTWICE && (real_y(p, sy+i) < conp->vc_rows))
+ p->dispsw->clear(conp, p, p->vrows + real_y(p, sy+i), sx, 1, width);
+ }
+ }

if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -715,6 +732,8 @@
}

p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos);
+ if (YTWICE && (real_y(p, ypos) < conp->vc_rows))
+ p->dispsw->putc(conp, p, c, p->vrows + real_y(p, ypos), xpos);

if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
@@ -740,6 +759,9 @@
redraw_cursor = 1;
}
p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
+ if (YTWICE && (real_y(p, ypos) < conp->vc_rows))
+ p->dispsw->putcs(conp, p, s, count, p->vrows + real_y(p, ypos), xpos);
+
if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
@@ -776,8 +798,11 @@
return;

cursor_on = 0;
- if (cursor_drawn)
+ if (cursor_drawn) {
p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+ if (YTWICE && (real_y(p, p->cursor_y) < conp->vc_rows))
+ p->dispsw->revc(p, p->cursor_x, p->vrows + real_y(p, p->cursor_y));
+ }

p->cursor_x = conp->vc_x;
p->cursor_y = y;
@@ -817,6 +842,21 @@
static int scrollback_max = 0;
static int scrollback_current = 0;

+/*
+ * Logic behind YTWICE:
+ *
+ * real begining of videoram +-----------------------+
+ * | line 1 |
+ * | line 2 |
+ * conp->vc_rows ---> +-----------------------+
+ * | line 3 |
+ * | line 4 |
+ * p->vrows ---> +-----------------------+
+ * | line 1 (copy) |
+ * | line 2 (copy) |
+ * +-----------------------+
+ */
+
static __inline__ void ywrap_up(int unit, struct vc_data *conp,
struct display *p, int count)
{
@@ -827,6 +867,8 @@
p->var.yoffset = p->yscroll*fontheight(p);
p->var.vmode |= FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
+ if (YTWICE && p->dispsw->clear_margins)
+ p->dispsw->clear_margins(conp, p, 1);
scrollback_max += count;
if (scrollback_max > scrollback_phys_max)
scrollback_max = scrollback_phys_max;
@@ -844,6 +886,8 @@
p->var.yoffset = p->yscroll*fontheight(p);
p->var.vmode |= FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
+ if (YTWICE && p->dispsw->clear_margins)
+ p->dispsw->clear_margins(conp, p, 1);
scrollback_max -= count;
if (scrollback_max < 0)
scrollback_max = 0;
@@ -1158,6 +1202,23 @@
fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
break;

+ case __SCROLL_YTWICE:
+ if (b-t-count > 3*conp->vc_rows>>2) {
+ if (t > 0)
+ fbcon_bmove(conp, 0, 0, count, 0, t,
+ conp->vc_cols);
+ ywrap_up(unit, conp, p, count);
+ if (conp->vc_rows-b > 0)
+ fbcon_bmove(conp, b-count, 0, b, 0,
+ conp->vc_rows-b, conp->vc_cols);
+ } else if (p->scrollmode & __SCROLL_YPANREDRAW)
+ goto redraw_up;
+ else
+ fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
+ conp->vc_cols);
+ fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+ break;
+
case __SCROLL_YPAN:
if (( p->yscroll + count <= 2 * (p->vrows - conp->vc_rows)) &&
(( !scroll_partial && (b-t == conp->vc_rows)) ||
@@ -1218,6 +1279,23 @@
fbcon_clear(conp, t, 0, count, conp->vc_cols);
break;

+ case __SCROLL_YTWICE:
+ if (b-t-count > 3*conp->vc_rows>>2) {
+ if (conp->vc_rows-b > 0)
+ fbcon_bmove(conp, b, 0, b-count, 0,
+ conp->vc_rows-b, conp->vc_cols);
+ ywrap_down(unit, conp, p, count);
+ if (t > 0)
+ fbcon_bmove(conp, count, 0, 0, 0, t,
+ conp->vc_cols);
+ } else if (p->scrollmode & __SCROLL_YPANREDRAW)
+ goto redraw_down;
+ else
+ fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
+ conp->vc_cols);
+ fbcon_clear(conp, t, 0, count, conp->vc_cols);
+ break;
+
case __SCROLL_YPAN:
if (( count-p->yscroll <= p->vrows-conp->vc_rows) &&
(( !scroll_partial && (b-t == conp->vc_rows)) ||
@@ -1278,22 +1356,24 @@
* Recursive invocations don't need to erase the cursor over and
* over again, so we use fbcon_bmove_rec()
*/
- fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
+ fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll, 0);
+ if (YTWICE)
+ fbcon_bmove_rec(p, p->vrows+sy, sx, p->vrows+dy, dx, height, width, p->total_vrows, 1);
}

static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width, u_int y_break)
+ int height, int width, u_int y_break, int flags)
{
u_int b;

if (sy < y_break && sy+height > y_break) {
b = y_break-sy;
if (dy < sy) { /* Avoid trashing self */
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
+ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break, flags);
+ fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break, flags);
} else {
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
+ fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break, flags);
+ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break, flags);
}
return;
}
@@ -1301,14 +1381,24 @@
if (dy < y_break && dy+height > y_break) {
b = y_break-dy;
if (dy < sy) { /* Avoid trashing self */
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
+ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break, flags);
+ fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break, flags);
} else {
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
+ fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break, flags);
+ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break, flags);
}
return;
}
+ if (YTWICE) {
+ if (real_y(p, dy) > p->total_vrows)
+ return;
+ if (real_y(p, sy) > p->total_vrows)
+ return;
+ if (flags && (real_y(p, dy) < p->vrows))
+ return;
+ if (flags && (real_y(p, sy) < p->vrows))
+ return;
+ }
p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
}

@@ -1343,6 +1435,7 @@
}
p->var.yoffset = p->yscroll = 0;
switch (p->scrollmode & __SCROLL_YMASK) {
+ case __SCROLL_YTWICE:
case __SCROLL_YWRAP:
scrollback_phys_max = p->vrows-conp->vc_rows;
break;
@@ -1583,6 +1676,8 @@
/* reset wrap/pan */
p->var.xoffset = p->var.yoffset = p->yscroll = 0;
p->vrows = p->var.yres_virtual/h;
+ if (YTWICE)
+ p->vrows -= p->var.yres/h;
if ((p->var.yres % h) && (p->var.yres_virtual % h < p->var.yres % h))
p->vrows--;
updatescrollmode(p);

-- 
I'm really pavel@ucw.cz. Look at http://195.113.31.123/~pavel.  Pavel
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/