Speed up vt(4) by keeping a record of the most recently drawn character and

the foreground and background colours.  In bitblt_text functions, compare
values to this cache and don't re-draw the characters if they haven't changed.
When invalidating the display, clear this cache in order to force characters
to be redrawn; also force full redraws between suspend/resume pairs since odd
artifacts can otherwise result.

When scrolling the display (which is where most time is spent within the vt
driver) this yields a significant performance improvement if most lines are
less than the width of the terminal, since this avoids re-drawing blanks on
top of blanks.

(Note that "re-drawing" here includes writing to the VGA text mode buffer; on
virtualized systems this can be extremely slow since it triggers a glyph
being rendered onto a 640x480 screen).

On a c5.4xlarge EC2 instance (with emulated text mode VGA) this cuts the time
spent in vt(4) during the kernel boot from 1200 ms to 700ms; on my laptop
(with a 3200x1800 display) the corresponding time is reduced from 970 ms down
to 155 ms.

Reviewed by:	imp, cem
Approved by:	re (gjb)
Relnotes:	Significant speedup in vt(4) and the system boot generally.
Differential Revision:	https://reviews.freebsd.org/D16723
This commit is contained in:
Colin Percival 2018-08-25 16:14:56 +00:00
parent fedded8d04
commit ee97b2336a
7 changed files with 101 additions and 2 deletions

View File

