v86 / src /rust /cpu /vga.rs
peterpeter8585's picture
Upload 553 files
8df6da4 verified
#![allow(non_upper_case_globals)]
#![allow(static_mut_refs)]
// 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;
#[no_mangle]
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)
}
#[no_mangle]
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;
}
}
#[no_mangle]
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
}
}