diff --git a/src/cpu.js b/src/cpu.js index 3e7b0005..9cb5c6d4 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -161,6 +161,9 @@ function CPU(bus, wm, next_tick_immediately) this.reg_pdpte = v86util.view(Int32Array, memory, 968, 8); + this.svga_dirty_bitmap_min_offset = v86util.view(Uint32Array, memory, 716, 1); + this.svga_dirty_bitmap_max_offset = v86util.view(Uint32Array, memory, 720, 1); + this.fw_value = []; this.fw_pointer = 0; this.option_roms = []; diff --git a/src/rust/cpu/global_pointers.rs b/src/rust/cpu/global_pointers.rs index e884b4c5..00b0b336 100644 --- a/src/rust/cpu/global_pointers.rs +++ b/src/rust/cpu/global_pointers.rs @@ -40,6 +40,10 @@ pub const instruction_counter: *mut u32 = 664 as *mut u32; pub const sreg: *mut u16 = 668 as *mut u16; pub const dreg: *mut i32 = 684 as *mut i32; +// filled in by svga_fill_pixel_buffer, read by javacsript for optimised putImageData calls +pub const svga_dirty_bitmap_min_offset: *mut u32 = 716 as *mut u32; +pub const svga_dirty_bitmap_max_offset: *mut u32 = 720 as *mut u32; + pub const segment_is_null: *mut bool = 724 as *mut bool; pub const segment_offsets: *mut i32 = 736 as *mut i32; pub const segment_limits: *mut u32 = 768 as *mut u32; diff --git a/src/rust/cpu/vga.rs b/src/rust/cpu/vga.rs index a78fbeb7..5c7e56a0 100644 --- a/src/rust/cpu/vga.rs +++ b/src/rust/cpu/vga.rs @@ -1,5 +1,6 @@ #![allow(non_upper_case_globals)] +use cpu::global_pointers; use cpu::memory; pub static mut dirty_bitmap: Vec = Vec::new(); @@ -26,6 +27,9 @@ pub unsafe fn svga_mark_dirty() { } fn iter_dirty_pages(f: &dyn Fn(isize)) { + let mut min_off = u32::MAX; + let mut max_off = u32::MIN; + for (i, &word) in unsafe { &dirty_bitmap }.iter().enumerate() { if word == 0 { continue; @@ -36,13 +40,22 @@ fn iter_dirty_pages(f: &dyn Fn(isize)) { } let off = ((i << 6 | j) << 12) as isize; dbg_assert!(off < unsafe { memory::vga_memory_size as isize }); + if min_off == u32::MAX { + min_off = off as u32; + } + max_off = off as u32; f(off); } } + + unsafe { + *global_pointers::svga_dirty_bitmap_min_offset = min_off; + *global_pointers::svga_dirty_bitmap_max_offset = max_off; + } } #[no_mangle] -pub unsafe fn svga_fill_pixel_buffer(bpp: i32, svga_dest_offset: i32) { +pub unsafe fn svga_fill_pixel_buffer(bpp: u32, svga_dest_offset: u32) { let debug_bounds = false; match bpp { @@ -58,6 +71,8 @@ pub unsafe fn svga_fill_pixel_buffer(bpp: i32, svga_dest_offset: i32) { isize::min(1024, dest_buffer.len() as isize - dest_offset) }; + dbg_assert!(src as u32 % 8 == 0); + dbg_assert!(dest as u32 % 8 == 0); for i in 0..end { dbg_assert!(off + i < memory::vga_memory_size as isize); let dword = *src.offset(i); diff --git a/src/vga.js b/src/vga.js index b70865a7..bff80159 100644 --- a/src/vga.js +++ b/src/vga.js @@ -2279,6 +2279,9 @@ VGAScreen.prototype.screen_fill_buffer = function() if(this.svga_enabled) { + let min_y = 0; + let max_y = this.svga_height - 1; + if(this.svga_bpp === 8) { // XXX: Slow, should be ported to rust, but it doesn't have access to vga256_palette @@ -2295,18 +2298,23 @@ VGAScreen.prototype.screen_fill_buffer = function() else { this.cpu.svga_fill_pixel_buffer(this.svga_bpp, this.svga_offset); + + const bytes_per_pixel = this.svga_bpp === 15 ? 2 : this.svga_bpp / 8; + const bytes_per_line = bytes_per_pixel * this.svga_width; + min_y = this.cpu.svga_dirty_bitmap_min_offset[0] / bytes_per_line | 0; + max_y = this.cpu.svga_dirty_bitmap_max_offset[0] / bytes_per_line | 0; } - const min_y = 0; - const max_y = this.svga_height; - - this.bus.send("screen-fill-buffer-end", [{ - image_data: this.image_data, - screen_x: 0, screen_y: min_y, - buffer_x: 0, buffer_y: min_y, - buffer_width: this.svga_width, - buffer_height: max_y - min_y + 1, - }]); + if(min_y < max_y) + { + this.bus.send("screen-fill-buffer-end", [{ + image_data: this.image_data, + screen_x: 0, screen_y: min_y, + buffer_x: 0, buffer_y: min_y, + buffer_width: this.svga_width, + buffer_height: max_y - min_y + 1, + }]); + } } else {