Spaces:
Runtime error
Runtime error
File size: 6,623 Bytes
8df6da4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
#![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
}
}
|