From: Marc-André Lureau <[email protected]> When bit 3 of the VGA Attribute Mode Control register is set, attribute bit 7 switches from selecting bright background colors to enabling character blink.
Implement this by tracking a separate blink phase timer that toggles every 32 frames (matching real VGA hardware frame counter bit 5 @60hz), and rendering blinking characters by replacing their foreground with background during the off phase. As with cursor, no VMState migration of the fields, as they are transient display-side states. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1585 Signed-off-by: Marc-André Lureau <[email protected]> --- hw/display/vga_int.h | 2 ++ hw/display/vga.c | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 747b5cc6cf8..5664317ecd6 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -130,6 +130,8 @@ typedef struct VGACommonState { uint8_t cursor_start, cursor_end; bool cursor_visible_phase; int64_t cursor_blink_time; + bool blink_visible_phase; + int64_t blink_time; uint32_t cursor_offset; const GraphicHwOps *hw_ops; bool full_update_text; diff --git a/hw/display/vga.c b/hw/display/vga.c index 0ac4bf37310..ea01a889f20 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -45,8 +45,10 @@ bool have_vga = true; -/* 16 state changes per vertical frame @60 Hz */ +/* frame counter bit 4: cursor blink toggles every 16 frames @60 Hz */ #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) +/* frame counter bit 5: character blink toggles every 32 frames @60 Hz */ +#define VGA_TEXT_BLINK_PERIOD_MS (1000 * 2 * 32 / 60) /* Address mask for non-VESA modes. */ #define VGA_VRAM_SIZE (256 * KiB) @@ -1286,6 +1288,13 @@ static void vga_draw_text(VGACommonState *s, int full_update) s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2; s->cursor_visible_phase = !s->cursor_visible_phase; } + if (now >= s->blink_time) { + s->blink_time = now + VGA_TEXT_BLINK_PERIOD_MS / 2; + s->blink_visible_phase = !s->blink_visible_phase; + if (s->ar[VGA_ATC_MODE] & 0x08) { + full_update = 1; + } + } dest = surface_data(surface); linesize = surface_stride(surface); @@ -1317,8 +1326,17 @@ static void vga_draw_text(VGACommonState *s, int full_update) #endif font_ptr = font_base[(cattr >> 3) & 1]; font_ptr += 32 * 4 * ch; - bgcol = palette[cattr >> 4]; - fgcol = palette[cattr & 0x0f]; + if (s->ar[VGA_ATC_MODE] & 0x08) { + bgcol = palette[(cattr >> 4) & 0x07]; + if ((cattr & 0x80) && !s->blink_visible_phase) { + fgcol = bgcol; + } else { + fgcol = palette[cattr & 0x0f]; + } + } else { + bgcol = palette[cattr >> 4]; + fgcol = palette[cattr & 0x0f]; + } if (cw == 16) { vga_draw_glyph16(d1, linesize, font_ptr, cheight, fgcol, bgcol); -- 2.54.0
