summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/fb/creator_vt.c84
-rw-r--r--sys/dev/vt/font/vt_mouse_cursor.c6
-rw-r--r--sys/dev/vt/hw/efifb/efifb.c3
-rw-r--r--sys/dev/vt/hw/fb/vt_early_fb.c3
-rw-r--r--sys/dev/vt/hw/fb/vt_fb.c96
-rw-r--r--sys/dev/vt/hw/fb/vt_fb.h13
-rw-r--r--sys/dev/vt/hw/ofwfb/ofwfb.c92
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c843
-rw-r--r--sys/dev/vt/vt.h56
-rw-r--r--sys/dev/vt/vt_buf.c22
-rw-r--r--sys/dev/vt/vt_core.c398
-rw-r--r--sys/powerpc/ps3/ps3_syscons.c3
12 files changed, 1208 insertions, 411 deletions
diff --git a/sys/dev/fb/creator_vt.c b/sys/dev/fb/creator_vt.c
index 0f28749..f811f30 100644
--- a/sys/dev/fb/creator_vt.c
+++ b/sys/dev/fb/creator_vt.c
@@ -45,14 +45,16 @@ __FBSDID("$FreeBSD$");
static vd_probe_t creatorfb_probe;
static vd_init_t creatorfb_init;
static vd_blank_t creatorfb_blank;
-static vd_bitbltchr_t creatorfb_bitbltchr;
+static vd_bitblt_text_t creatorfb_bitblt_text;
+static vd_bitblt_bmp_t creatorfb_bitblt_bitmap;
static const struct vt_driver vt_creatorfb_driver = {
.vd_name = "creatorfb",
.vd_probe = creatorfb_probe,
.vd_init = creatorfb_init,
.vd_blank = creatorfb_blank,
- .vd_bitbltchr = creatorfb_bitbltchr,
+ .vd_bitblt_text = creatorfb_bitblt_text,
+ .vd_bitblt_bmp = creatorfb_bitblt_bitmap,
.vd_fb_ioctl = vt_fb_ioctl,
.vd_fb_mmap = vt_fb_mmap,
.vd_priority = VD_PRIORITY_SPECIFIC
@@ -176,30 +178,30 @@ creatorfb_blank(struct vt_device *vd, term_color_t color)
}
static void
-creatorfb_bitbltchr(struct vt_device *vd, const uint8_t *src,
- const uint8_t *mask, int bpl, vt_axis_t top, vt_axis_t left,
- unsigned int width, unsigned int height, term_color_t fg, term_color_t bg)
+creatorfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+ const uint8_t *pattern, const uint8_t *mask,
+ unsigned int width, unsigned int height,
+ unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
{
struct creatorfb_softc *sc = vd->vd_softc;
u_long line;
uint32_t fgc, bgc;
- int c;
+ int c, l;
uint8_t b, m;
fgc = sc->fb.fb_cmap[fg];
bgc = sc->fb.fb_cmap[bg];
b = m = 0;
- /* Don't try to put off screen pixels */
- if (((left + width) > vd->vd_width) || ((top + height) >
- vd->vd_height))
- return;
-
- line = (sc->fb.fb_stride * top) + 4*left;
- for (; height > 0; height--) {
- for (c = 0; c < width; c++) {
+ line = (sc->fb.fb_stride * y) + 4*x;
+ for (l = 0;
+ l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+ l++) {
+ for (c = 0;
+ c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+ c++) {
if (c % 8 == 0)
- b = *src++;
+ b = *pattern++;
else
b <<= 1;
if (mask != NULL) {
@@ -218,3 +220,55 @@ creatorfb_bitbltchr(struct vt_device *vd, const uint8_t *src,
}
}
+void
+creatorfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+ unsigned int col, row, x, y;
+ struct vt_font *vf;
+ term_char_t c;
+ term_color_t fg, bg;
+ const uint8_t *pattern;
+
+ vf = vw->vw_font;
+
+ 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) {
+ x = col * vf->vf_width +
+ vw->vw_draw_area.tr_begin.tp_col;
+ y = row * vf->vf_height +
+ vw->vw_draw_area.tr_begin.tp_row;
+
+ c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+ pattern = vtfont_lookup(vf, c);
+ vt_determine_colors(c,
+ VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+ creatorfb_bitblt_bitmap(vd, vw,
+ pattern, NULL, vf->vf_width, vf->vf_height,
+ x, y, fg, bg);
+ }
+ }
+
+#ifndef SC_NO_CUTPASTE
+ if (!vd->vd_mshown)
+ return;
+
+ term_rect_t drawn_area;
+
+ drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+ drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+ drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+ drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+ if (vt_is_cursor_in_area(vd, &drawn_area)) {
+ creatorfb_bitblt_bitmap(vd, vw,
+ vd->vd_mcursor->map, vd->vd_mcursor->mask,
+ vd->vd_mcursor->width, vd->vd_mcursor->height,
+ vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+ vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+ vd->vd_mcursor_fg, vd->vd_mcursor_bg);
+ }
+#endif
+}
diff --git a/sys/dev/vt/font/vt_mouse_cursor.c b/sys/dev/vt/font/vt_mouse_cursor.c
index 0219c7c..4f12991 100644
--- a/sys/dev/vt/font/vt_mouse_cursor.c
+++ b/sys/dev/vt/font/vt_mouse_cursor.c
@@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$");
#include <dev/vt/vt.h>
#ifndef SC_NO_CUTPASTE
-struct mouse_cursor vt_default_mouse_pointer = {
+struct vt_mouse_cursor vt_default_mouse_pointer = {
.map = {
0x00, /* "__ " */
0x40, /* "_*_ " */
@@ -64,7 +64,7 @@ struct mouse_cursor vt_default_mouse_pointer = {
0x0f, /* " ____" */
0x0f, /* " ____" */
},
- .w = 8,
- .h = 13,
+ .width = 8,
+ .height = 13,
};
#endif
diff --git a/sys/dev/vt/hw/efifb/efifb.c b/sys/dev/vt/hw/efifb/efifb.c
index 35deded..ff95391 100644
--- a/sys/dev/vt/hw/efifb/efifb.c
+++ b/sys/dev/vt/hw/efifb/efifb.c
@@ -60,7 +60,8 @@ static struct vt_driver vt_efifb_driver = {
.vd_probe = vt_efifb_probe,
.vd_init = vt_efifb_init,
.vd_blank = vt_fb_blank,
- .vd_bitbltchr = vt_fb_bitbltchr,
+ .vd_bitblt_text = vt_fb_bitblt_text,
+ .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_fb_ioctl = vt_fb_ioctl,
.vd_fb_mmap = vt_fb_mmap,
/* Better than VGA, but still generic driver. */
diff --git a/sys/dev/vt/hw/fb/vt_early_fb.c b/sys/dev/vt/hw/fb/vt_early_fb.c
index a618ca3..ff50a9c 100644
--- a/sys/dev/vt/hw/fb/vt_early_fb.c
+++ b/sys/dev/vt/hw/fb/vt_early_fb.c
@@ -59,7 +59,8 @@ static struct vt_driver vt_fb_early_driver = {
.vd_probe = vt_efb_probe,
.vd_init = vt_efb_init,
.vd_blank = vt_fb_blank,
- .vd_bitbltchr = vt_fb_bitbltchr,
+ .vd_bitblt_text = vt_fb_bitblt_text,
+ .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_priority = VD_PRIORITY_GENERIC,
};
diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c
index 3dd3564..ddec76d 100644
--- a/sys/dev/vt/hw/fb/vt_fb.c
+++ b/sys/dev/vt/hw/fb/vt_fb.c
@@ -41,15 +41,15 @@ __FBSDID("$FreeBSD$");
#include <dev/vt/hw/fb/vt_fb.h>
#include <dev/vt/colors/vt_termcolors.h>
-void vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2,
- int fill, term_color_t color);
-void vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color);
+static vd_drawrect_t vt_fb_drawrect;
+static vd_setpixel_t vt_fb_setpixel;
static struct vt_driver vt_fb_driver = {
.vd_name = "fb",
.vd_init = vt_fb_init,
.vd_blank = vt_fb_blank,
- .vd_bitbltchr = vt_fb_bitbltchr,
+ .vd_bitblt_text = vt_fb_bitblt_text,
+ .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_drawrect = vt_fb_drawrect,
.vd_setpixel = vt_fb_setpixel,
.vd_postswitch = vt_fb_postswitch,
@@ -146,7 +146,7 @@ vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
return (EINVAL);
}
-void
+static void
vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
{
struct fb_info *info;
@@ -181,7 +181,7 @@ vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
}
-void
+static void
vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
term_color_t color)
{
@@ -244,13 +244,14 @@ vt_fb_blank(struct vt_device *vd, term_color_t color)
}
void
-vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
- int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
- unsigned int height, term_color_t fg, term_color_t bg)
+vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+ const uint8_t *pattern, const uint8_t *mask,
+ unsigned int width, unsigned int height,
+ unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
{
struct fb_info *info;
uint32_t fgc, bgc, cc, o;
- int c, l, bpp;
+ int c, l, bpp, bpl;
u_long line;
uint8_t b, m;
const uint8_t *ch;
@@ -260,20 +261,18 @@ vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
fgc = info->fb_cmap[fg];
bgc = info->fb_cmap[bg];
b = m = 0;
- if (bpl == 0)
- bpl = (width + 7) >> 3; /* Bytes per sorce line. */
-
- /* Don't try to put off screen pixels */
- if (((left + width) > info->fb_width) || ((top + height) >
- info->fb_height))
- return;
+ bpl = (width + 7) >> 3; /* Bytes per source line. */
KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
- line = (info->fb_stride * top) + (left * bpp);
- for (l = 0; l < height; l++) {
- ch = src;
- for (c = 0; c < width; c++) {
+ line = (info->fb_stride * y) + (x * bpp);
+ for (l = 0;
+ l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+ l++) {
+ ch = pattern;
+ for (c = 0;
+ c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+ c++) {
if (c % 8 == 0)
b = *ch++;
else
@@ -312,8 +311,61 @@ vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
}
}
line += info->fb_stride;
- src += bpl;
+ pattern += bpl;
+ }
+}
+
+void
+vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+ unsigned int col, row, x, y;
+ struct vt_font *vf;
+ term_char_t c;
+ term_color_t fg, bg;
+ const uint8_t *pattern;
+
+ vf = vw->vw_font;
+
+ 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) {
+ x = col * vf->vf_width +
+ vw->vw_draw_area.tr_begin.tp_col;
+ y = row * vf->vf_height +
+ vw->vw_draw_area.tr_begin.tp_row;
+
+ c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+ pattern = vtfont_lookup(vf, c);
+ vt_determine_colors(c,
+ VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+ vt_fb_bitblt_bitmap(vd, vw,
+ pattern, NULL, vf->vf_width, vf->vf_height,
+ x, y, fg, bg);
+ }
+ }
+
+#ifndef SC_NO_CUTPASTE
+ if (!vd->vd_mshown)
+ return;
+
+ term_rect_t drawn_area;
+
+ drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+ drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+ drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+ drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+ if (vt_is_cursor_in_area(vd, &drawn_area)) {
+ vt_fb_bitblt_bitmap(vd, vw,
+ vd->vd_mcursor->map, vd->vd_mcursor->mask,
+ vd->vd_mcursor->width, vd->vd_mcursor->height,
+ vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+ vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+ vd->vd_mcursor_fg, vd->vd_mcursor_bg);
}
+#endif
}
void
diff --git a/sys/dev/vt/hw/fb/vt_fb.h b/sys/dev/vt/hw/fb/vt_fb.h
index 2cbe8d5..9a0da6e 100644
--- a/sys/dev/vt/hw/fb/vt_fb.h
+++ b/sys/dev/vt/hw/fb/vt_fb.h
@@ -36,11 +36,12 @@ int vt_fb_attach(struct fb_info *info);
void vt_fb_resume(void);
void vt_fb_suspend(void);
-vd_init_t vt_fb_init;
-vd_blank_t vt_fb_blank;
-vd_bitbltchr_t vt_fb_bitbltchr;
-vd_postswitch_t vt_fb_postswitch;
-vd_fb_ioctl_t vt_fb_ioctl;
-vd_fb_mmap_t vt_fb_mmap;
+vd_init_t vt_fb_init;
+vd_blank_t vt_fb_blank;
+vd_bitblt_text_t vt_fb_bitblt_text;
+vd_bitblt_bmp_t vt_fb_bitblt_bitmap;
+vd_postswitch_t vt_fb_postswitch;
+vd_fb_ioctl_t vt_fb_ioctl;
+vd_fb_mmap_t vt_fb_mmap;
#endif /* _DEV_VT_HW_FB_VT_FB_H_ */
diff --git a/sys/dev/vt/hw/ofwfb/ofwfb.c b/sys/dev/vt/hw/ofwfb/ofwfb.c
index 6efd9de..75d42b5 100644
--- a/sys/dev/vt/hw/ofwfb/ofwfb.c
+++ b/sys/dev/vt/hw/ofwfb/ofwfb.c
@@ -58,14 +58,16 @@ struct ofwfb_softc {
static vd_probe_t ofwfb_probe;
static vd_init_t ofwfb_init;
-static vd_bitbltchr_t ofwfb_bitbltchr;
+static vd_bitblt_text_t ofwfb_bitblt_text;
+static vd_bitblt_bmp_t ofwfb_bitblt_bitmap;
static const struct vt_driver vt_ofwfb_driver = {
.vd_name = "ofwfb",
.vd_probe = ofwfb_probe,
.vd_init = ofwfb_init,
.vd_blank = vt_fb_blank,
- .vd_bitbltchr = ofwfb_bitbltchr,
+ .vd_bitblt_text = ofwfb_bitblt_text,
+ .vd_bitblt_bmp = ofwfb_bitblt_bitmap,
.vd_fb_ioctl = vt_fb_ioctl,
.vd_fb_mmap = vt_fb_mmap,
.vd_priority = VD_PRIORITY_GENERIC+1,
@@ -100,14 +102,15 @@ ofwfb_probe(struct vt_device *vd)
}
static void
-ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
- int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
- unsigned int height, term_color_t fg, term_color_t bg)
+ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+ const uint8_t *pattern, const uint8_t *mask,
+ unsigned int width, unsigned int height,
+ unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
{
struct fb_info *sc = vd->vd_softc;
u_long line;
uint32_t fgc, bgc;
- int c;
+ int c, l;
uint8_t b, m;
union {
uint32_t l;
@@ -118,16 +121,16 @@ ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
bgc = sc->fb_cmap[bg];
b = m = 0;
- /* Don't try to put off screen pixels */
- if (((left + width) > vd->vd_width) || ((top + height) >
- vd->vd_height))
- return;
-
- line = (sc->fb_stride * top) + left * sc->fb_bpp/8;
+ line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
+ /* Don't try to put off screen pixels */
+ if (((x + width) > vd->vd_width) || ((y + height) >
+ vd->vd_height))
+ return;
+
for (; height > 0; height--) {
for (c = 0; c < width; c += 8) {
- b = *src++;
+ b = *pattern++;
/*
* Assume that there is more background than
@@ -157,10 +160,14 @@ ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
line += sc->fb_stride;
}
} else {
- for (; height > 0; height--) {
- for (c = 0; c < width; c++) {
+ for (l = 0;
+ l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
+ l++) {
+ for (c = 0;
+ c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
+ c++) {
if (c % 8 == 0)
- b = *src++;
+ b = *pattern++;
else
b <<= 1;
if (mask != NULL) {
@@ -191,6 +198,59 @@ ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
}
}
+void
+ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+ unsigned int col, row, x, y;
+ struct vt_font *vf;
+ term_char_t c;
+ term_color_t fg, bg;
+ const uint8_t *pattern;
+
+ vf = vw->vw_font;
+
+ 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) {
+ x = col * vf->vf_width +
+ vw->vw_draw_area.tr_begin.tp_col;
+ y = row * vf->vf_height +
+ vw->vw_draw_area.tr_begin.tp_row;
+
+ c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
+ pattern = vtfont_lookup(vf, c);
+ vt_determine_colors(c,
+ VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
+
+ ofwfb_bitblt_bitmap(vd, vw,
+ pattern, NULL, vf->vf_width, vf->vf_height,
+ x, y, fg, bg);
+ }
+ }
+
+#ifndef SC_NO_CUTPASTE
+ if (!vd->vd_mshown)
+ return;
+
+ term_rect_t drawn_area;
+
+ drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
+ drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
+ drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
+ drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
+
+ if (vt_is_cursor_in_area(vd, &drawn_area)) {
+ ofwfb_bitblt_bitmap(vd, vw,
+ vd->vd_mcursor->map, vd->vd_mcursor->mask,
+ vd->vd_mcursor->width, vd->vd_mcursor->height,
+ vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
+ vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
+ vd->vd_mcursor_fg, vd->vd_mcursor_bg);
+ }
+#endif
+}
+
static void
ofwfb_initialize(struct vt_device *vd)
{
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 834e6e8..bf5263a 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -54,7 +54,8 @@ struct vga_softc {
bus_space_handle_t vga_fb_handle;
bus_space_tag_t vga_reg_tag;
bus_space_handle_t vga_reg_handle;
- int vga_curcolor;
+ int vga_wmode;
+ term_color_t vga_curfg, vga_curbg;
};
/* Convenience macros. */
@@ -71,13 +72,27 @@ struct vga_softc {
#define VT_VGA_HEIGHT 480
#define VT_VGA_MEMSIZE (VT_VGA_WIDTH * VT_VGA_HEIGHT / 8)
+/*
+ * VGA is designed to handle 8 pixels at a time (8 pixels in one byte of
+ * memory).
+ */
+#define VT_VGA_PIXELS_BLOCK 8
+
+/*
+ * We use an off-screen addresses to:
+ * o store the background color;
+ * o store pixels pattern.
+ * Those addresses are then loaded in the latches once.
+ */
+#define VT_VGA_BGCOLOR_OFFSET VT_VGA_MEMSIZE
+
static vd_probe_t vga_probe;
static vd_init_t vga_init;
static vd_blank_t vga_blank;
-static vd_bitbltchr_t vga_bitbltchr;
+static vd_bitblt_text_t vga_bitblt_text;
+static vd_bitblt_bmp_t vga_bitblt_bitmap;
static vd_drawrect_t vga_drawrect;
static vd_setpixel_t vga_setpixel;
-static vd_putchar_t vga_putchar;
static vd_postswitch_t vga_postswitch;
static const struct vt_driver vt_vga_driver = {
@@ -85,10 +100,10 @@ static const struct vt_driver vt_vga_driver = {
.vd_probe = vga_probe,
.vd_init = vga_init,
.vd_blank = vga_blank,
- .vd_bitbltchr = vga_bitbltchr,
+ .vd_bitblt_text = vga_bitblt_text,
+ .vd_bitblt_bmp = vga_bitblt_bitmap,
.vd_drawrect = vga_drawrect,
.vd_setpixel = vga_setpixel,
- .vd_putchar = vga_putchar,
.vd_postswitch = vga_postswitch,
.vd_priority = VD_PRIORITY_GENERIC,
};
@@ -101,158 +116,74 @@ static struct vga_softc vga_conssoftc;
VT_DRIVER_DECLARE(vt_vga, vt_vga_driver);
static inline void
-vga_setcolor(struct vt_device *vd, term_color_t color)
+vga_setwmode(struct vt_device *vd, int wmode)
{
struct vga_softc *sc = vd->vd_softc;
- if (sc->vga_curcolor != color) {
- REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET);
- REG_WRITE1(sc, VGA_GC_DATA, color);
- sc->vga_curcolor = color;
- }
-}
-
-static void
-vga_blank(struct vt_device *vd, term_color_t color)
-{
- struct vga_softc *sc = vd->vd_softc;
- u_int ofs;
+ if (sc->vga_wmode == wmode)
+ return;
- vga_setcolor(vd, color);
- for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++)
- MEM_WRITE1(sc, ofs, 0xff);
+ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE);
+ REG_WRITE1(sc, VGA_GC_DATA, wmode);
+ sc->vga_wmode = wmode;
+
+ switch (wmode) {
+ case 3:
+ /* Re-enable all plans. */
+ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK);
+ REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_MM_EM3 | VGA_SEQ_MM_EM2 |
+ VGA_SEQ_MM_EM1 | VGA_SEQ_MM_EM0);
+ break;
+ }
}
static inline void
-vga_bitblt_put(struct vt_device *vd, u_long dst, term_color_t color,
- uint8_t v)
+vga_setfg(struct vt_device *vd, term_color_t color)
{
struct vga_softc *sc = vd->vd_softc;
- /* Skip empty writes, in order to avoid palette changes. */
- if (v != 0x00) {
- vga_setcolor(vd, color);
- /*
- * When this MEM_READ1() gets disabled, all sorts of
- * artifacts occur. This is because this read loads the
- * set of 8 pixels that are about to be changed. There
- * is one scenario where we can avoid the read, namely
- * if all pixels are about to be overwritten anyway.
- */
- if (v != 0xff)
- MEM_READ1(sc, dst);
- MEM_WRITE1(sc, dst, v);
- }
-}
-
-static void
-vga_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
-{
-
- vga_bitblt_put(vd, (y * VT_VGA_WIDTH / 8) + (x / 8), color,
- 0x80 >> (x % 8));
-}
+ vga_setwmode(vd, 3);
-static void
-vga_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
- term_color_t color)
-{
- int x, y;
+ if (sc->vga_curfg == color)
+ return;
- for (y = y1; y <= y2; y++) {
- if (fill || (y == y1) || (y == y2)) {
- for (x = x1; x <= x2; x++)
- vga_setpixel(vd, x, y, color);
- } else {
- vga_setpixel(vd, x1, y, color);
- vga_setpixel(vd, x2, y, color);
- }
- }
+ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET);
+ REG_WRITE1(sc, VGA_GC_DATA, color);
+ sc->vga_curfg = color;
}
static inline void
-vga_bitblt_draw(struct vt_device *vd, const uint8_t *src,
- u_long ldst, uint8_t shift, unsigned int width, unsigned int height,
- term_color_t color, int negate)
+vga_setbg(struct vt_device *vd, term_color_t color)
{
- u_long dst;
- int w;
- uint8_t b, r, out;
-
- for (; height > 0; height--) {
- dst = ldst;
- ldst += VT_VGA_WIDTH / 8;
- r = 0;
- for (w = width; w > 0; w -= 8) {
- b = *src++;
- if (negate) {
- b = ~b;
- /* Don't go too far. */
- if (w < 8)
- b &= 0xff << (8 - w);
- }
- /* Reintroduce bits from previous column. */
- out = (b >> shift) | r;
- r = b << (8 - shift);
- vga_bitblt_put(vd, dst++, color, out);
- }
- /* Print the remainder. */
- vga_bitblt_put(vd, dst, color, r);
- }
-}
+ struct vga_softc *sc = vd->vd_softc;
-static void
-vga_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
- int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
- unsigned int height, term_color_t fg, term_color_t bg)
-{
- u_long dst, ldst;
- int w;
+ vga_setwmode(vd, 3);
- /* Don't try to put off screen pixels */
- if (((left + width) > VT_VGA_WIDTH) || ((top + height) >
- VT_VGA_HEIGHT))
+ if (sc->vga_curbg == color)
return;
- dst = (VT_VGA_WIDTH * top + left) / 8;
-
- for (; height > 0; height--) {
- ldst = dst;
- for (w = width; w > 0; w -= 8) {
- vga_bitblt_put(vd, ldst, fg, *src);
- vga_bitblt_put(vd, ldst, bg, ~*src);
- ldst++;
- src++;
- }
- dst += VT_VGA_WIDTH / 8;
- }
-}
+ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET);
+ REG_WRITE1(sc, VGA_GC_DATA, color);
-/* Bitblt with mask support. Slow. */
-static void
-vga_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
- int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
- unsigned int height, term_color_t fg, term_color_t bg)
-{
- struct vga_softc *sc = vd->vd_softc;
- u_long dst;
- uint8_t shift;
+ /*
+ * Write 8 pixels using the background color to an off-screen
+ * byte in the video memory.
+ */
+ MEM_WRITE1(sc, VT_VGA_BGCOLOR_OFFSET, 0xff);
- dst = (VT_VGA_WIDTH * top + left) / 8;
- shift = left % 8;
+ /*
+ * Read those 8 pixels back to load the background color in the
+ * latches register.
+ */
+ MEM_READ1(sc, VT_VGA_BGCOLOR_OFFSET);
- /* Don't try to put off screen pixels */
- if (((left + width) > VT_VGA_WIDTH) || ((top + height) >
- VT_VGA_HEIGHT))
- return;
+ sc->vga_curbg = color;
- if (sc->vga_curcolor == fg) {
- vga_bitblt_draw(vd, src, dst, shift, width, height, fg, 0);
- vga_bitblt_draw(vd, src, dst, shift, width, height, bg, 1);
- } else {
- vga_bitblt_draw(vd, src, dst, shift, width, height, bg, 1);
- vga_bitblt_draw(vd, src, dst, shift, width, height, fg, 0);
- }
+ /*
+ * The Set/Reset register doesn't contain the fg color anymore,
+ * store an invalid color.
+ */
+ sc->vga_curfg = 0xff;
}
/*
@@ -381,25 +312,635 @@ vga_get_cp437(term_char_t c)
}
static void
-vga_putchar(struct vt_device *vd, term_char_t c,
- vt_axis_t top, vt_axis_t left, term_color_t fg, term_color_t bg)
+vga_blank(struct vt_device *vd, term_color_t color)
{
struct vga_softc *sc = vd->vd_softc;
- uint8_t ch, attr;
+ u_int ofs;
+
+ vga_setfg(vd, color);
+ for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++)
+ MEM_WRITE1(sc, ofs, 0xff);
+}
+
+static inline void
+vga_bitblt_put(struct vt_device *vd, u_long dst, term_color_t color,
+ uint8_t v)
+{
+ struct vga_softc *sc = vd->vd_softc;
+
+ /* Skip empty writes, in order to avoid palette changes. */
+ if (v != 0x00) {
+ vga_setfg(vd, color);
+ /*
+ * When this MEM_READ1() gets disabled, all sorts of
+ * artifacts occur. This is because this read loads the
+ * set of 8 pixels that are about to be changed. There
+ * is one scenario where we can avoid the read, namely
+ * if all pixels are about to be overwritten anyway.
+ */
+ if (v != 0xff) {
+ MEM_READ1(sc, dst);
+
+ /* The bg color was trashed by the reads. */
+ sc->vga_curbg = 0xff;
+ }
+ MEM_WRITE1(sc, dst, v);
+ }
+}
+
+static void
+vga_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
+{
+
+ vga_bitblt_put(vd, (y * VT_VGA_WIDTH / 8) + (x / 8), color,
+ 0x80 >> (x % 8));
+}
+
+static void
+vga_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
+ term_color_t color)
+{
+ int x, y;
+
+ for (y = y1; y <= y2; y++) {
+ if (fill || (y == y1) || (y == y2)) {
+ for (x = x1; x <= x2; x++)
+ vga_setpixel(vd, x, y, color);
+ } else {
+ vga_setpixel(vd, x1, y, color);
+ vga_setpixel(vd, x2, y, color);
+ }
+ }
+}
+
+static void
+vga_compute_shifted_pattern(const uint8_t *src, unsigned int bytes,
+ unsigned int src_x, unsigned int x_count, unsigned int dst_x,
+ uint8_t *pattern, uint8_t *mask)
+{
+ unsigned int n;
+
+ n = src_x / 8;
+
+ /*
+ * This mask has bits set, where a pixel (ether 0 or 1)
+ * comes from the source bitmap.
+ */
+ if (mask != NULL) {
+ *mask = (0xff
+ >> (8 - x_count))
+ << (8 - x_count - dst_x);
+ }
+
+ if (n == (src_x + x_count - 1) / 8) {
+ /* All the pixels we want are in the same byte. */
+ *pattern = src[n];
+ if (dst_x >= src_x)
+ *pattern >>= (dst_x - src_x % 8);
+ else
+ *pattern <<= (src_x % 8 - dst_x);
+ } else {
+ /* The pixels we want are split into two bytes. */
+ if (dst_x >= src_x % 8) {
+ *pattern =
+ src[n] << (8 - dst_x - src_x % 8) |
+ src[n + 1] >> (dst_x - src_x % 8);
+ } else {
+ *pattern =
+ src[n] << (src_x % 8 - dst_x) |
+ src[n + 1] >> (8 - src_x % 8 - dst_x);
+ }
+ }
+}
+
+static void
+vga_copy_bitmap_portion(uint8_t *pattern_2colors, uint8_t *pattern_ncolors,
+ const uint8_t *src, const uint8_t *src_mask, unsigned int src_width,
+ unsigned int src_x, unsigned int dst_x, unsigned int x_count,
+ unsigned int src_y, unsigned int dst_y, unsigned int y_count,
+ term_color_t fg, term_color_t bg, int overwrite)
+{
+ unsigned int i, bytes;
+ uint8_t pattern, relevant_bits, mask;
+
+ bytes = (src_width + 7) / 8;
+
+ for (i = 0; i < y_count; ++i) {
+ vga_compute_shifted_pattern(src + (src_y + i) * bytes,
+ bytes, src_x, x_count, dst_x, &pattern, &relevant_bits);
+
+ if (src_mask == NULL) {
+ /*
+ * No src mask. Consider that all wanted bits
+ * from the source are "authoritative".
+ */
+ mask = relevant_bits;
+ } else {
+ /*
+ * There's an src mask. We shift it the same way
+ * we shifted the source pattern.
+ */
+ vga_compute_shifted_pattern(
+ src_mask + (src_y + i) * bytes,
+ bytes, src_x, x_count, dst_x,
+ &mask, NULL);
+
+ /* Now, only keep the wanted bits among them. */
+ mask &= relevant_bits;
+ }
+
+ /*
+ * Clear bits from the pattern which must be
+ * transparent, according to the source mask.
+ */
+ pattern &= mask;
+
+ /* Set the bits in the 2-colors array. */
+ if (overwrite)
+ pattern_2colors[dst_y + i] &= ~mask;
+ pattern_2colors[dst_y + i] |= pattern;
+
+ if (pattern_ncolors == NULL)
+ continue;
+
+ /*
+ * Set the same bits in the n-colors array. This one
+ * supports transparency, when a given bit is cleared in
+ * all colors.
+ */
+ if (overwrite) {
+ /*
+ * Ensure that the pixels used by this bitmap are
+ * cleared in other colors.
+ */
+ for (int j = 0; j < 16; ++j)
+ pattern_ncolors[(dst_y + i) * 16 + j] &=
+ ~mask;
+ }
+ pattern_ncolors[(dst_y + i) * 16 + fg] |= pattern;
+ pattern_ncolors[(dst_y + i) * 16 + bg] |= (~pattern & mask);
+ }
+}
+
+static void
+vga_bitblt_pixels_block_2colors(struct vt_device *vd, const uint8_t *masks,
+ term_color_t fg, term_color_t bg,
+ unsigned int x, unsigned int y, unsigned int height)
+{
+ unsigned int i, offset;
+ struct vga_softc *sc;
+
+ /*
+ * The great advantage of Write Mode 3 is that we just need
+ * to load the foreground in the Set/Reset register, load the
+ * background color in the latches register (this is done
+ * through a write in offscreen memory followed by a read of
+ * that data), then write the pattern to video memory. This
+ * pattern indicates if the pixel should use the foreground
+ * color (bit set) or the background color (bit cleared).
+ */
+
+ vga_setbg(vd, bg);
+ vga_setfg(vd, fg);
+
+ sc = vd->vd_softc;
+ offset = (VT_VGA_WIDTH * y + x) / 8;
+
+ for (i = 0; i < height; ++i, offset += VT_VGA_WIDTH / 8) {
+ MEM_WRITE1(sc, offset, masks[i]);
+ }
+}
+
+static void
+vga_bitblt_pixels_block_ncolors(struct vt_device *vd, const uint8_t *masks,
+ unsigned int x, unsigned int y, unsigned int height)
+{
+ unsigned int i, j, plan, color, offset;
+ struct vga_softc *sc;
+ uint8_t mask, plans[height * 4];
+
+ sc = vd->vd_softc;
+
+ memset(plans, 0, sizeof(plans));
+
+ /*
+ * To write a group of pixels using 3 or more colors, we select
+ * Write Mode 0 and write one byte to each plan separately.
+ */
/*
- * Convert character to CP437, which is the character set used
- * by the VGA hardware by default.
+ * We first compute each byte: each plan contains one bit of the
+ * color code for each of the 8 pixels.
+ *
+ * For example, if the 8 pixels are like this:
+ * GBBBBBBY
+ * where:
+ * G (gray) = 0b0111
+ * B (black) = 0b0000
+ * Y (yellow) = 0b0011
+ *
+ * The corresponding for bytes are:
+ * GBBBBBBY
+ * Plan 0: 10000001 = 0x81
+ * Plan 1: 10000001 = 0x81
+ * Plan 2: 10000000 = 0x80
+ * Plan 3: 00000000 = 0x00
+ * | | |
+ * | | +-> 0b0011 (Y)
+ * | +-----> 0b0000 (B)
+ * +--------> 0b0111 (G)
*/
- ch = vga_get_cp437(c);
+
+ for (i = 0; i < height; ++i) {
+ for (color = 0; color < 16; ++color) {
+ mask = masks[i * 16 + color];
+ if (mask == 0x00)
+ continue;
+
+ for (j = 0; j < 8; ++j) {
+ if (!((mask >> (7 - j)) & 0x1))
+ continue;
+
+ /* The pixel "j" uses color "color". */
+ for (plan = 0; plan < 4; ++plan)
+ plans[i * 4 + plan] |=
+ ((color >> plan) & 0x1) << (7 - j);
+ }
+ }
+ }
/*
- * Convert colors to VGA attributes.
+ * The bytes are ready: we now switch to Write Mode 0 and write
+ * all bytes, one plan at a time.
*/
- attr = bg << 4 | fg;
+ vga_setwmode(vd, 0);
- MEM_WRITE1(sc, 0x18000 + (top * 80 + left) * 2 + 0, ch);
- MEM_WRITE1(sc, 0x18000 + (top * 80 + left) * 2 + 1, attr);
+ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK);
+ for (plan = 0; plan < 4; ++plan) {
+ /* Select plan. */
+ REG_WRITE1(sc, VGA_SEQ_DATA, 1 << plan);
+
+ /* Write all bytes for this plan, from Y to Y+height. */
+ for (i = 0; i < height; ++i) {
+ offset = (VT_VGA_WIDTH * (y + i) + x) / 8;
+ MEM_WRITE1(sc, offset, plans[i * 4 + plan]);
+ }
+ }
+}
+
+static void
+vga_bitblt_one_text_pixels_block(struct vt_device *vd,
+ const struct vt_window *vw, unsigned int x, unsigned int y)
+{
+ const struct vt_buf *vb;
+ const struct vt_font *vf;
+ unsigned int i, col, row, src_x, x_count;
+ unsigned int used_colors_list[16], used_colors;
+ uint8_t pattern_2colors[vw->vw_font->vf_height];
+ uint8_t pattern_ncolors[vw->vw_font->vf_height * 16];
+ term_char_t c;
+ term_color_t fg, bg;
+ const uint8_t *src;
+
+ vb = &vw->vw_buf;
+ vf = vw->vw_font;
+
+ /*
+ * The current pixels block.
+ *
+ * We fill it with portions of characters, because both "grids"
+ * may not match.
+ *
+ * i is the index in this pixels block.
+ */
+
+ i = x;
+ used_colors = 0;
+ memset(used_colors_list, 0, sizeof(used_colors_list));
+ memset(pattern_2colors, 0, sizeof(pattern_2colors));
+ memset(pattern_ncolors, 0, sizeof(pattern_ncolors));
+
+ if (i < vw->vw_draw_area.tr_begin.tp_col) {
+ /*
+ * i is in the margin used to center the text area on
+ * the screen.
+ */
+
+ i = vw->vw_draw_area.tr_begin.tp_col;
+ }
+
+ while (i < x + VT_VGA_PIXELS_BLOCK &&
+ i < vw->vw_draw_area.tr_end.tp_col) {
+ /*
+ * Find which character is drawn on this pixel in the
+ * pixels block.
+ *
+ * While here, record what colors it uses.
+ */
+
+ col = (i - vw->vw_draw_area.tr_begin.tp_col) / vf->vf_width;
+ row = (y - vw->vw_draw_area.tr_begin.tp_row) / vf->vf_height;
+
+ c = VTBUF_GET_FIELD(vb, row, col);
+ src = vtfont_lookup(vf, c);
+
+ vt_determine_colors(c, VTBUF_ISCURSOR(vb, row, col), &fg, &bg);
+ if ((used_colors_list[fg] & 0x1) != 0x1)
+ used_colors++;
+ if ((used_colors_list[bg] & 0x2) != 0x2)
+ used_colors++;
+ used_colors_list[fg] |= 0x1;
+ used_colors_list[bg] |= 0x2;
+
+ /*
+ * Compute the portion of the character we want to draw,
+ * because the pixels block may start in the middle of a
+ * character.
+ *
+ * The first pixel to draw in the character is
+ * the current position -
+ * the start position of the character
+ *
+ * The last pixel to draw is either
+ * - the last pixel of the character, or
+ * - the pixel of the character matching the end of
+ * the pixels block
+ * whichever comes first. This position is then
+ * changed to be relative to the start position of the
+ * character.
+ */
+
+ src_x = i -
+ (col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col);
+ x_count = min(min(
+ (col + 1) * vf->vf_width +
+ vw->vw_draw_area.tr_begin.tp_col,
+ x + VT_VGA_PIXELS_BLOCK),
+ vw->vw_draw_area.tr_end.tp_col);
+ x_count -= col * vf->vf_width +
+ vw->vw_draw_area.tr_begin.tp_col;
+ x_count -= src_x;
+
+ /* Copy a portion of the character. */
+ vga_copy_bitmap_portion(pattern_2colors, pattern_ncolors,
+ src, NULL, vf->vf_width,
+ src_x, i % VT_VGA_PIXELS_BLOCK, x_count,
+ 0, 0, vf->vf_height, fg, bg, 0);
+
+ /* We move to the next portion. */
+ i += x_count;
+ }
+
+#ifndef SC_NO_CUTPASTE
+ /*
+ * Copy the mouse pointer bitmap if it's over the current pixels
+ * block.
+ *
+ * We use the saved cursor position (saved in vt_flush()), because
+ * the current position could be different than the one used
+ * to mark the area dirty.
+ */
+ term_rect_t drawn_area;
+
+ drawn_area.tr_begin.tp_col = x;
+ drawn_area.tr_begin.tp_row = y;
+ drawn_area.tr_end.tp_col = x + VT_VGA_PIXELS_BLOCK;
+ drawn_area.tr_end.tp_row = y + vf->vf_height;
+ if (vd->vd_mshown && vt_is_cursor_in_area(vd, &drawn_area)) {
+ struct vt_mouse_cursor *cursor;
+ unsigned int mx, my;
+ unsigned int dst_x, src_y, dst_y, y_count;
+
+ cursor = vd->vd_mcursor;
+ mx = vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col;
+ my = vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row;
+
+ /* Compute the portion of the cursor we want to copy. */
+ src_x = x > mx ? x - mx : 0;
+ dst_x = mx > x ? mx - x : 0;
+ x_count = min(min(min(
+ cursor->width - src_x,
+ x + VT_VGA_PIXELS_BLOCK - mx),
+ vw->vw_draw_area.tr_end.tp_col - mx),
+ VT_VGA_PIXELS_BLOCK);
+
+ /*
+ * The cursor isn't aligned on the Y-axis with
+ * characters, so we need to compute the vertical
+ * start/count.
+ */
+ src_y = y > my ? y - my : 0;
+ dst_y = my > y ? my - y : 0;
+ y_count = min(
+ min(cursor->height - src_y, y + vf->vf_height - my),
+ vf->vf_height);
+
+ /* Copy the cursor portion. */
+ vga_copy_bitmap_portion(pattern_2colors, pattern_ncolors,
+ cursor->map, cursor->mask, cursor->width,
+ src_x, dst_x, x_count, src_y, dst_y, y_count,
+ vd->vd_mcursor_fg, vd->vd_mcursor_bg, 1);
+
+ if ((used_colors_list[vd->vd_mcursor_fg] & 0x1) != 0x1)
+ used_colors++;
+ if ((used_colors_list[vd->vd_mcursor_bg] & 0x2) != 0x2)
+ used_colors++;
+ }
+#endif
+
+ /*
+ * The pixels block is completed, we can now draw it on the
+ * screen.
+ */
+ if (used_colors == 2)
+ vga_bitblt_pixels_block_2colors(vd, pattern_2colors, fg, bg,
+ x, y, vf->vf_height);
+ else
+ vga_bitblt_pixels_block_ncolors(vd, pattern_ncolors,
+ x, y, vf->vf_height);
+}
+
+static void
+vga_bitblt_text_gfxmode(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+ const struct vt_font *vf;
+ unsigned int col, row;
+ unsigned int x1, y1, x2, y2, x, y;
+
+ vf = vw->vw_font;
+
+ /*
+ * Compute the top-left pixel position aligned with the video
+ * adapter pixels block size.
+ *
+ * This is calculated from the top-left column of te dirty area:
+ *
+ * 1. Compute the top-left pixel of the character:
+ * col * font width + x offset
+ *
+ * NOTE: x offset is used to center the text area on the
+ * screen. It's expressed in pixels, not in characters
+ * col/row!
+ *
+ * 2. Find the pixel further on the left marking the start of
+ * an aligned pixels block (eg. chunk of 8 pixels):
+ * character's x / blocksize * blocksize
+ *
+ * The division, being made on integers, achieves the
+ * alignment.
+ *
+ * For the Y-axis, we need to compute the character's y
+ * coordinate, but we don't need to align it.
+ */
+
+ col = area->tr_begin.tp_col;
+ row = area->tr_begin.tp_row;
+ x1 = (int)((col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col)
+ / VT_VGA_PIXELS_BLOCK)
+ * VT_VGA_PIXELS_BLOCK;
+ y1 = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row;
+
+ /*
+ * Compute the bottom right pixel position, again, aligned with
+ * the pixels block size.
+ *
+ * The same rules apply, we just add 1 to base the computation
+ * on the "right border" of the dirty area.
+ */
+
+ col = area->tr_end.tp_col;
+ row = area->tr_end.tp_row;
+ x2 = (int)((col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col
+ + VT_VGA_PIXELS_BLOCK - 1)
+ / VT_VGA_PIXELS_BLOCK)
+ * VT_VGA_PIXELS_BLOCK;
+ y2 = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row;
+
+ /* Clip the area to the screen size. */
+ x2 = min(x2, vw->vw_draw_area.tr_end.tp_col);
+ y2 = min(y2, vw->vw_draw_area.tr_end.tp_row);
+
+ /*
+ * Now, we take care of N pixels line at a time (the first for
+ * loop, N = font height), and for these lines, draw one pixels
+ * block at a time (the second for loop), not a character at a
+ * time.
+ *
+ * Therefore, on the X-axis, characters my be drawn partially if
+ * they are not aligned on 8-pixels boundary.
+ *
+ * However, the operation is repeated for the full height of the
+ * font before moving to the next character, because it allows
+ * to keep the color settings and write mode, before perhaps
+ * changing them with the next one.
+ */
+
+ for (y = y1; y < y2; y += vf->vf_height) {
+ for (x = x1; x < x2; x += VT_VGA_PIXELS_BLOCK) {
+ vga_bitblt_one_text_pixels_block(vd, vw, x, y);
+ }
+ }
+}
+
+static void
+vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+ struct vga_softc *sc;
+ const struct vt_buf *vb;
+ unsigned int col, row;
+ term_char_t c;
+ term_color_t fg, bg;
+ uint8_t ch, attr;
+
+ sc = vd->vd_softc;
+ vb = &vw->vw_buf;
+
+ 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) {
+ /*
+ * Get next character and its associated fg/bg
+ * colors.
+ */
+ c = VTBUF_GET_FIELD(vb, row, col);
+ vt_determine_colors(c, VTBUF_ISCURSOR(vb, row, col),
+ &fg, &bg);
+
+ /*
+ * Convert character to CP437, which is the
+ * character set used by the VGA hardware by
+ * default.
+ */
+ ch = vga_get_cp437(TCHAR_CHARACTER(c));
+
+ /* Convert colors to VGA attributes. */
+ attr = bg << 4 | fg;
+
+ MEM_WRITE1(sc, 0x18000 + (row * 80 + col) * 2 + 0,
+ ch);
+ MEM_WRITE1(sc, 0x18000 + (row * 80 + col) * 2 + 1,
+ attr);
+ }
+ }
+}
+
+static void
+vga_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
+ const term_rect_t *area)
+{
+
+ if (!(vd->vd_flags & VDF_TEXTMODE)) {
+ vga_bitblt_text_gfxmode(vd, vw, area);
+ } else {
+ vga_bitblt_text_txtmode(vd, vw, area);
+ }
+}
+
+static void
+vga_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
+ const uint8_t *pattern, const uint8_t *mask,
+ unsigned int width, unsigned int height,
+ unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
+{
+ unsigned int x1, y1, x2, y2, i, j, src_x, dst_x, x_count;
+ uint8_t pattern_2colors;
+
+ /* Align coordinates with the 8-pxels grid. */
+ x1 = x / VT_VGA_PIXELS_BLOCK * VT_VGA_PIXELS_BLOCK;
+ y1 = y;
+
+ x2 = (x + width + VT_VGA_PIXELS_BLOCK - 1) /
+ VT_VGA_PIXELS_BLOCK * VT_VGA_PIXELS_BLOCK;
+ y2 = y + height;
+ x2 = min(x2, vd->vd_width - 1);
+ y2 = min(y2, vd->vd_height - 1);
+
+ for (j = y1; j < y2; ++j) {
+ src_x = 0;
+ dst_x = x - x1;
+ x_count = VT_VGA_PIXELS_BLOCK - dst_x;
+
+ for (i = x1; i < x2; i += VT_VGA_PIXELS_BLOCK) {
+ pattern_2colors = 0;
+
+ vga_copy_bitmap_portion(
+ &pattern_2colors, NULL,
+ pattern, mask, width,
+ src_x, dst_x, x_count,
+ j - y1, 0, 1, fg, bg, 0);
+
+ vga_bitblt_pixels_block_2colors(vd,
+ &pattern_2colors, fg, bg,
+ i, j, 1);
+
+ src_x += x_count;
+ dst_x = (dst_x + x_count) % VT_VGA_PIXELS_BLOCK;
+ x_count = min(width - src_x, VT_VGA_PIXELS_BLOCK);
+ }
+ }
}
static void
@@ -625,8 +1166,22 @@ vga_initialize(struct vt_device *vd, int textmode)
/* Switch to write mode 3, because we'll mainly do bitblt. */
REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE);
REG_WRITE1(sc, VGA_GC_DATA, 3);
+ sc->vga_wmode = 3;
+
+ /*
+ * In Write Mode 3, Enable Set/Reset is ignored, but we
+ * use Write Mode 0 to write a group of 8 pixels using
+ * 3 or more colors. In this case, we want to disable
+ * Set/Reset: set Enable Set/Reset to 0.
+ */
REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_ENABLE_SET_RESET);
- REG_WRITE1(sc, VGA_GC_DATA, 0x0f);
+ REG_WRITE1(sc, VGA_GC_DATA, 0x00);
+
+ /*
+ * Clear the colors we think are loaded into Set/Reset or
+ * the latches.
+ */
+ sc->vga_curfg = sc->vga_curbg = 0xff;
}
}
diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h
index 2a7b5e0..a667e1c 100644
--- a/sys/dev/vt/vt.h
+++ b/sys/dev/vt/vt.h
@@ -110,6 +110,10 @@ typedef unsigned int vt_axis_t;
* Per-device datastructure.
*/
+#ifndef SC_NO_CUTPASTE
+struct vt_mouse_cursor;
+#endif
+
struct vt_device {
struct vt_window *vd_windows[VT_MAXWINDOWS]; /* (c) Windows. */
struct vt_window *vd_curwindow; /* (d) Current window. */
@@ -117,12 +121,17 @@ struct vt_device {
struct vt_window *vd_markedwin; /* (?) Copy/paste buf owner. */
const struct vt_driver *vd_driver; /* (c) Graphics driver. */
void *vd_softc; /* (u) Driver data. */
+#ifndef SC_NO_CUTPASTE
+ struct vt_mouse_cursor *vd_mcursor; /* (?) Cursor bitmap. */
+ term_color_t vd_mcursor_fg; /* (?) Cursor fg color. */
+ term_color_t vd_mcursor_bg; /* (?) Cursor bg color. */
+ vt_axis_t vd_mx_drawn; /* (?) Mouse X and Y */
+ vt_axis_t vd_my_drawn; /* as of last redraw. */
+ int vd_mshown; /* (?) Mouse shown during */
+#endif /* last redrawn. */
uint16_t vd_mx; /* (?) Current mouse X. */
uint16_t vd_my; /* (?) current mouse Y. */
- vt_axis_t vd_moldx; /* (?) Mouse X as of last redraw. */
- vt_axis_t vd_moldy; /* (?) Mouse Y as of last redraw. */
uint32_t vd_mstate; /* (?) Mouse state. */
- term_pos_t vd_offset; /* (?) Pixel offset. */
vt_axis_t vd_width; /* (?) Screen width. */
vt_axis_t vd_height; /* (?) Screen height. */
struct mtx vd_lock; /* Per-device lock. */
@@ -168,7 +177,7 @@ struct vt_buf {
#define VBF_MTX_INIT 0x4 /* Mutex initialized. */
#define VBF_SCROLL 0x8 /* scroll locked mode. */
#define VBF_HISTORY_FULL 0x10 /* All rows filled. */
- int vb_history_size;
+ unsigned int vb_history_size;
#define VBF_DEFAULT_HISTORY_SIZE 500
int vb_roffset; /* (b) History rows offset. */
int vb_curroffset; /* (b) Saved rows offset. */
@@ -186,16 +195,16 @@ void vtbuf_copy(struct vt_buf *, const term_rect_t *, const term_pos_t *);
void vtbuf_fill_locked(struct vt_buf *, const term_rect_t *, term_char_t);
void vtbuf_init_early(struct vt_buf *);
void vtbuf_init(struct vt_buf *, const term_pos_t *);
-void vtbuf_grow(struct vt_buf *, const term_pos_t *, int);
+void vtbuf_grow(struct vt_buf *, const term_pos_t *, unsigned int);
void vtbuf_putchar(struct vt_buf *, const term_pos_t *, term_char_t);
void vtbuf_cursor_position(struct vt_buf *, const term_pos_t *);
void vtbuf_scroll_mode(struct vt_buf *vb, int yes);
+void vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area);
void vtbuf_undirty(struct vt_buf *, term_rect_t *, struct vt_bufmask *);
void vtbuf_sethistory_size(struct vt_buf *, int);
int vtbuf_iscursor(const struct vt_buf *vb, int row, int col);
void vtbuf_cursor_visibility(struct vt_buf *, int);
#ifndef SC_NO_CUTPASTE
-void vtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row);
int vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row);
int vtbuf_get_marked_len(struct vt_buf *vb);
void vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz);
@@ -244,6 +253,7 @@ struct vt_window {
struct terminal *vw_terminal; /* (c) Terminal. */
struct vt_buf vw_buf; /* (u) Screen buffer. */
struct vt_font *vw_font; /* (d) Graphical font. */
+ term_rect_t vw_draw_area; /* (?) Drawable area. */
unsigned int vw_number; /* (c) Window number. */
int vw_kbdmode; /* (?) Keyboard mode. */
char *vw_kbdsq; /* Escape sequence queue*/
@@ -256,6 +266,7 @@ struct vt_window {
#define VWF_VTYLOCK 0x10 /* Prevent window switch. */
#define VWF_MOUSE_HIDE 0x20 /* Disable mouse events processing. */
#define VWF_READY 0x40 /* Window fully initialized. */
+#define VWF_GRAPHICS 0x80 /* Window in graphics mode (KDSETMODE). */
#define VWF_SWWAIT_REL 0x10000 /* Program wait for VT acquire is done. */
#define VWF_SWWAIT_ACQ 0x20000 /* Program wait for VT release is done. */
pid_t vw_pid; /* Terminal holding process */
@@ -273,21 +284,18 @@ struct vt_window {
/*
* Per-device driver routines.
- *
- * vd_bitbltchr is used when the driver operates in graphics mode, while
- * vd_putchar is used when the driver operates in text mode
- * (VDF_TEXTMODE).
*/
typedef int vd_init_t(struct vt_device *vd);
typedef int vd_probe_t(struct vt_device *vd);
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_bitbltchr_t(struct vt_device *vd, const uint8_t *src,
- const uint8_t *mask, int bpl, vt_axis_t top, vt_axis_t left,
- unsigned int width, unsigned int height, term_color_t fg, term_color_t bg);
-typedef void vd_putchar_t(struct vt_device *vd, term_char_t,
- vt_axis_t top, vt_axis_t left, term_color_t fg, term_color_t bg);
+typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw,
+ 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,
+ unsigned int x, unsigned int y, term_color_t fg, term_color_t bg);
typedef int vd_fb_ioctl_t(struct vt_device *, u_long, caddr_t, struct thread *);
typedef int vd_fb_mmap_t(struct vt_device *, vm_ooffset_t, vm_paddr_t *, int,
vm_memattr_t *);
@@ -303,9 +311,10 @@ struct vt_driver {
/* Drawing. */
vd_blank_t *vd_blank;
- vd_bitbltchr_t *vd_bitbltchr;
vd_drawrect_t *vd_drawrect;
vd_setpixel_t *vd_setpixel;
+ vd_bitblt_text_t *vd_bitblt_text;
+ vd_bitblt_bmp_t *vd_bitblt_bmp;
/* Framebuffer ioctls, if present. */
vd_fb_ioctl_t *vd_fb_ioctl;
@@ -313,9 +322,6 @@ struct vt_driver {
/* Framebuffer mmap, if present. */
vd_fb_mmap_t *vd_fb_mmap;
- /* Text mode operation. */
- vd_putchar_t *vd_putchar;
-
/* Update display setting on vt switch. */
vd_postswitch_t *vd_postswitch;
@@ -373,11 +379,11 @@ struct vt_font {
};
#ifndef SC_NO_CUTPASTE
-struct mouse_cursor {
+struct vt_mouse_cursor {
uint8_t map[64 * 64 / 8];
uint8_t mask[64 * 64 / 8];
- uint8_t w;
- uint8_t h;
+ uint8_t width;
+ uint8_t height;
};
#endif
@@ -395,5 +401,11 @@ void vt_mouse_state(int show);
#define VT_MOUSE_SHOW 1
#define VT_MOUSE_HIDE 0
+/* Utilities. */
+void vt_determine_colors(term_char_t c, int cursor,
+ term_color_t *fg, term_color_t *bg);
+int vt_is_cursor_in_area(const struct vt_device *vd,
+ const term_rect_t *area);
+
#endif /* !_DEV_VT_VT_H_ */
diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c
index e6efcd2..d468173 100644
--- a/sys/dev/vt/vt_buf.c
+++ b/sys/dev/vt/vt_buf.c
@@ -246,7 +246,7 @@ vtbuf_dirty_locked(struct vt_buf *vb, const term_rect_t *area)
vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col);
}
-static inline void
+void
vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area)
{
@@ -410,9 +410,9 @@ vtbuf_init_early(struct vt_buf *vb)
vtbuf_init_rows(vb);
rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0;
- rect.tr_end = vb->vb_scr_size;
- vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR((boothowto & RB_MUTE) == 0 ?
- TERMINAL_KERN_ATTR : TERMINAL_NORM_ATTR));
+ rect.tr_end.tp_col = vb->vb_scr_size.tp_col;
+ rect.tr_end.tp_row = vb->vb_history_size;
+ vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR));
vtbuf_make_undirty(vb);
if ((vb->vb_flags & VBF_MTX_INIT) == 0) {
mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN);
@@ -451,7 +451,7 @@ vtbuf_sethistory_size(struct vt_buf *vb, int size)
}
void
-vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size)
+vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size)
{
term_char_t *old, *new, **rows, **oldrows, **copyrows, *row;
int bufsize, rowssize, w, h, c, r;
@@ -558,18 +558,6 @@ vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p)
}
#ifndef SC_NO_CUTPASTE
-void
-vtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row)
-{
- term_rect_t area;
-
- area.tr_begin.tp_row = MAX(row - 1, 0);
- area.tr_begin.tp_col = MAX(col - 1, 0);
- area.tr_end.tp_row = MIN(row + 2, vb->vb_scr_size.tp_row);
- area.tr_end.tp_col = MIN(col + 2, vb->vb_scr_size.tp_col);
- vtbuf_dirty(vb, &area);
-}
-
static void
vtbuf_flush_mark(struct vt_buf *vb)
{
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 918778a..0911739 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -131,7 +131,7 @@ extern unsigned char vt_logo_image[];
/* Font. */
extern struct vt_font vt_font_default;
#ifndef SC_NO_CUTPASTE
-extern struct mouse_cursor vt_default_mouse_pointer;
+extern struct vt_mouse_cursor vt_default_mouse_pointer;
#endif
static int signal_vt_rel(struct vt_window *);
@@ -159,6 +159,12 @@ static struct vt_device vt_consdev = {
.vd_curwindow = &vt_conswindow,
.vd_markedwin = NULL,
.vd_kbstate = 0,
+
+#ifndef SC_NO_CUTPASTE
+ .vd_mcursor = &vt_default_mouse_pointer,
+ .vd_mcursor_fg = TC_WHITE,
+ .vd_mcursor_bg = TC_BLACK,
+#endif
};
static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)];
static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE];
@@ -239,7 +245,8 @@ static void
vt_resume_flush_timer(struct vt_device *vd, int ms)
{
- if (!atomic_cmpset_int(&vd->vd_timer_armed, 0, 1))
+ if (!(vd->vd_flags & VDF_ASYNC) ||
+ !atomic_cmpset_int(&vd->vd_timer_armed, 0, 1))
return;
vt_schedule_flush(vd, ms);
@@ -249,7 +256,8 @@ static void
vt_suspend_flush_timer(struct vt_device *vd)
{
- if (!atomic_cmpset_int(&vd->vd_timer_armed, 1, 0))
+ if (!(vd->vd_flags & VDF_ASYNC) ||
+ !atomic_cmpset_int(&vd->vd_timer_armed, 1, 0))
return;
callout_drain(&vd->vd_timer);
@@ -406,6 +414,31 @@ vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size)
}
}
+static inline void
+vt_compute_drawable_area(struct vt_window *vw)
+{
+ struct vt_device *vd;
+ struct vt_font *vf;
+
+ if (vw->vw_font == NULL)
+ return;
+
+ vd = vw->vw_device;
+ vf = vw->vw_font;
+
+ /*
+ * Compute the drawable area, so that the text is centered on
+ * the screen.
+ */
+
+ vw->vw_draw_area.tr_begin.tp_col = (vd->vd_width % vf->vf_width) / 2;
+ vw->vw_draw_area.tr_begin.tp_row = (vd->vd_height % vf->vf_height) / 2;
+ vw->vw_draw_area.tr_end.tp_col = vw->vw_draw_area.tr_begin.tp_col +
+ vd->vd_width / vf->vf_width * vf->vf_width;
+ vw->vw_draw_area.tr_end.tp_row = vw->vw_draw_area.tr_begin.tp_row +
+ vd->vd_height / vf->vf_height * vf->vf_height;
+}
+
static void
vt_scroll(struct vt_window *vw, int offset, int whence)
{
@@ -419,16 +452,18 @@ vt_scroll(struct vt_window *vw, int offset, int whence)
diff = vthistory_seek(&vw->vw_buf, offset, whence);
/*
- * Offset changed, please update Nth lines on sceen.
+ * Offset changed, please update Nth lines on screen.
* +N - Nth lines at top;
* -N - Nth lines at bottom.
*/
if (diff < -size.tp_row || diff > size.tp_row) {
vw->vw_device->vd_flags |= VDF_INVALID;
+ vt_resume_flush_timer(vw->vw_device, 0);
return;
}
vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/
+ vt_resume_flush_timer(vw->vw_device, 0);
}
static int
@@ -737,6 +772,7 @@ vtterm_cursor(struct terminal *tm, const term_pos_t *p)
struct vt_window *vw = tm->tm_softc;
vtbuf_cursor_position(&vw->vw_buf, p);
+ vt_resume_flush_timer(vw->vw_device, 0);
}
static void
@@ -745,6 +781,7 @@ vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c)
struct vt_window *vw = tm->tm_softc;
vtbuf_putchar(&vw->vw_buf, p, c);
+ vt_resume_flush_timer(vw->vw_device, 0);
}
static void
@@ -753,6 +790,7 @@ vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c)
struct vt_window *vw = tm->tm_softc;
vtbuf_fill_locked(&vw->vw_buf, r, c);
+ vt_resume_flush_timer(vw->vw_device, 0);
}
static void
@@ -762,6 +800,7 @@ vtterm_copy(struct terminal *tm, const term_rect_t *r,
struct vt_window *vw = tm->tm_softc;
vtbuf_copy(&vw->vw_buf, r, p);
+ vt_resume_flush_timer(vw->vw_device, 0);
}
static void
@@ -772,6 +811,7 @@ vtterm_param(struct terminal *tm, int cmd, unsigned int arg)
switch (cmd) {
case TP_SHOWCURSOR:
vtbuf_cursor_visibility(&vw->vw_buf, arg);
+ vt_resume_flush_timer(vw->vw_device, 0);
break;
case TP_MOUSE:
vw->vw_mouse_level = arg;
@@ -779,7 +819,7 @@ vtterm_param(struct terminal *tm, int cmd, unsigned int arg)
}
}
-static inline void
+void
vt_determine_colors(term_char_t c, int cursor,
term_color_t *fg, term_color_t *bg)
{
@@ -805,98 +845,130 @@ vt_determine_colors(term_char_t c, int cursor,
}
}
-static void
-vt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c,
- int iscursor, unsigned int row, unsigned int col)
+#ifndef SC_NO_CUTPASTE
+int
+vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area)
{
- term_color_t fg, bg;
+ unsigned int mx, my, x1, y1, x2, y2;
- vt_determine_colors(c, iscursor, &fg, &bg);
+ /*
+ * We use the cursor position saved during the current refresh,
+ * in case the cursor moved since.
+ */
+ mx = vd->vd_mx_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_col;
+ my = vd->vd_my_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_row;
+
+ x1 = area->tr_begin.tp_col;
+ y1 = area->tr_begin.tp_row;
+ x2 = area->tr_end.tp_col;
+ y2 = area->tr_end.tp_row;
+
+ if (((mx >= x1 && x2 - 1 >= mx) ||
+ (mx < x1 && mx + vd->vd_mcursor->width >= x1)) &&
+ ((my >= y1 && y2 - 1 >= my) ||
+ (my < y1 && my + vd->vd_mcursor->height >= y1)))
+ return (1);
- if (vf != NULL) {
- const uint8_t *src;
- vt_axis_t top, left;
+ return (0);
+}
+
+static void
+vt_mark_mouse_position_as_dirty(struct vt_device *vd)
+{
+ term_rect_t area;
+ struct vt_window *vw;
+ struct vt_font *vf;
+ int x, y;
- src = vtfont_lookup(vf, c);
+ vw = vd->vd_curwindow;
+ vf = vw->vw_font;
- /*
- * Align the terminal to the centre of the screen.
- * Fonts may not always be able to fill the entire
- * screen.
- */
- top = row * vf->vf_height + vd->vd_offset.tp_row;
- left = col * vf->vf_width + vd->vd_offset.tp_col;
+ x = vd->vd_mx_drawn;
+ y = vd->vd_my_drawn;
- vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left,
- vf->vf_width, vf->vf_height, fg, bg);
+ if (vf != NULL) {
+ area.tr_begin.tp_col = x / vf->vf_width;
+ area.tr_begin.tp_row = y / vf->vf_height;
+ area.tr_end.tp_col =
+ ((x + vd->vd_mcursor->width) / vf->vf_width) + 1;
+ area.tr_end.tp_row =
+ ((y + vd->vd_mcursor->height) / vf->vf_height) + 1;
} else {
- vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c),
- row, col, fg, bg);
+ /*
+ * No font loaded (ie. vt_vga operating in textmode).
+ *
+ * FIXME: This fake area needs to be revisited once the
+ * mouse cursor is supported in vt_vga's textmode.
+ */
+ area.tr_begin.tp_col = x;
+ area.tr_begin.tp_row = y;
+ area.tr_end.tp_col = x + 2;
+ area.tr_end.tp_row = y + 2;
}
+
+ vtbuf_dirty(&vw->vw_buf, &area);
}
+#endif
-static void
+static int
vt_flush(struct vt_device *vd)
{
struct vt_window *vw;
struct vt_font *vf;
struct vt_bufmask tmask;
- unsigned int row, col;
term_rect_t tarea;
term_pos_t size;
- term_char_t *r;
#ifndef SC_NO_CUTPASTE
- struct mouse_cursor *m;
- int bpl, h, w;
+ int cursor_was_shown, cursor_moved;
#endif
vw = vd->vd_curwindow;
if (vw == NULL)
- return;
- vf = vw->vw_font;
- if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL))
- return;
+ return (0);
if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
- return;
+ return (0);
+
+ vf = vw->vw_font;
+ if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL))
+ return (0);
#ifndef SC_NO_CUTPASTE
- if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */
- !(vw->vw_flags & VWF_MOUSE_HIDE)) { /* Cursor displayed. */
- if (vd->vd_moldx != vd->vd_mx ||
- vd->vd_moldy != vd->vd_my) {
- /*
- * Mark last mouse position as dirty to erase.
- *
- * FIXME: The font size could be different among
- * all windows, so the column/row calculation
- * below isn't correct for all windows.
- *
- * FIXME: The cursor can span more than one
- * character cell. vtbuf_mouse_cursor_position
- * marks surrounding cells as dirty. But due
- * to font size possibly inconsistent across
- * windows, this may not be sufficient. This
- * causes part of the cursor to not be erased.
- *
- * FIXME: The vt_buf lock is acquired twice in a
- * row.
- */
- vtbuf_mouse_cursor_position(&vw->vw_buf,
- vd->vd_moldx / vf->vf_width,
- vd->vd_moldy / vf->vf_height);
- vtbuf_mouse_cursor_position(&vw->vw_buf,
- vd->vd_mx / vf->vf_width,
- vd->vd_my / vf->vf_height);
+ cursor_was_shown = vd->vd_mshown;
+ cursor_moved = (vd->vd_mx != vd->vd_mx_drawn ||
+ vd->vd_my != vd->vd_my_drawn);
- /*
- * Save point of last mouse cursor to erase it
- * later.
- */
- vd->vd_moldx = vd->vd_mx;
- vd->vd_moldy = vd->vd_my;
- }
+ /* Check if the cursor should be displayed or not. */
+ if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */
+ !(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed. */
+ !kdb_active && panicstr == NULL) { /* DDB inactive. */
+ vd->vd_mshown = 1;
+ } else {
+ vd->vd_mshown = 0;
}
+
+ /*
+ * If the cursor changed display state or moved, we must mark
+ * the old position as dirty, so that it's erased.
+ */
+ if (cursor_was_shown != vd->vd_mshown ||
+ (vd->vd_mshown && cursor_moved))
+ vt_mark_mouse_position_as_dirty(vd);
+
+ /*
+ * Save position of the mouse cursor. It's used by backends to
+ * know where to draw the cursor and during the next refresh to
+ * erase the previous position.
+ */
+ vd->vd_mx_drawn = vd->vd_mx;
+ vd->vd_my_drawn = vd->vd_my;
+
+ /*
+ * If the cursor is displayed and has moved since last refresh,
+ * mark the new position as dirty.
+ */
+ if (vd->vd_mshown && cursor_moved)
+ vt_mark_mouse_position_as_dirty(vd);
#endif
vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
@@ -911,60 +983,29 @@ vt_flush(struct vt_device *vd)
vd->vd_flags &= ~VDF_INVALID;
}
- for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) {
- if (!VTBUF_DIRTYROW(&tmask, row))
- continue;
- r = VTBUF_GET_ROW(&vw->vw_buf, row);
- for (col = tarea.tr_begin.tp_col;
- col < tarea.tr_end.tp_col; col++) {
- if (!VTBUF_DIRTYCOL(&tmask, col))
- continue;
-
- vt_bitblt_char(vd, vf, r[col],
- VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col);
- }
+ if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) {
+ vd->vd_driver->vd_bitblt_text(vd, vw, &tarea);
+ return (1);
}
-#ifndef SC_NO_CUTPASTE
- /* Mouse disabled. */
- if (vw->vw_flags & VWF_MOUSE_HIDE)
- return;
-
- /* No mouse for DDB. */
- if (kdb_active || panicstr != NULL)
- return;
-
- if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) ==
- VDF_MOUSECURSOR) {
- m = &vt_default_mouse_pointer;
- bpl = (m->w + 7) >> 3; /* Bytes per source line. */
- w = m->w;
- h = m->h;
-
- if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width))
- w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1;
- if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height))
- h = (size.tp_row * vf->vf_height) - vd->vd_my - 1;
-
- vd->vd_driver->vd_bitbltchr(vd, m->map, m->mask, bpl,
- vd->vd_offset.tp_row + vd->vd_my,
- vd->vd_offset.tp_col + vd->vd_mx,
- w, h, TC_WHITE, TC_BLACK);
- }
-#endif
+ return (0);
}
static void
vt_timer(void *arg)
{
struct vt_device *vd;
+ int changed;
vd = arg;
/* Update screen if required. */
- vt_flush(vd);
+ changed = vt_flush(vd);
/* Schedule for next update. */
- vt_schedule_flush(vd, 0);
+ if (changed)
+ vt_schedule_flush(vd, 0);
+ else
+ vd->vd_timer_armed = 0;
}
static void
@@ -1002,8 +1043,9 @@ vtterm_splash(struct vt_device *vd)
switch (vt_logo_depth) {
case 1:
/* XXX: Unhardcode colors! */
- vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0,
- top, left, vt_logo_width, vt_logo_height, 0xf, 0x0);
+ vd->vd_driver->vd_bitblt_bmp(vd, vd->vd_curwindow,
+ vt_logo_image, NULL, vt_logo_width, vt_logo_height,
+ left, top, TC_WHITE, TC_BLACK);
}
vd->vd_flags |= VDF_SPLASH;
}
@@ -1059,8 +1101,10 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp)
sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw));
/* Attach default font if not in TEXTMODE. */
- if ((vd->vd_flags & VDF_TEXTMODE) == 0)
+ if ((vd->vd_flags & VDF_TEXTMODE) == 0) {
vw->vw_font = vtfont_ref(&vt_font_default);
+ vt_compute_drawable_area(vw);
+ }
vtbuf_init_early(&vw->vw_buf);
vt_winsize(vd, vw->vw_font, &wsz);
@@ -1184,6 +1228,35 @@ vtterm_opened(struct terminal *tm, int opened)
}
static int
+vt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c)
+{
+ struct vt_device *vd = vw->vw_device;
+ int x, y, off_x, off_y;
+
+ if (vd->vd_driver->vd_drawrect == NULL)
+ return (ENOTSUP);
+
+ x = vd->vd_width - 1;
+ y = vd->vd_height - 1;
+ off_x = vw->vw_draw_area.tr_begin.tp_col;
+ off_y = vw->vw_draw_area.tr_begin.tp_row;
+
+ /* Top bar. */
+ if (off_y > 0)
+ vd->vd_driver->vd_drawrect(vd, 0, 0, x, off_y - 1, 1, c);
+ /* Left bar. */
+ if (off_x > 0)
+ vd->vd_driver->vd_drawrect(vd, 0, off_y, off_x - 1, y - off_y,
+ 1, c);
+ /* Right bar. May be 1 pixel wider than necessary due to rounding. */
+ vd->vd_driver->vd_drawrect(vd, x - off_x, off_y, x, y - off_y, 1, c);
+ /* Bottom bar. May be 1 mixel taller than necessary due to rounding. */
+ vd->vd_driver->vd_drawrect(vd, 0, y - off_y, x, y, 1, c);
+
+ return (0);
+}
+
+static int
vt_change_font(struct vt_window *vw, struct vt_font *vf)
{
struct vt_device *vd = vw->vw_device;
@@ -1220,9 +1293,6 @@ vt_change_font(struct vt_window *vw, struct vt_font *vf)
vt_termsize(vd, vf, &size);
vt_winsize(vd, vf, &wsz);
- /* Save offset to font aligned area. */
- vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2;
- vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2;
/* Grow the screen buffer and terminal. */
terminal_mute(tm, 1);
@@ -1241,44 +1311,30 @@ vt_change_font(struct vt_window *vw, struct vt_font *vf)
vw->vw_font = vtfont_ref(vf);
}
+ /*
+ * Compute the drawable area and move the mouse cursor inside
+ * it, in case the new area is smaller than the previous one.
+ */
+ vt_compute_drawable_area(vw);
+ vd->vd_mx = min(vd->vd_mx,
+ vw->vw_draw_area.tr_end.tp_col -
+ vw->vw_draw_area.tr_begin.tp_col - 1);
+ vd->vd_my = min(vd->vd_my,
+ vw->vw_draw_area.tr_end.tp_row -
+ vw->vw_draw_area.tr_begin.tp_row - 1);
+
/* Force a full redraw the next timer tick. */
- if (vd->vd_curwindow == vw)
+ if (vd->vd_curwindow == vw) {
+ vt_set_border(vw, vf, TC_BLACK);
vd->vd_flags |= VDF_INVALID;
+ vt_resume_flush_timer(vw->vw_device, 0);
+ }
vw->vw_flags &= ~VWF_BUSY;
VT_UNLOCK(vd);
return (0);
}
static int
-vt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c)
-{
- struct vt_device *vd = vw->vw_device;
- int x, y, off_x, off_y;
-
- if (vd->vd_driver->vd_drawrect == NULL)
- return (ENOTSUP);
-
- x = vd->vd_width - 1;
- y = vd->vd_height - 1;
- off_x = vd->vd_offset.tp_col;
- off_y = vd->vd_offset.tp_row;
-
- /* Top bar. */
- if (off_y > 0)
- vd->vd_driver->vd_drawrect(vd, 0, 0, x, off_y - 1, 1, c);
- /* Left bar. */
- if (off_x > 0)
- vd->vd_driver->vd_drawrect(vd, 0, off_y, off_x - 1, y - off_y,
- 1, c);
- /* Right bar. May be 1 pixel wider than necessary due to rounding. */
- vd->vd_driver->vd_drawrect(vd, x - off_x, off_y, x, y - off_y, 1, c);
- /* Bottom bar. May be 1 mixel taller than necessary due to rounding. */
- vd->vd_driver->vd_drawrect(vd, 0, y - off_y, x, y, 1, c);
-
- return (0);
-}
-
-static int
vt_proc_alive(struct vt_window *vw)
{
struct proc *p;
@@ -1441,8 +1497,13 @@ vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel)
vf = vw->vw_font;
mark = 0;
- if (vw->vw_flags & VWF_MOUSE_HIDE)
- return; /* Mouse disabled. */
+ if (vw->vw_flags & (VWF_MOUSE_HIDE | VWF_GRAPHICS))
+ /*
+ * Either the mouse is disabled, or the window is in
+ * "graphics mode". The graphics mode is usually set by
+ * an X server, using the KDSETMODE ioctl.
+ */
+ return;
if (vf == NULL) /* Text mode. */
return;
@@ -1474,7 +1535,7 @@ vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel)
vd->vd_my = y;
if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) &&
(vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE,
- vd->vd_mx / vf->vf_width,
+ vd->vd_mx / vf->vf_width,
vd->vd_my / vf->vf_height) == 1)) {
/*
@@ -1483,6 +1544,8 @@ vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel)
*/
vd->vd_markedwin = vw;
}
+
+ vt_resume_flush_timer(vw->vw_device, 0);
return; /* Done */
case MOUSE_BUTTON_EVENT:
/* Buttons */
@@ -1567,6 +1630,7 @@ vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel)
* window with selection.
*/
vd->vd_markedwin = vw;
+ vt_resume_flush_timer(vw->vw_device, 0);
}
}
@@ -1588,14 +1652,9 @@ vt_mouse_state(int show)
break;
}
- /*
- * Mark mouse position as dirty.
- *
- * FIXME: See comments in vt_flush().
- */
- vtbuf_mouse_cursor_position(&vw->vw_buf,
- vd->vd_mx / vw->vw_font->vf_width,
- vd->vd_my / vw->vw_font->vf_height);
+ /* Mark mouse position as dirty. */
+ vt_mark_mouse_position_as_dirty(vd);
+ vt_resume_flush_timer(vw->vw_device, 0);
}
#endif
@@ -1668,6 +1727,7 @@ skip_thunk:
case KDSETRAD: /* set keyboard repeat & delay rates (old) */
if (*(int *)data & ~0x7f)
return (EINVAL);
+ /* FALLTHROUGH */
case GIO_KEYMAP:
case PIO_KEYMAP:
case GIO_DEADKEYMAP:
@@ -1813,10 +1873,6 @@ skip_thunk:
return (error);
error = vt_change_font(vw, vf);
- if (error == 0) {
- /* XXX: replace 0 with current bg color. */
- vt_set_border(vw, vf, 0);
- }
vtfont_unref(vf);
return (error);
}
@@ -1829,7 +1885,20 @@ skip_thunk:
return (0);
}
case KDSETMODE:
- /* XXX */
+ /*
+ * FIXME: This implementation is incomplete compared to
+ * syscons.
+ */
+ switch (*(int *)data) {
+ case KD_TEXT:
+ case KD_TEXT1:
+ case KD_PIXEL:
+ vw->vw_flags &= ~VWF_GRAPHICS;
+ break;
+ case KD_GRAPHICS:
+ vw->vw_flags |= VWF_GRAPHICS;
+ break;
+ }
return (0);
case KDENABIO: /* allow io operations */
error = priv_check(td, PRIV_IO);
@@ -2063,8 +2132,10 @@ vt_allocate_window(struct vt_device *vd, unsigned int window)
vw->vw_number = window;
vw->vw_kbdmode = K_XLATE;
- if ((vd->vd_flags & VDF_TEXTMODE) == 0)
+ if ((vd->vd_flags & VDF_TEXTMODE) == 0) {
vw->vw_font = vtfont_ref(&vt_font_default);
+ vt_compute_drawable_area(vw);
+ }
vt_termsize(vd, vw->vw_font, &size);
vt_winsize(vd, vw->vw_font, &wsz);
@@ -2141,6 +2212,7 @@ vt_resize(struct vt_device *vd)
if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL)
vw->vw_font = vtfont_ref(&vt_font_default);
VT_UNLOCK(vd);
+
/* Resize terminal windows */
while (vt_change_font(vw, vw->vw_font) == EBUSY) {
DPRINTF(100, "%s: vt_change_font() is busy, "
diff --git a/sys/powerpc/ps3/ps3_syscons.c b/sys/powerpc/ps3/ps3_syscons.c
index 3b1aea9..1c4f4d8 100644
--- a/sys/powerpc/ps3/ps3_syscons.c
+++ b/sys/powerpc/ps3/ps3_syscons.c
@@ -76,7 +76,8 @@ static struct vt_driver vt_ps3fb_driver = {
.vd_probe = ps3fb_probe,
.vd_init = ps3fb_init,
.vd_blank = vt_fb_blank,
- .vd_bitbltchr = vt_fb_bitbltchr,
+ .vd_bitblt_text = vt_fb_bitblt_text,
+ .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
.vd_fb_ioctl = vt_fb_ioctl,
.vd_fb_mmap = vt_fb_mmap,
/* Better than VGA, but still generic driver. */
OpenPOWER on IntegriCloud