summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2014-09-04 20:18:08 +0000
committeremaste <emaste@FreeBSD.org>2014-09-04 20:18:08 +0000
commit1a3d3113bf90005851a1df8d34f450a163a43b56 (patch)
treed5a6c94a4300fa1231640c2d70b2a76e54202c9b /sys/dev
parentec8cd58eaa7dce1497f70cbccb426548688b297a (diff)
downloadFreeBSD-src-1a3d3113bf90005851a1df8d34f450a163a43b56.zip
FreeBSD-src-1a3d3113bf90005851a1df8d34f450a163a43b56.tar.gz
MFC vt(4) improvements / sync with HEAD
These are largely dumbbell@'s changes. Most significantly they address the extreme performance degradation with VGA hardware. SVN revisions in this MFC: 269471 270290 270293 270322 270324 270329 270331 270336 270338 270340 270341 270342 270343 270388 270390 270404 270411 270412 270413 270431 270446 270448 270485 270587 270589 270613 270618 270620 270667 270702 270707 270708 270720 270721 270785 270786 Detailed commit list: r270290: Test if the cursor is shown only once Later, we just see if the "struct mouse_cursor" pointer is set. This avoids the need to mess with all the conditions several times; this has been error prone. While here, rename the variable "m" to a more meaningful "cursor", like it's done elsewhere in the code. r270293: Rename the "mouse_cursor" structure to "vt_mouse_cursor" At the same time, "w" and "h" members are now called "width" and "height". The goal is to have a more "public" structure, because it will soon be passed as argument to a new callback, replacing vd_bitbltchr_t. r269471 (ray): Fix vt_vga driver to draw not-8-bit-aligned fonts correctly. Still one bug here: mouse left some gaps on track when moving left. r270322: Add new vd_bitblt_text_t callback, and implement it for vt_vga Compared to the deprecated vd_bitbltchr_t callback, vd_bitblt_text_t receives: o the whole text buffer o the dirty area o the mouse cursor (map, position, colors) This allows the backend to perform optimization on how to draw things. The goal is to remove vd_bitbltchr_t and vd_putchar_t, once all driver are converted (only vt_vga is included in this commit). In vt_vga, this allows to draw the text and the cursor in one pass, without ever reading from video memory (because it has all the context). The main benefit is the speed improvement: no more slideshow during boot! Other bugs fixed in vt_vga are: o left-most characters are drawn properly (the left-most pixels were missing with bold characters and some wide letters such as 'm') o no more black square around the cursor o no cursor flickering when the text is scrolling There are still many problems to fix: the known issues are marked with "FIXME" inside the code. r270411: vt_fb: Implement vd_bitblt_text_t for vt_fb and derivatives r270412: creator_fb: Implement vd_bitblt_text_t r270413: ofwfb: Implement vd_bitblt_text_t r270324: vt_vga: Clip the draw area to never draw offscreen This fixes a bug when two windows use different fonts, but a longer- term solution is required. The dirty area should be stored as pixels, not character cells, because such coordinates don't have the same meaning in all windows, when using different fonts. r270329: Mark new mouse position as dirty only when it's actually displayed r270331: Store cursor bitmap & colors in struct vt_device This removes the need to specify them to each call to vd_bitblt_text_t and, therefore, simplifies the API. r270336: Give the window to vd_bitblt_text_t callback ... instead of both the buffer and the font. Again, this simplifies the API. r270338: The offset to center the text area is per-window now The previous global offset, based on the last loaded font, had no meaning for other windows. This caused a shifted text area, often partly out-of-screen. r270341: vt_vga: Remove a "FIXME" comment; the issue was solved in r270338 r270340: Don't run vt_set_border() and vt_flush() concurrently In the case of vt_vga, the two concurrent calls were writing to the same VGA registers, causing incorrect refresh of the screen. r270342: Use the actual size of the mouse when marking its position as dirty This fixes a bug where part of the cursor was not erased. r270343: Remove "FIXME" about multiple locking of vt_buf in vt_flush() After some testing, it appears that acquiring the lock once and keeping it longer is slower than taking it multiple times. While here, fix a typo in another comment. r270388: vt_vga: Give only the character part of term_char_t to vga_get_cp437() This fixes a bug where vga_get_cp437() was called with an invalid argument. The screen was then filled with '?' instead of the actual character. r270390: Fix a crash in vt_mark_mouse_position_as_dirty() when in textmode In textmode, no font is loaded, thus the page fault in vt_mark_mouse_position_as_dirty() when it wants the font width/height. For now, create a fake area for the textmode. This needs to be modified if vt_vga gains mouse support in textmode. While here, fix a build failure when SC_NO_CUTPASTE is defined: vt_mark_mouse_position_as_dirty() must not be included in this case. r270404: Fix cursor handling in vt_flush() There were situations where the cursor was not erased/redrawn or its position was marked as dirty even though it's not displayed. The code is now more straightforward. At the same, add a function to determine if the cursor covers a given area. This is used by backends to know if they need to draw the cursor. This new function should be paired with a new state in struct vt_device, called vd_mshown, which indicates if the cursor should be displayed. This again simplifies vd_bitblt_text_t callback's API. r270431: vt(4): Add vd_bitblt_bmp_t callback The code was already there in all backends, we just expose it. This is used to display the splash screen. r270446: Remove vd_bitbltchr_t It's replaced by vd_bitblt_text_t, which gives more context to the backend and allows it to perform more efficiently when redrawing a given area. r270448: Fix order of arguments (x <-> y) when showing the splash screen r270485: vt_vga: Fix the display of the splash screen r270587: Take font offset into account in vt_is_cursor_in_area() This fixes a "General protection fault" in vt_vga, where vt_is_cursor_in_area() erroneously reported that the cursor was over the text. This led to negative integers stored in "unsigned int" and chaos. r270589: The cursor coordinates are relative to the drawn area ... not the whole screen. Don't use font offsets in vt_mark_mouse_position_as_dirty(). This fixes a bug where the mouse position wasn't marked as dirty when approaching the borders of the drawn area. r270613: Store a rectangle for the drawable area, not just the top-left corner This allows backends to verify they do not draw outside of this area. This fixes a bug in vt_vga where the text was happily drawn over the right and bottom margins, when using the Gallant font. r270618: Intialize drawable area rectangle each time a font is loaded This also fixes a problem where early in boot, the area was zero, leading to nothing displayed for a few seconds. r270620: vt_vga: Use Write Mode 0 to draw group of 8 pixels using 3 or more colors This replaces the method based on Write Mode 3, which required reads from the video memory to load the latches. r270667: When creating a window buffer, fill it entirely ... not just the visible part. This fixes a bug where, when switching from eg. vt_vga to vt_fb (ie. the resolution goes up), the originally hidden, uninitialized area of the buffer is displayed on the screen. This leads to a missing text cursor when it's over an unitialized area. This was also visible when selecting text: the uninitialized area was not highlighted. Internally, this area was zeroed: characters were all 0x00000000, meaning the foreground and background color was black. Now, everything is filled with a space with a gray foreground color, like the visible area. While here, remove the check for the mute flag and always use TERMINAL_NORM_ATTR as the character attribute (ie. gray foreground, black background). r270702: Implement basic support for KDSETMODE ioctl With the current implementation, this allows an X11 server to tell the console it switches a particular window in "graphics mode". This information is used by the mouse handling code to ignore sysmouse events in the window taken by the X server: only him should receive those events. r270707: Pause the vt_flush() timer when the screen is up-to-date The timer is restarted whenever a window buffer is marked as dirty or the mouse cursor moves. There's still room for improvement. For instance, we should not mark a window buffer as dirty when this window isn't displayed. r270708: vt(4): Recompute the drawable area when the resolution changes This was only done when the font changed. r270720: vt(4): Fix mouse cursor handling in vt_fb/creator_vt/ofwfb There were two issues: 1. The area given to vt_is_cursor_in_area() was adding the drawable area offset, something already handled by this function. 2. The cursor was shifted on the screen by the offset of this area and thus was misplaced or not erased. Furthermore, when reaching the bottom or right borders, the cursor was either totally removed or not erased correctly. r270721: vt(4): If the terminal shrinks, make sure the mouse is inside the new area r270785: vt(4): Change vb_history_size from "int" to "unsigned int" CID: 1230002, 1230003 r270786: Indicate that KDSETRAD case falls through the next case CID: 1229953 Relnotes: Yes
Diffstat (limited to 'sys/dev')
-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
11 files changed, 1206 insertions, 410 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, "
OpenPOWER on IntegriCloud