Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VGA graphical text mode #1123

Merged
merged 38 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b1766c6
Revert "Add VGA graphical text mode"
chschnell Sep 22, 2024
6152b74
started 2nd iteration of graphical text mode
chschnell Sep 22, 2024
404c3f7
fixed eslint complaints
chschnell Sep 22, 2024
02de981
include changes to main.js and cpu.js from f92e6b4, fix eslint error
chschnell Sep 22, 2024
8798246
added new methods in ScreenAdapter to DummyScreenAdapter
chschnell Sep 22, 2024
6dec4bd
include changes to starter.js from f92e6b4
chschnell Sep 22, 2024
91efd19
changed text attribute BLINKING to FLAGS, introduced flags for BLINKI…
chschnell Sep 22, 2024
93ef88a
added support for cursor and blinking, made ScreenAdapter.FLAGS_* vis…
chschnell Sep 23, 2024
d15c827
Variuos improvements and fixes.
chschnell Sep 23, 2024
8217ca1
fixed issues detected by eslint
chschnell Sep 23, 2024
6d74ee0
fixed classical text mode
chschnell Sep 23, 2024
47d8d02
optimization: do not copy buffer to canvas when it's unmodified
chschnell Sep 23, 2024
f724857
invalidate all text rows when entering graphical text mode
chschnell Sep 23, 2024
ee5b95c
Made sure that complete_redraw() is called whenever the state that pu…
chschnell Sep 26, 2024
8a59102
removed leftover comment
chschnell Sep 27, 2024
cef6e84
Merge branch 'copy:master' into master
chschnell Sep 27, 2024
4445c3c
added new VGAScreen state variable font_page_ab_enabled to state[]
chschnell Sep 27, 2024
e290f00
render internal font less often but more aggressively
chschnell Sep 27, 2024
7cb49fc
fixed bug in ScreenAdapter.set_font_bitmap()
chschnell Sep 27, 2024
d543b1c
refactored ScreenAdapter
chschnell Sep 28, 2024
f949166
fixed bug in restoring state of graphical text: font_page was missing
chschnell Sep 28, 2024
1066f26
Merge branch 'copy:master' into master
chschnell Oct 1, 2024
861dfb4
restored accidentally lost cleanup code from commit f92e6b4
chschnell Oct 3, 2024
ff632a0
narrowed scope of some variables
chschnell Oct 3, 2024
d35da67
removed obsolete compatibility attributes from graphic_context
chschnell Oct 3, 2024
48b9975
removed redundant initialization call to ScreenAdapter.set_mode()
chschnell Oct 3, 2024
9f2d029
allow overriding private member charmap[] to support external codepag…
chschnell Oct 3, 2024
e58e02b
merged grab_text_content() into get_text_row()/get_text_screen()
chschnell Oct 3, 2024
0e76c0f
removed comment as suggested
chschnell Oct 3, 2024
ea2119f
replaced boolean options.disable_autoscale with number options.scale
chschnell Oct 3, 2024
403d5e5
changed render_font_bitmap() to return void, reduced reallocation of …
chschnell Oct 3, 2024
26939fd
added guard to ensure that set_font_bitmap() is only called in text mode
chschnell Oct 5, 2024
fcb634b
changed text rendering method to glyph-blitting using canvas.drawImage()
chschnell Oct 5, 2024
11cf1c8
improved cursor rendering
chschnell Oct 5, 2024
4681e94
improved foreground color handling
chschnell Oct 5, 2024
8bcf116
minor changes
chschnell Oct 5, 2024
4e91d37
improved rendering of invisible glyphs
chschnell Oct 5, 2024
308be89
improved vga bit handling readabilty
chschnell Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Made sure that complete_redraw() is called whenever the state that pu…
…t_char() depends on is modified.

Method VGAScreen.put_char() depends on:

1. screen-wide BLINK_ENABLE bit
2. screen-wide PAGE_AB_ENABLE bit
3. VGAScreen.vga256_palette[]
4. VGAScreen.dac_mask
5. VGAScreen.dac_map

For 1, 3 and 5 this was already the case.

Added call to VGAScreen.complete_redraw() when PAGE_AB_ENABLE is changed.

Added call to VGAScreen.complete_redraw() when VGAScreen.dac_map is changed.

Added logic to mask out most significant foreground color bit if screen-wide PAGE_AB_ENABLE is true.
  • Loading branch information
chschnell committed Sep 26, 2024
commit ee5b95cd0fbf33bbfaa2860830b01583f97e95e4
19 changes: 7 additions & 12 deletions src/browser/screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function ScreenAdapter(options, screen_fill_buffer)
};