@ -58,6 +58,7 @@ static struct vt_driver vt_efifb_driver = {
.vd_init = vt_efifb_init,
.vd_blank = vt_fb_blank,
.vd_bitblt_text = vt_fb_bitblt_text,
.vd_invalidate_text = vt_fb_invalidate_text,
.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_drawrect = vt_fb_drawrect,
.vd_setpixel = vt_fb_setpixel,

View File

@ -60,6 +60,7 @@ static struct vt_driver vt_fb_early_driver = {
.vd_init = vt_efb_init,
.vd_blank = vt_fb_blank,
.vd_bitblt_text = vt_fb_bitblt_text,
.vd_invalidate_text = vt_fb_invalidate_text,
.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_drawrect = vt_fb_drawrect,
.vd_setpixel = vt_fb_setpixel,

View File

@ -50,6 +50,7 @@ static struct vt_driver vt_fb_driver = {
.vd_fini = vt_fb_fini,
.vd_blank = vt_fb_blank,
.vd_bitblt_text = vt_fb_bitblt_text,
.vd_invalidate_text = vt_fb_invalidate_text,
.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_drawrect = vt_fb_drawrect,
.vd_setpixel = vt_fb_setpixel,
@ -335,6 +336,7 @@ vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
term_char_t c;
term_color_t fg, bg;
const uint8_t *pattern;
size_t z;
vf = vw->vw_font;
@ -351,9 +353,22 @@ vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
vt_determine_colors(c,
VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
if (vd->vd_drawn && (vd->vd_drawn[z] == c) &&
vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) &&
vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg))
continue;
vt_fb_bitblt_bitmap(vd, vw,
pattern, NULL, vf->vf_width, vf->vf_height,
x, y, fg, bg);
if (vd->vd_drawn)
vd->vd_drawn[z] = c;
if (vd->vd_drawnfg)
vd->vd_drawnfg[z] = fg;
if (vd->vd_drawnbg)
vd->vd_drawnbg[z] = bg;
}
}
@ -379,6 +394,26 @@ vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
#endif
}
void
vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area)
{
unsigned int col, row;
size_t z;
for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
++col) {
z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
if (vd->vd_drawn)
vd->vd_drawn[z] = 0;
if (vd->vd_drawnfg)
vd->vd_drawnfg[z] = 0;
if (vd->vd_drawnbg)
vd->vd_drawnbg[z] = 0;
}
}
}
void
vt_fb_postswitch(struct vt_device *vd)
{

View File

@ -43,6 +43,7 @@ vd_init_t vt_fb_init;
vd_fini_t vt_fb_fini;
vd_blank_t vt_fb_blank;
vd_bitblt_text_t vt_fb_bitblt_text;
vd_invalidate_text_t vt_fb_invalidate_text;
vd_bitblt_bmp_t vt_fb_bitblt_bitmap;
vd_drawrect_t vt_fb_drawrect;
vd_setpixel_t vt_fb_setpixel;

View File

@ -97,6 +97,7 @@ static vd_probe_t vga_probe;
static vd_init_t vga_init;
static vd_blank_t vga_blank;
static vd_bitblt_text_t vga_bitblt_text;
static vd_invalidate_text_t vga_invalidate_text;
static vd_bitblt_bmp_t vga_bitblt_bitmap;
static vd_drawrect_t vga_drawrect;
static vd_setpixel_t vga_setpixel;
@ -108,6 +109,7 @@ static const struct vt_driver vt_vga_driver = {
.vd_init = vga_init,
.vd_blank = vga_blank,
.vd_bitblt_text = vga_bitblt_text,
.vd_invalidate_text = vga_invalidate_text,
.vd_bitblt_bmp = vga_bitblt_bitmap,
.vd_drawrect = vga_drawrect,
.vd_setpixel = vga_setpixel,
@ -868,6 +870,7 @@ vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
term_char_t c;
term_color_t fg, bg;
uint8_t ch, attr;
size_t z;
sc = vd->vd_softc;
vb = &vw->vw_buf;
@ -884,6 +887,12 @@ vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
vt_determine_colors(c, VTBUF_ISCURSOR(vb, row, col),
&fg, &bg);
z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
if (vd->vd_drawn && (vd->vd_drawn[z] == c) &&
vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) &&
vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg))
continue;
/*
* Convert character to CP437, which is the
* character set used by the VGA hardware by
@ -898,6 +907,13 @@ vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
MEM_WRITE2(sc, (row * 80 + col) * 2 + 0,
ch + ((uint16_t)(attr) << 8));
if (vd->vd_drawn)
vd->vd_drawn[z] = c;
if (vd->vd_drawnfg)
vd->vd_drawnfg[z] = fg;
if (vd->vd_drawnbg)
vd->vd_drawnbg[z] = bg;
}
}
}
@ -914,6 +930,27 @@ vga_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
}
}
void
vga_invalidate_text(struct vt_device *vd, const term_rect_t *area)
{
unsigned int col, row;
size_t z;
for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
for (col = area->tr_begin.tp_col;
col < area->tr_end.tp_col;
++col) {
z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
if (vd->vd_drawn)
vd->vd_drawn[z] = 0;
if (vd->vd_drawnfg)
vd->vd_drawnfg[z] = 0;
if (vd->vd_drawnbg)
vd->vd_drawnbg[z] = 0;
}
}
}
static void
vga_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
const uint8_t *pattern, const uint8_t *mask,

View File

@ -156,11 +156,15 @@ struct vt_device {
#define VDF_INITIALIZED 0x20 /* vtterm_cnprobe already done. */
#define VDF_MOUSECURSOR 0x40 /* Mouse cursor visible. */
#define VDF_QUIET_BELL 0x80 /* Disable bell. */
#define VDF_SUSPENDED 0x100 /* Device has been suspended. */
#define VDF_DOWNGRADE 0x8000 /* The driver is being downgraded. */
int vd_keyboard; /* (G) Keyboard index. */
unsigned int vd_kbstate; /* (?) Device unit. */
unsigned int vd_unit; /* (c) Device unit. */
int vd_altbrk; /* (?) Alt break seq. state */
term_char_t *vd_drawn; /* (?) Most recent char drawn. */
term_color_t *vd_drawnfg; /* (?) Most recent fg color drawn. */
term_color_t *vd_drawnbg; /* (?) Most recent bg color drawn. */
};
#define VD_PASTEBUF(vd) ((vd)->vd_pastebuf.vpb_buf)
@ -320,6 +324,8 @@ typedef void vd_postswitch_t(struct vt_device *vd);
typedef void vd_blank_t(struct vt_device *vd, term_color_t color);
typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw,
const term_rect_t *area);
typedef void vd_invalidate_text_t(struct vt_device *vd,
const term_rect_t *area);
typedef void vd_bitblt_bmp_t(struct vt_device *vd, const struct vt_window *vw,
const uint8_t *pattern, const uint8_t *mask,
unsigned int width, unsigned int height,
@ -345,6 +351,7 @@ struct vt_driver {
vd_drawrect_t *vd_drawrect;
vd_setpixel_t *vd_setpixel;
vd_bitblt_text_t *vd_bitblt_text;
vd_invalidate_text_t *vd_invalidate_text;
vd_bitblt_bmp_t *vd_bitblt_bmp;
/* Framebuffer ioctls, if present. */

View File

@ -190,6 +190,11 @@ SET_DECLARE(vt_drv_set, struct vt_driver);
struct terminal vt_consterm;
static struct vt_window vt_conswindow;
#ifndef SC_NO_CONSDRAWN
static term_char_t vt_consdrawn[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
static term_color_t vt_consdrawnfg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
static term_color_t vt_consdrawnbg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
#endif
struct vt_device vt_consdev = {
.vd_driver = NULL,
.vd_softc = NULL,
@ -210,6 +215,12 @@ struct vt_device vt_consdev = {
.vd_mcursor_fg = TC_WHITE,
.vd_mcursor_bg = TC_BLACK,
#endif
#ifndef SC_NO_CONSDRAWN
.vd_drawn = vt_consdrawn,
.vd_drawnfg = vt_consdrawnfg,
.vd_drawnbg = vt_consdrawnbg,
#endif
};
static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)];
static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE];
@ -1181,6 +1192,8 @@ vt_mark_mouse_position_as_dirty(struct vt_device *vd, int locked)
if (!locked)
vtbuf_lock(&vw->vw_buf);
if (vd->vd_driver->vd_invalidate_text)
vd->vd_driver->vd_invalidate_text(vd, &area);
vtbuf_dirty(&vw->vw_buf, &area);
if (!locked)
vtbuf_unlock(&vw->vw_buf);
@ -1280,12 +1293,14 @@ vt_flush(struct vt_device *vd)
vtbuf_undirty(&vw->vw_buf, &tarea);
/* Force a full redraw when the screen contents are invalid. */
if (vd->vd_flags & VDF_INVALID) {
/* Force a full redraw when the screen contents might be invalid. */
if (vd->vd_flags & (VDF_INVALID | VDF_SUSPENDED)) {
vd->vd_flags &= ~VDF_INVALID;
vt_set_border(vd, &vw->vw_draw_area, TC_BLACK);
vt_termrect(vd, vf, &tarea);
if (vd->vd_driver->vd_invalidate_text)
vd->vd_driver->vd_invalidate_text(vd, &tarea);
if (vt_draw_logo_cpus)
vtterm_draw_cpu_logos(vd);
}
@ -2824,6 +2839,7 @@ vt_suspend_handler(void *priv)
struct vt_device *vd;
vd = priv;
vd->vd_flags |= VDF_SUSPENDED;
if (vd->vd_driver != NULL && vd->vd_driver->vd_suspend != NULL)
vd->vd_driver->vd_suspend(vd);
}
@ -2836,6 +2852,7 @@ vt_resume_handler(void *priv)
vd = priv;
if (vd->vd_driver != NULL && vd->vd_driver->vd_resume != NULL)
vd->vd_driver->vd_resume(vd);
vd->vd_flags &= ~VDF_SUSPENDED;
}
void