Spaces:
Runtime error
Runtime error
// Safety of allow(static_mut_refs) in this file: | |
// These following two globals are not passed anywhere, only built-in function are called on them | |
static mut dirty_bitmap: Vec<u64> = Vec::new(); | |
static mut dest_buffer: Vec<u32> = Vec::new(); | |
use crate::cpu::global_pointers; | |
use crate::cpu::memory; | |
use std::ptr; | |
pub unsafe fn svga_allocate_dest_buffer(size: u32) -> u32 { | |
dest_buffer.resize(size as usize, 0); | |
dest_buffer.as_mut_ptr() as u32 | |
} | |
pub unsafe fn set_dirty_bitmap_size(size: u32) { dirty_bitmap.resize(size as usize, 0); } | |
pub unsafe fn mark_dirty(addr: u32) { | |
let page = (addr - memory::VGA_LFB_ADDRESS) >> 12; | |
dbg_assert!(((page >> 6) as usize) < dirty_bitmap.len()); | |
*dirty_bitmap.get_unchecked_mut((page >> 6) as usize) |= 1 << (page & 63) | |
} | |
pub unsafe fn svga_mark_dirty() { | |
for v in dirty_bitmap.iter_mut() { | |
*v = u64::MAX | |
} | |
} | |
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; | |
} | |
for j in 0..64 { | |
if word & 1 << j == 0 { | |
continue; | |
} | |
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 + 0xFFF; | |
} | |
} | |
pub unsafe fn svga_fill_pixel_buffer(bpp: u32, svga_dest_offset: u32) { | |
let debug_bounds = false; | |
match bpp { | |
32 => iter_dirty_pages(&|off| { | |
dbg_assert!(off >= 0); | |
let src = memory::vga_mem8.offset(off) as *const u32; | |
let dest_offset = off / 4 - svga_dest_offset as isize; | |
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32; | |
let end = if dest_offset < 0 { | |
0 | |
} | |
else { | |
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); | |
let dword = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFFFF } else { dword }; | |
dbg_assert!(dest_offset + i < dest_buffer.len() as isize); | |
*dest.offset(i) = dword << 16 | dword >> 16 & 0xFF | dword & 0xFF00 | 0xFF00_0000; | |
} | |
}), | |
24 => iter_dirty_pages(&|off| { | |
dbg_assert!(off >= 0 && off < memory::vga_memory_size as isize); | |
let off = off - off % 3; | |
let src = memory::vga_mem8.offset(off); | |
let dest_offset = off / 3 - svga_dest_offset as isize; | |
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32; | |
let end = if dest_offset < 0 { | |
0 | |
} | |
else { | |
isize::min(4096 / 3 + 1, dest_buffer.len() as isize - dest_offset) | |
}; | |
for i in 0..end { | |
let dword = ptr::read_unaligned(src.offset(3 * i) as *const u32); | |
let dword = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFFFF } else { dword }; | |
dbg_assert!(dest_offset + i < dest_buffer.len() as isize); | |
*dest.offset(i) = dword << 16 | dword >> 16 & 0xFF | dword & 0xFF00 | 0xFF00_0000; | |
} | |
}), | |
16 => iter_dirty_pages(&|off| { | |
dbg_assert!(off >= 0 && off + 2048 < memory::vga_memory_size as isize); | |
let src = memory::vga_mem8.offset(off) as *const u16; | |
let dest_offset = off / 2 - svga_dest_offset as isize; | |
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32; | |
let end = if dest_offset < 0 { | |
0 | |
} | |
else { | |
isize::min(2048, dest_buffer.len() as isize - dest_offset) | |
}; | |
for i in 0..end { | |
dbg_assert!(off + i < memory::vga_memory_size as isize); | |
let word = *src.offset(i); | |
let word = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFF } else { word }; | |
let r = (word & 0x1F) * 0xFF / 0x1F; | |
let g = (word >> 5 & 0x3F) * 0xFF / 0x3F; | |
let b = (word >> 11) * 0xFF / 0x1F; | |
dbg_assert!(dest_offset + i < dest_buffer.len() as isize); | |
*dest.offset(i) = (r as u32) << 16 | (g as u32) << 8 | b as u32 | 0xFF00_0000; | |
} | |
}), | |
15 => iter_dirty_pages(&|off| { | |
dbg_assert!(off >= 0 && off + 2048 < memory::vga_memory_size as isize); | |
let src = memory::vga_mem8.offset(off) as *const u16; | |
let dest_offset = off / 2 - svga_dest_offset as isize; | |
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32; | |
let end = if dest_offset < 0 { | |
0 | |
} | |
else { | |
isize::min(2048, dest_buffer.len() as isize - dest_offset) | |
}; | |
for i in 0..end { | |
dbg_assert!(off + i < memory::vga_memory_size as isize); | |
let word = *src.offset(i); | |
let word = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFF } else { word }; | |
let r = (word & 0x1F) * 0xFF / 0x1F; | |
let g = (word >> 5 & 0x1F) * 0xFF / 0x1F; | |
let b = (word >> 10 & 0x1F) * 0xFF / 0x1F; | |
dbg_assert!(dest_offset + i < dest_buffer.len() as isize); | |
*dest.offset(i) = (r as u32) << 16 | (g as u32) << 8 | b as u32 | 0xFF00_0000; | |
} | |
}), | |
_ => { | |
dbg_log!("{}", bpp); | |
dbg_assert!(false, "Unsupported bpp"); | |
}, | |
} | |
//if cfg!(debug_assertions) { | |
// let mut pages = 0; | |
// for &word in dirty_bitmap.iter() { | |
// pages += word.count_ones(); | |
// } | |
// dbg_log!( | |
// "fill offset={:x} bpp={} pages={}", | |
// svga_dest_offset, | |
// bpp, | |
// pages, | |
// ); | |
//} | |
for v in dirty_bitmap.iter_mut() { | |
*v = 0 | |
} | |
} | |