let i_src = 0;
for(let i_font = 0; i_font < 8; ++i_font)
for(let i_font_page = 0; i_font_page < 8; ++i_font_page)
{
for(let i_chr = 0; i_chr < 256; ++i_chr, i_src += vga_inc_chr)
{
Expand All @@ -210,13 +210,11 @@ function ScreenAdapter(options, screen_fill_buffer)
return dst_bitmap;
}

function render_dirty_rows()
function render_changed_rows()
{
const font_size = font_width * font_height;
const font_AB_enabled = font_page_a !== font_page_b;
const font_A_offset = font_page_a * 256;
const font_B_offset = font_page_b * 256;
const font_blink_enabled = true; // TODO!
const cursor_visible = cursor_enabled && blink_visible;
const cursor_height = cursor_end - cursor_start + 1;
const gfx_width = font_width * text_mode_width;
Expand Down Expand Up @@ -257,8 +255,8 @@ function ScreenAdapter(options, screen_fill_buffer)
{
const chr = text_mode_data[txt_i + CHARACTER_INDEX];
const chr_flags = text_mode_data[txt_i + FLAGS_INDEX];
const chr_blinking = font_blink_enabled && chr_flags & FLAG_BLINKING;
const chr_font_offset = font_AB_enabled && chr_flags & FLAG_FONT_PAGE_B ? font_B_offset : font_A_offset;
const chr_blinking = chr_flags & FLAG_BLINKING;
const chr_font_offset = chr_flags & FLAG_FONT_PAGE_B ? font_B_offset : font_A_offset;
const chr_bg_rgba = text_mode_data[txt_i + BG_COLOR_INDEX];
const chr_fg_rgba = text_mode_data[txt_i + FG_COLOR_INDEX];

Expand Down Expand Up @@ -536,7 +534,7 @@ function ScreenAdapter(options, screen_fill_buffer)
tm_last_update = tm_now;
}
// copy to canvas only if render buffer changed
if(render_dirty_rows())
if(render_changed_rows())
{
graphic_context.putImageData(graphical_text_image_data, 0, 0);
}
Expand Down Expand Up @@ -611,12 +609,9 @@ function ScreenAdapter(options, screen_fill_buffer)
{
font_bitmap = render_font_bitmap(bitmap);
changed_rows.fill(1);
if(size_changed)
if(size_changed && mode === MODE_GRAPHICAL_TEXT)
{
if(mode === MODE_GRAPHICAL_TEXT)
{
this.set_size_graphical_text();
}
this.set_size_graphical_text();
}
}
};
Expand Down
62 changes: 33 additions & 29 deletions src/vga.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ function VGAScreen(cpu, bus, screen, vga_memory_size, options)
this.port_3DA_value = 0xFF;

this.text_font_plane_dirty = false;
this.font_page_ab_enabled = false;

var io = cpu.io;

Expand Down Expand Up @@ -835,8 +836,9 @@ VGAScreen.prototype.text_mode_redraw = function()
{
const split_screen_row = this.scan_line_to_screen_row(this.line_compare);
const row_offset = Math.max(0, (this.offset_register * 2 - this.max_cols) * 2);
const blink_flag = this.attribute_mode & 1 << 3;
const bg_color_mask = blink_flag ? 7 : 0xF;
const blink_enabled = this.attribute_mode & 1 << 3;
const fg_color_mask = this.font_page_ab_enabled ? 7 : 0xF;
const bg_color_mask = blink_enabled ? 7 : 0xF;
const FLAG_BLINKING = this.screen.FLAG_BLINKING;
const FLAG_FONT_PAGE_B = this.screen.FLAG_FONT_PAGE_B;

Expand All @@ -853,15 +855,15 @@ VGAScreen.prototype.text_mode_redraw = function()
{
const chr = this.vga_memory[addr];
const color = this.vga_memory[addr | 1];
const blinking = blink_flag && (color & 1 << 7);
const font_page_b = !(color & 1 << 3);
const blinking = blink_enabled && (color & 1 << 7);
const font_page_b = this.font_page_ab_enabled && !(color & 1 << 3);
const flags = (blinking ? FLAG_BLINKING : 0) | (font_page_b ? FLAG_FONT_PAGE_B : 0);

this.bus.send("screen-put-char", [row, col, chr]);

this.screen.put_char(row, col, chr, flags,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & bg_color_mask]],
this.vga256_palette[this.dac_mask & this.dac_map[color & 0xF]]);
this.vga256_palette[this.dac_mask & this.dac_map[color & fg_color_mask]]);

addr += 2;
}
Expand Down Expand Up @@ -912,17 +914,18 @@ VGAScreen.prototype.vga_memory_write_text_mode = function(addr, value)
chr = value;
color = this.vga_memory[addr | 1];
}
const blink_flag = this.attribute_mode & 1 << 3;
const blinking = blink_flag && (color & 1 << 7);
const font_page_b = !(color & 1 << 3);
const blink_enabled = this.attribute_mode & 1 << 3;
const blinking = blink_enabled && (color & 1 << 7);
const font_page_b = this.font_page_ab_enabled && !(color & 1 << 3);
const flags = (blinking ? this.screen.FLAG_BLINKING : 0) | (font_page_b ? this.screen.FLAG_FONT_PAGE_B : 0);
const bg_color_mask = blink_flag ? 7 : 0xF;
const fg_color_mask = this.font_page_ab_enabled ? 7 : 0xF;
const bg_color_mask = blink_enabled ? 7 : 0xF;

this.bus.send("screen-put-char", [row, col, chr]);

