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:
parent
fedded8d04
commit
ee97b2336a
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user