this.screen.put_char(row, col, chr, flags,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & bg_color_mask]],
this.vga256_palette[this.dac_mask & this.dac_map[color & 0xF]]);
this.vga256_palette[this.dac_mask & this.dac_map[color & fg_color_mask]]);
};

VGAScreen.prototype.update_cursor = function()
Expand Down Expand Up @@ -1138,11 +1141,6 @@ VGAScreen.prototype.set_size_text = function(cols_count, rows_count)
this.max_cols = cols_count;
this.max_rows = rows_count;

if(this.text_font_plane_dirty)
{
this.set_font_bitmap();
}

this.screen.set_size_text(cols_count, rows_count);
this.bus.send("screen-set-size", [cols_count, rows_count, 0]);
};
Expand Down Expand Up @@ -1258,7 +1256,7 @@ VGAScreen.prototype.update_vga_size = function()
this.set_size_text(horizontal_characters, height);
}

this.set_font_bitmap();
this.set_font_bitmap(false);
}
};

Expand Down Expand Up @@ -1429,7 +1427,7 @@ VGAScreen.prototype.port3C0_write = function(value)
// Data stored in image buffer are invalidated
this.complete_redraw();

this.set_font_bitmap();
this.set_font_bitmap(false);
}
break;
case 0x12:
Expand Down Expand Up @@ -1545,7 +1543,7 @@ VGAScreen.prototype.port3C5_write = function(value)
// Screen disable bit modified
this.update_layers();
}
this.set_font_bitmap();
this.set_font_bitmap(false);
break;
case 0x02:
dbg_log("plane write mask: " + h(value), LOG_VGA);
Expand All @@ -1554,7 +1552,8 @@ VGAScreen.prototype.port3C5_write = function(value)
if(!this.graphical_mode && this.text_font_plane_dirty && previous_plane_write_bm & 0x4 && !(this.plane_write_bm & 0x4))
{
// End of font plane 2 write access
this.set_font_bitmap();
this.set_font_bitmap(true);
this.text_font_plane_dirty = false;
}
break;
case 0x03:
Expand All @@ -1569,7 +1568,9 @@ VGAScreen.prototype.port3C5_write = function(value)
const linear_index_map = [0, 2, 4, 6, 1, 3, 5, 7];
const vga_index_A = ((value & 0b1100) >> 2) | ((value & 0b100000) >> 3);
const vga_index_B = (value & 0b11) | ((value & 0b10000) >> 2);
this.font_page_ab_enabled = vga_index_A !== vga_index_B;
this.screen.set_font_page(linear_index_map[vga_index_A], linear_index_map[vga_index_B]);
this.complete_redraw();
}
break;
case 0x04:
Expand Down Expand Up @@ -1604,7 +1605,11 @@ VGAScreen.prototype.port3C5_read = function()

VGAScreen.prototype.port3C6_write = function(data)
{
this.dac_mask = data;
if(this.dac_mask !== data)
{
this.dac_mask = data;
this.complete_redraw();
}
};

VGAScreen.prototype.port3C6_read = function()
Expand Down Expand Up @@ -1888,7 +1893,7 @@ VGAScreen.prototype.port3D5_write = function(value)
this.update_cursor_scanline();
this.update_layers();

this.set_font_bitmap();
this.set_font_bitmap(false);
break;
case 0xA:
dbg_log("3D5 / cursor scanline start write: " + h(value), LOG_VGA);
Expand Down Expand Up @@ -2527,7 +2532,7 @@ VGAScreen.prototype.screen_fill_buffer = function()
this.update_vertical_retrace();
};

VGAScreen.prototype.set_font_bitmap = function()
VGAScreen.prototype.set_font_bitmap = function(font_plane_dirty)
{
const height = this.max_scan_line & 0x1f;
if(height)
Expand All @@ -2536,13 +2541,12 @@ VGAScreen.prototype.set_font_bitmap = function()
const width_9px = !width_dbl && !(this.clocking_mode & 0x01);
const copy_8th_col = !!(this.attribute_mode & 0x04);
this.screen.set_font_bitmap(
height + 1, // int height, font height 1..32px
width_9px, // bool width_9px, True: font width 9px, else 8px
width_dbl, // bool width_dbl, True: font width 16px (overrides width_9px)
copy_8th_col, // bool copy_8th_col, True: duplicate 8th into 9th column in ASCII chars 0xC0-0xDF
this.plane2, // Uint8Array font_bitmap[64k], static
this.text_font_plane_dirty // bool bitmap_changed, True: content of this.plane2 has changed
height + 1, // int height, font height 1..32px
width_9px, // bool width_9px, True: font width 9px, else 8px
width_dbl, // bool width_dbl, True: font width 16px (overrides width_9px)
copy_8th_col, // bool copy_8th_col, True: duplicate 8th into 9th column in ASCII chars 0xC0-0xDF
this.plane2, // Uint8Array font_bitmap[64k], static
font_plane_dirty // bool bitmap_changed, True: content of this.plane2 has changed
);
this.text_font_plane_dirty = false;
}
};
Loading