From 440006c9c4fb03b3fe17b8b30273028c16eec1ad Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sun, 27 Nov 2022 23:10:03 +0300 Subject: [PATCH 01/32] Initial commit --- Cargo.lock | 26 ++ applications/porthole/Cargo.toml | 63 +++ applications/porthole/src/lib.rs | 713 +++++++++++++++++++++++++++++++ 3 files changed, 802 insertions(+) create mode 100644 applications/porthole/Cargo.toml create mode 100644 applications/porthole/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 52d2612cda..f90960b990 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2634,6 +2634,32 @@ dependencies = [ name = "port_io" version = "0.2.1" +[[package]] +name = "porthole" +version = "0.1.0" +dependencies = [ + "core2", + "device_manager", + "event_types", + "font", + "hpet", + "keycodes_ascii", + "log", + "memory", + "memory_structs", + "mouse", + "mouse_data", + "mpmc", + "multicore_bringup", + "page_attribute_table", + "scheduler", + "spawn", + "spin 0.9.4", + "stdio", + "task", + "zerocopy", +] + [[package]] name = "ppv-lite86" version = "0.2.17" diff --git a/applications/porthole/Cargo.toml b/applications/porthole/Cargo.toml new file mode 100644 index 0000000000..e5c0c07e77 --- /dev/null +++ b/applications/porthole/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "porthole" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +mpmc = "0.1.6" +spin = "0.9.0" +zerocopy = "0.5.0" +core2 = { version = "0.4.0", default-features = false, features = ["alloc", "nightly"] } + +[dependencies.log] +version = "0.4.8" + +[dependencies.memory] +path = "../../kernel/memory" + +[dependencies.memory_structs] +path = "../../kernel/memory_structs" + +[target.'cfg(target_arch = "x86_64")'.dependencies] +page_attribute_table = { path = "../../kernel/page_attribute_table" } + +[dependencies.multicore_bringup] +path = "../../kernel/multicore_bringup" + +[dependencies.spawn] +path = "../../kernel/spawn" + +[dependencies.task] +path = "../../kernel/task" + +[dependencies.scheduler] +path = "../../kernel/scheduler" + +[dependencies.stdio] +path = "../../libs/stdio" + +[dependencies.hpet] +path = "../../kernel/acpi/hpet" + +[dependencies.mouse_data] +path = "../../libs/mouse_data" + +[dependencies.mouse] +path = "../../kernel/mouse" + +[dependencies.event_types] +path = "../../kernel/event_types" + +[dependencies.keycodes_ascii] +path = "../../libs/keycodes_ascii" + +[dependencies.font] +path = "../../kernel/font" + +[dependencies.device_manager] +path = "../../kernel/device_manager" + +[lib] +crate-type = ["rlib"] \ No newline at end of file diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs new file mode 100644 index 0000000000..e4f1681919 --- /dev/null +++ b/applications/porthole/src/lib.rs @@ -0,0 +1,713 @@ +#![no_std] + +extern crate alloc; +extern crate device_manager; +extern crate hpet; +extern crate memory; +extern crate mouse; +extern crate mouse_data; +extern crate multicore_bringup; +extern crate scheduler; +extern crate spin; +extern crate task; +use alloc::sync::{Arc, Weak}; +use log::{debug, info}; +use spin::{Mutex, MutexGuard, Once}; + +use event_types::{Event, MousePositionEvent}; +use keycodes_ascii::{KeyAction, KeyEvent, Keycode}; +use mpmc::Queue; + +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use font::{CHARACTER_HEIGHT, CHARACTER_WIDTH}; +use hpet::get_hpet; +use memory::{BorrowedSliceMappedPages, Mutable, PhysicalAddress, PteFlags, PteFlagsArch}; +use mouse_data::MouseEvent; +use task::{ExitValue, JoinableTaskRef, KillReason}; +pub static WINDOW_MANAGER: Once> = Once::new(); + +static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { + const T: u32 = 0xFF0000; + const C: u32 = 0x000000; // Cursor + const B: u32 = 0xFFFFFF; // Border + [ + [B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, T, T], + [T, B, C, C, C, C, C, C, C, C, C, C, C, C, B, T, T, T], + [T, T, B, C, C, C, C, C, C, C, C, C, C, B, T, T, T, T], + [T, T, T, B, C, C, C, C, C, C, C, C, B, T, T, T, T, T], + [T, T, T, T, B, C, C, C, C, C, C, C, C, B, B, T, T, T], + [T, T, T, T, T, B, C, C, C, C, C, C, C, C, C, B, B, T], + [T, T, T, T, T, T, B, C, C, C, C, B, B, C, C, C, C, B], + [T, T, T, T, T, T, T, B, C, C, B, T, T, B, B, C, B, T], + [T, T, T, T, T, T, T, T, B, C, B, T, T, T, T, B, B, T], + [T, T, T, T, T, T, T, T, T, B, B, T, T, T, T, T, T, T], + [T, T, T, T, T, T, T, T, T, T, B, T, T, T, T, T, T, T], + ] +}; + +pub struct App { + window: Arc>, + text: TextDisplay, +} + +impl App { + pub fn new(window: Arc>, text: TextDisplay) -> Self { + Self { window, text } + } + pub fn draw(&mut self) { + self.window.lock().draw_rectangle(0x111FFF); + self.text.print_string("slie", &mut self.window.lock()); + } +} + +pub struct TextDisplay { + width: usize, + height: usize, + next_col: usize, + next_line: usize, + text: String, + fg_color: u32, + bg_color: u32, +} + +impl TextDisplay { + pub fn new( + width: usize, + height: usize, + next_col: usize, + next_line: usize, + text: String, + fg_color: u32, + bg_color: u32, + ) -> Self { + Self { + width, + height, + next_col, + next_line, + text, + fg_color, + bg_color, + } + } + + pub fn print_string(&mut self, slice: &str, window: &mut MutexGuard) { + let rect = window.rect; + let buffer_width = rect.width / CHARACTER_WIDTH; + let buffer_height = rect.height / CHARACTER_HEIGHT; + let (x, y) = (rect.x, rect.y); + + let some_slice = slice.as_bytes(); + + self.print_ascii_character(some_slice, window); + } + + // TODO: Try to simplify this + pub fn print_ascii_character(&mut self, slice: &[u8], window: &mut MutexGuard) { + let rect = window.rect; + let relative_x = rect.x; + let relative_y = rect.y; + let start_x = relative_x + (self.next_col as isize * CHARACTER_WIDTH as isize); + let start_y = relative_y + (self.next_line as isize * CHARACTER_HEIGHT as isize); + + let buffer_width = rect.width; + let buffer_height = rect.height; + + let off_set_x = 0; + let off_set_y = 0; + + let mut j = off_set_x; + let mut i = off_set_y; + let mut z = 0; + let mut index_j = j; + loop { + let x = start_x + j as isize; + let y = start_y + i as isize; + if j % CHARACTER_WIDTH == 0 { + index_j = 0; + } + let color = if index_j >= 1 { + let index = index_j - 1; + let char_font = font::FONT_BASIC[slice[z] as usize][i]; + index_j += 1; + if self.get_bit(char_font, index) != 0 { + self.fg_color + } else { + self.bg_color + } + } else { + index_j += 1; + self.bg_color + }; + window.draw_relative(x, y, color); + + j += 1; + if j == CHARACTER_WIDTH + || j % CHARACTER_WIDTH == 0 + || start_x + j as isize == buffer_width as isize + { + if slice.len() >= 1 && z < slice.len() - 1 { + z += 1; + } + + if j >= CHARACTER_WIDTH * slice.len() && j % (CHARACTER_WIDTH * slice.len()) == 0 { + i += 1; + z = 0; + j = off_set_x; + } + + if i == CHARACTER_HEIGHT || start_y + i as isize == buffer_height as isize { + break; + } + } + } + } + fn get_bit(&self, char_font: u8, i: usize) -> u8 { + char_font & (0x80 >> i) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Rect { + pub width: usize, + pub height: usize, + pub x: isize, + pub y: isize, +} + +impl Rect { + fn new(width: usize, height: usize, x: isize, y: isize) -> Rect { + Rect { + width, + height, + x, + y, + } + } + + fn start_x(&self) -> isize { + self.x + } + + fn end_x(&self) -> isize { + self.x + self.width as isize + } + + fn start_y(&self) -> isize { + self.y + } + + fn end_y(&self) -> isize { + self.y + self.height as isize + } + + fn detect_collision(&self, other: &Rect) -> bool { + if self.x < other.end_x() + && self.end_x() > other.x + && self.y < other.end_y() + && self.end_y() > other.y + { + true + } else { + false + } + } +} + +pub struct FrameBuffer { + width: usize, + height: usize, + buffer: BorrowedSliceMappedPages, +} +impl FrameBuffer { + fn init_front_buffer() -> Result { + let graphic_info = multicore_bringup::GRAPHIC_INFO.lock(); + if graphic_info.physical_address() == 0 { + return Err("wrong physical address for porthole"); + } + let vesa_display_phys_start = + PhysicalAddress::new(graphic_info.physical_address() as usize).ok_or("Invalid address"); + let buffer_width = graphic_info.width() as usize; + let buffer_height = graphic_info.height() as usize; + + let framebuffer = FrameBuffer::new( + buffer_width, + buffer_height, + Some(vesa_display_phys_start.unwrap()), + )?; + Ok(framebuffer) + } + + pub fn new( + width: usize, + height: usize, + physical_address: Option, + ) -> Result { + let kernel_mmi_ref = + memory::get_kernel_mmi_ref().ok_or("KERNEL_MMI was not yet initialized!")?; + let size = width * height * core::mem::size_of::(); + let pages = memory::allocate_pages_by_bytes(size) + .ok_or("could not allocate pages for a new framebuffer")?; + + let mapped_framebuffer = if let Some(address) = physical_address { + // For best performance, we map the real physical framebuffer memory + // as write-combining using the PAT (on x86 only). + // If PAT isn't available, fall back to disabling caching altogether. + let mut flags: PteFlagsArch = PteFlags::new().valid(true).writable(true).into(); + + #[cfg(target_arch = "x86_64")] + { + let use_pat = page_attribute_table::init().is_ok(); + if use_pat { + flags = flags.pat_index( + page_attribute_table::MemoryCachingType::WriteCombining.pat_slot_index(), + ); + info!("Using PAT write-combining mapping for real physical framebuffer memory"); + } else { + flags = flags.device_memory(true); + info!("Falling back to cache-disable mapping for real physical framebuffer memory"); + } + } + #[cfg(not(target_arch = "x86_64"))] + { + flags = flags.device_memory(true); + } + + let frames = memory::allocate_frames_by_bytes_at(address, size) + .map_err(|_e| "Couldn't allocate frames for the final framebuffer")?; + let fb_mp = kernel_mmi_ref + .lock() + .page_table + .map_allocated_pages_to(pages, frames, flags)?; + debug!("Mapped real physical framebuffer: {fb_mp:?}"); + fb_mp + } else { + kernel_mmi_ref + .lock() + .page_table + .map_allocated_pages(pages, PteFlags::new().valid(true).writable(true))? + }; + + Ok(FrameBuffer { + width, + height, + buffer: mapped_framebuffer + .into_borrowed_slice_mut(0, width * height) + .map_err(|(_mp, s)| s)?, + }) + } + + pub fn draw_something(&mut self, x: isize, y: isize, col: u32) { + if x > 0 && x < self.width as isize && y > 0 && y < self.height as isize { + self.buffer[(self.width * y as usize) + x as usize] = col; + } + } + + pub fn get_pixel(&self, x: isize, y: isize) -> u32 { + self.buffer[(self.width * y as usize) + x as usize] + } + + pub fn draw_rectangle(&mut self, rect: &Rect) { + for y in rect.start_y()..rect.end_y() { + for x in rect.start_x()..rect.end_x() { + if x > 0 && x < self.width as isize && y > 0 && y < self.height as isize { + self.draw_something(x, y, 0xF123999); + } + } + } + } + + pub fn blank(&mut self) { + for pixel in self.buffer.iter_mut() { + *pixel = 0x000000; + } + } + + pub fn blank_rect(&mut self, rect: &Rect) { + for y in rect.y..rect.end_y() { + for x in rect.x..rect.end_x() { + self.draw_something(x, y, 0x000000); + } + } + } + + fn copy_window_only(&mut self, window: &MutexGuard) { + for y in 0..window.rect.height { + for x in 0..window.rect.width { + let pixel = window.frame_buffer.get_pixel(x as isize, y as isize); + let x = x as isize; + let y = y as isize; + if (x + window.rect.x) > 0 + && (window.rect.x + x) < self.width as isize + && (y + window.rect.y) > 0 + && (y + window.rect.y) < self.height as isize + { + self.draw_something( + x as isize + window.rect.x, + y as isize + window.rect.y, + pixel, + ); + } + } + } + } +} + +pub fn main(_args: Vec) -> isize { + let mouse_consumer = Queue::with_capacity(100); + let mouse_producer = mouse_consumer.clone(); + let key_consumer = Queue::with_capacity(100); + let key_producer = mouse_consumer.clone(); + WindowManager::init(); + device_manager::init(key_producer, mouse_producer).unwrap(); + + let _task_ref = match spawn::new_task_builder(port_loop, (mouse_consumer, key_consumer)) + .name("port_loop".to_string()) + .spawn() + { + Ok(task_ref) => task_ref, + Err(err) => { + log::error!("{}", err); + log::error!("failed to spawn shell"); + return -1; + } + }; + + task::get_my_current_task().unwrap().block().unwrap(); + scheduler::schedule(); + + loop { + log::warn!("BUG: blocked shell task was scheduled in unexpectedly"); + } +} + +pub struct WindowManager { + windows: Vec>>, + v_framebuffer: FrameBuffer, + p_framebuffer: FrameBuffer, + pub mouse: Rect, +} + +impl WindowManager { + fn init() { + let p_framebuffer = FrameBuffer::init_front_buffer().unwrap(); + let v_framebuffer = + FrameBuffer::new(p_framebuffer.width, p_framebuffer.height, None).unwrap(); + let mouse = Rect::new(11, 18, 200, 200); + + let window_manager = WindowManager { + windows: Vec::new(), + v_framebuffer, + p_framebuffer, + mouse, + }; + WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); + } + + fn new_window(dimensions: &Rect) -> Arc> { + let mut manager = WINDOW_MANAGER.get().unwrap().lock(); + + let buffer_width = manager.p_framebuffer.width as usize; + let buffer_height = manager.p_framebuffer.height as usize; + + let window = Window::new( + *dimensions, + FrameBuffer::new(dimensions.width, dimensions.height, None).unwrap(), + ); + let arc_window = Arc::new(Mutex::new(window)); + manager.windows.push(Arc::downgrade(&arc_window.clone())); + arc_window + } + + fn draw_windows(&mut self) { + for window in self.windows.iter() { + self.v_framebuffer + .copy_window_only(&window.upgrade().unwrap().lock()); + } + for window in self.windows.iter() { + window.upgrade().unwrap().lock().blank(); + } + } + + fn draw_mouse(&mut self) { + let mouse = self.mouse; + for y in mouse.y..mouse.y + mouse.height as isize { + for x in mouse.x..mouse.x + mouse.width as isize { + let color = MOUSE_POINTER_IMAGE[(x - mouse.x) as usize][(y - mouse.y) as usize]; + if color != 0xFF0000 { + self.v_framebuffer.draw_something(x, y, color); + } + } + } + } + + fn update(&mut self) { + self.v_framebuffer.blank(); + self.draw_windows(); + self.draw_mouse(); + } + + fn update_mouse_position(&mut self, x: isize, y: isize) { + let mut new_pos_x = self.mouse.x + x; + let mut new_pos_y = self.mouse.y - y; + + // handle left + if (new_pos_x + (self.mouse.width as isize / 2)) < 0 { + new_pos_x = self.mouse.x; + } + // handle right + if new_pos_x + (self.mouse.width as isize / 2) > self.v_framebuffer.width as isize { + new_pos_x = self.mouse.x; + } + + // handle top + if new_pos_y < 0 { + new_pos_y = self.mouse.y; + } + + // handle bottom + if new_pos_y + (self.mouse.height as isize / 2) > self.v_framebuffer.height as isize { + new_pos_y = self.mouse.y; + } + + self.mouse.x = new_pos_x; + self.mouse.y = new_pos_y; + } + + fn drag_windows(&mut self, x: isize, y: isize, mouse_event: &MouseEvent) { + if mouse_event.buttons.left() { + for window in self.windows.iter_mut() { + if window + .upgrade() + .unwrap() + .lock() + .rect + .detect_collision(&Rect::new( + self.mouse.width, + self.mouse.height, + self.mouse.x, + self.mouse.y, + )) + { + let window_rect = window.upgrade().unwrap().lock().rect; + let mut new_pos_x = window_rect.x + x; + let mut new_pos_y = window_rect.y - y; + + //handle left + if (new_pos_x + (window_rect.width as isize - 20)) < 0 { + new_pos_x = window_rect.x; + } + + //handle right + if (new_pos_x + 20) > self.v_framebuffer.width as isize { + new_pos_x = window_rect.x; + } + + //handle top + if new_pos_y <= 0 { + new_pos_y = window_rect.y; + } + + if new_pos_y + 20 > self.v_framebuffer.height as isize { + new_pos_y = window_rect.y; + } + + window.upgrade().unwrap().lock().rect.x = new_pos_x; + window.upgrade().unwrap().lock().rect.y = new_pos_y; + } + } + } else if mouse_event.buttons.right() { + let pos_x = self.mouse.x; + let pos_y = self.mouse.y; + + for window in self.windows.iter_mut() { + if window + .upgrade() + .unwrap() + .lock() + .rect + .detect_collision(&Rect::new( + self.mouse.width, + self.mouse.height, + self.mouse.x, + self.mouse.y, + )) + { + window.upgrade().unwrap().lock().rect.width += x as usize; + window.upgrade().unwrap().lock().rect.height -= y as usize; + window.upgrade().unwrap().lock().resized = true; + } + } + } + } + + #[inline] + fn render(&mut self) { + self.p_framebuffer + .buffer + .copy_from_slice(&self.v_framebuffer.buffer); + } +} + +pub struct Window { + rect: Rect, + pub frame_buffer: FrameBuffer, + resized: bool, +} + +impl Window { + fn new(rect: Rect, frame_buffer: FrameBuffer) -> Window { + Window { + rect, + frame_buffer, + resized: false, + } + } + + pub fn blank(&mut self) { + for pixel in self.frame_buffer.buffer.iter_mut() { + *pixel = 0x000000; + } + } + + pub fn blank_with_color(&mut self, rect: &Rect, col: u32) { + let start_x = rect.x; + let end_x = start_x + rect.width as isize; + + let start_y = rect.y; + let end_y = start_y + rect.height as isize; + + for y in rect.x..rect.height as isize { + for x in rect.y..rect.width as isize { + self.draw_something(x as isize, y as isize, col); + } + } + } + + pub fn draw_absolute(&mut self, x: isize, y: isize, col: u32) { + if x <= self.rect.width as isize && y <= self.rect.height as isize { + self.draw_something(x, y, col); + } + } + + pub fn draw_relative(&mut self, x: isize, y: isize, col: u32) { + let x = x - self.rect.x; + let y = y - self.rect.y; + + self.draw_something(x, y, col); + } + + // TODO: Change the name + fn draw_something(&mut self, x: isize, y: isize, col: u32) { + if x >= 0 && x <= self.rect.width as isize && y >= 0 && y <= self.rect.height as isize { + self.frame_buffer.buffer[(self.frame_buffer.width * y as usize) + x as usize] = col; + } + } + + pub fn draw_rectangle(&mut self, col: u32) { + // TODO: This should be somewhere else and it should be a function + if self.resized { + self.resize_framebuffer(); + self.resized = false; + } + for y in 0..self.rect.height { + for x in 0..self.rect.width { + self.draw_something(x as isize, y as isize, col); + } + } + } + pub fn set_position(&mut self, x: isize, y: isize) { + self.rect.x = x; + self.rect.y = y; + } + + fn resize_framebuffer(&mut self) { + self.frame_buffer = FrameBuffer::new(self.rect.width, self.rect.height, None).unwrap(); + } +} + +fn port_loop( + (key_consumer, mouse_consumer): (Queue, Queue), +) -> Result<(), &'static str> { + let window_manager = WINDOW_MANAGER.get().unwrap(); + let window_2 = WindowManager::new_window(&Rect::new(400, 400, 0, 0)); + let text = TextDisplay { + width: 400, + height: 400, + next_col: 1, + next_line: 1, + text: "asdasd".to_string(), + fg_color: 0xFFFFFF, + bg_color: 0x0F0FFF, + }; + let mut app = App::new(window_2, text); + let hpet = get_hpet(); + let mut start = hpet + .as_ref() + .ok_or("couldn't get HPET timer")? + .get_counter(); + let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; + + loop { + let mut end = hpet + .as_ref() + .ok_or("couldn't get HPET timer")? + .get_counter(); + let mut diff = (end - start) * hpet_freq / 1_000_000_000_00; + let event_opt = key_consumer + .pop() + .or_else(|| mouse_consumer.pop()) + .or_else(|| { + scheduler::schedule(); + None + }); + + if let Some(event) = event_opt { + match event { + Event::MouseMovementEvent(ref mouse_event) => { + let movement = &mouse_event.movement; + let mut x = (movement.x_movement as i8) as isize; + let mut y = (movement.y_movement as i8) as isize; + while let Some(next_event) = mouse_consumer.pop() { + match next_event { + Event::MouseMovementEvent(ref next_mouse_event) => { + if next_mouse_event.movement.scroll_movement + == mouse_event.movement.scroll_movement + && next_mouse_event.buttons.left() == mouse_event.buttons.left() + && next_mouse_event.buttons.right() + == mouse_event.buttons.right() + && next_mouse_event.buttons.fourth() + == mouse_event.buttons.fourth() + && next_mouse_event.buttons.fifth() + == mouse_event.buttons.fifth() + { + x += (next_mouse_event.movement.x_movement as i8) as isize; + y += (next_mouse_event.movement.y_movement as i8) as isize; + } + } + + _ => { + break; + } + } + } + if x != 0 || y != 0 { + window_manager.lock().update_mouse_position(x, y); + window_manager.lock().drag_windows(x, y, &mouse_event); + } + } + _ => (), + } + } + + if diff >= 0 { + app.draw(); + window_manager.lock().update(); + window_manager.lock().render(); + + start = hpet.as_ref().unwrap().get_counter(); + } + } + Ok(()) +} From cdffd0b42024351896a761d843de954895f35cca Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 14 Dec 2022 15:56:20 +0300 Subject: [PATCH 02/32] use is_supported --- applications/porthole/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index e4f1681919..6aba7f9dd9 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -258,8 +258,7 @@ impl FrameBuffer { #[cfg(target_arch = "x86_64")] { - let use_pat = page_attribute_table::init().is_ok(); - if use_pat { + if page_attribute_table::is_supported() { flags = flags.pat_index( page_attribute_table::MemoryCachingType::WriteCombining.pat_slot_index(), ); From c27911d92b169cabf7b011d9b8dd44fc555b1d32 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 19 Dec 2022 20:32:35 +0300 Subject: [PATCH 03/32] z order, remove most of bounds check --- applications/porthole/src/lib.rs | 113 +++++++++++++++++-------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 6aba7f9dd9..5c64bcf806 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -14,7 +14,7 @@ use alloc::sync::{Arc, Weak}; use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; -use event_types::{Event, MousePositionEvent}; +use event_types::Event; use keycodes_ascii::{KeyAction, KeyEvent, Keycode}; use mpmc::Queue; @@ -24,7 +24,6 @@ use font::{CHARACTER_HEIGHT, CHARACTER_WIDTH}; use hpet::get_hpet; use memory::{BorrowedSliceMappedPages, Mutable, PhysicalAddress, PteFlags, PteFlagsArch}; use mouse_data::MouseEvent; -use task::{ExitValue, JoinableTaskRef, KillReason}; pub static WINDOW_MANAGER: Once> = Once::new(); static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { @@ -310,9 +309,7 @@ impl FrameBuffer { pub fn draw_rectangle(&mut self, rect: &Rect) { for y in rect.start_y()..rect.end_y() { for x in rect.start_x()..rect.end_x() { - if x > 0 && x < self.width as isize && y > 0 && y < self.height as isize { - self.draw_something(x, y, 0xF123999); - } + self.draw_something(x, y, 0xF123999); } } } @@ -332,20 +329,17 @@ impl FrameBuffer { } fn copy_window_only(&mut self, window: &MutexGuard) { + let mut it = window.frame_buffer.buffer.iter(); for y in 0..window.rect.height { for x in 0..window.rect.width { - let pixel = window.frame_buffer.get_pixel(x as isize, y as isize); let x = x as isize; let y = y as isize; - if (x + window.rect.x) > 0 - && (window.rect.x + x) < self.width as isize - && (y + window.rect.y) > 0 - && (y + window.rect.y) < self.height as isize { self.draw_something( x as isize + window.rect.x, y as isize + window.rect.y, - pixel, + // This is safe because size of Window's framebuffer same as it's width * height + *it.next().unwrap(), ); } } @@ -381,11 +375,20 @@ pub fn main(_args: Vec) -> isize { } } +#[derive(PartialEq, Eq)] +pub enum Holding { + Background, + Nothing, + Window(usize), +} + pub struct WindowManager { windows: Vec>>, + window_rendering_order: Vec, v_framebuffer: FrameBuffer, p_framebuffer: FrameBuffer, pub mouse: Rect, + mouse_holding: Holding, } impl WindowManager { @@ -397,19 +400,20 @@ impl WindowManager { let window_manager = WindowManager { windows: Vec::new(), + window_rendering_order: Vec::new(), v_framebuffer, p_framebuffer, mouse, + mouse_holding: Holding::Nothing, }; WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); } fn new_window(dimensions: &Rect) -> Arc> { let mut manager = WINDOW_MANAGER.get().unwrap().lock(); + let len = manager.windows.len(); - let buffer_width = manager.p_framebuffer.width as usize; - let buffer_height = manager.p_framebuffer.height as usize; - + manager.window_rendering_order.push(len); let window = Window::new( *dimensions, FrameBuffer::new(dimensions.width, dimensions.height, None).unwrap(), @@ -420,9 +424,9 @@ impl WindowManager { } fn draw_windows(&mut self) { - for window in self.windows.iter() { + for order in self.window_rendering_order.iter() { self.v_framebuffer - .copy_window_only(&window.upgrade().unwrap().lock()); + .copy_window_only(&self.windows[*order].upgrade().unwrap().lock()); } for window in self.windows.iter() { window.upgrade().unwrap().lock().blank(); @@ -476,19 +480,36 @@ impl WindowManager { fn drag_windows(&mut self, x: isize, y: isize, mouse_event: &MouseEvent) { if mouse_event.buttons.left() { - for window in self.windows.iter_mut() { - if window - .upgrade() - .unwrap() - .lock() - .rect - .detect_collision(&Rect::new( - self.mouse.width, - self.mouse.height, - self.mouse.x, - self.mouse.y, - )) - { + match self.mouse_holding { + Holding::Background => todo!(), + Holding::Nothing => { + let rendering_o = self.window_rendering_order.clone(); + for &i in rendering_o.iter().rev() { + let window = &mut self.windows[i]; + if window + .upgrade() + .unwrap() + .lock() + .rect + .detect_collision(&self.mouse) + { + if i != *self.window_rendering_order.last().unwrap() { + let wind_index = self + .window_rendering_order + .iter() + .position(|ii| ii == &i) + .unwrap(); + self.window_rendering_order.remove(wind_index); + self.window_rendering_order.push(i); + } + self.mouse_holding = Holding::Window(i); + break; + } + self.mouse_holding = Holding::Nothing; + } + } + Holding::Window(i) => { + let window = &mut self.windows[i]; let window_rect = window.upgrade().unwrap().lock().rect; let mut new_pos_x = window_rect.x + x; let mut new_pos_y = window_rect.y - y; @@ -517,9 +538,6 @@ impl WindowManager { } } } else if mouse_event.buttons.right() { - let pos_x = self.mouse.x; - let pos_y = self.mouse.y; - for window in self.windows.iter_mut() { if window .upgrade() @@ -539,6 +557,9 @@ impl WindowManager { } } } + if !mouse_event.buttons.left() { + self.mouse_holding = Holding::Nothing; + } } #[inline] @@ -571,12 +592,6 @@ impl Window { } pub fn blank_with_color(&mut self, rect: &Rect, col: u32) { - let start_x = rect.x; - let end_x = start_x + rect.width as isize; - - let start_y = rect.y; - let end_y = start_y + rect.height as isize; - for y in rect.x..rect.height as isize { for x in rect.y..rect.width as isize { self.draw_something(x as isize, y as isize, col); @@ -585,9 +600,7 @@ impl Window { } pub fn draw_absolute(&mut self, x: isize, y: isize, col: u32) { - if x <= self.rect.width as isize && y <= self.rect.height as isize { - self.draw_something(x, y, col); - } + self.draw_something(x, y, col); } pub fn draw_relative(&mut self, x: isize, y: isize, col: u32) { @@ -610,10 +623,8 @@ impl Window { self.resize_framebuffer(); self.resized = false; } - for y in 0..self.rect.height { - for x in 0..self.rect.width { - self.draw_something(x as isize, y as isize, col); - } + for pixel in self.frame_buffer.buffer.iter_mut() { + *pixel = col; } } pub fn set_position(&mut self, x: isize, y: isize) { @@ -630,7 +641,8 @@ fn port_loop( (key_consumer, mouse_consumer): (Queue, Queue), ) -> Result<(), &'static str> { let window_manager = WINDOW_MANAGER.get().unwrap(); - let window_2 = WindowManager::new_window(&Rect::new(400, 400, 0, 0)); + let window_3 = WindowManager::new_window(&Rect::new(400, 200, 0, 0)); + let window_2 = WindowManager::new_window(&Rect::new(200, 200, 20, 20)); let text = TextDisplay { width: 400, height: 400, @@ -649,11 +661,11 @@ fn port_loop( let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; loop { - let mut end = hpet + let end = hpet .as_ref() .ok_or("couldn't get HPET timer")? .get_counter(); - let mut diff = (end - start) * hpet_freq / 1_000_000_000_00; + let diff = (end - start) * hpet_freq / 1_000_000_000_000; let event_opt = key_consumer .pop() .or_else(|| mouse_consumer.pop()) @@ -693,14 +705,15 @@ fn port_loop( } if x != 0 || y != 0 { window_manager.lock().update_mouse_position(x, y); - window_manager.lock().drag_windows(x, y, &mouse_event); } + window_manager.lock().drag_windows(x, y, &mouse_event); } _ => (), } } - if diff >= 0 { + if diff >= 1 { + window_3.lock().draw_rectangle(0x194888); app.draw(); window_manager.lock().update(); window_manager.lock().render(); From ec3656ffcf75c668ad0a6516062534e16553c274 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 27 Dec 2022 19:52:02 +0300 Subject: [PATCH 04/32] faster rendering border rendering and window titles --- applications/porthole/src/lib.rs | 485 ++++++++++++++++++++++--------- 1 file changed, 342 insertions(+), 143 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 5c64bcf806..bcf239d8ba 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -10,6 +10,7 @@ extern crate multicore_bringup; extern crate scheduler; extern crate spin; extern crate task; +use alloc::format; use alloc::sync::{Arc, Weak}; use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; @@ -20,11 +21,19 @@ use mpmc::Queue; use alloc::string::{String, ToString}; use alloc::vec::Vec; -use font::{CHARACTER_HEIGHT, CHARACTER_WIDTH}; +use font::{CHARACTER_HEIGHT, CHARACTER_WIDTH, FONT_BASIC}; use hpet::get_hpet; use memory::{BorrowedSliceMappedPages, Mutable, PhysicalAddress, PteFlags, PteFlagsArch}; use mouse_data::MouseEvent; pub static WINDOW_MANAGER: Once> = Once::new(); +static TITLE_BAR_HEIGHT: usize = 20; +static SCREEN_WIDTH: usize = 1024; +static SCREEN_HEIGHT: usize = 768; + +// TODO: Create an abstraction for COLOR +static DEFAULT_BORDER_COLOR: u32 = 0x141414; +static DEFAULT_TEXT_COLOR: u32 = 0xFBF1C7; +static DEFAULT_WINDOW_COLOR: u32 = 0x3C3836; static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { const T: u32 = 0xFF0000; @@ -44,7 +53,6 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { [T, T, T, T, T, T, T, T, T, T, B, T, T, T, T, T, T, T], ] }; - pub struct App { window: Arc>, text: TextDisplay, @@ -55,11 +63,105 @@ impl App { Self { window, text } } pub fn draw(&mut self) { - self.window.lock().draw_rectangle(0x111FFF); - self.text.print_string("slie", &mut self.window.lock()); + self.window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); + let rect = self.window.lock().rect; + display_window_title( + &mut self.window.lock(), + DEFAULT_TEXT_COLOR, + DEFAULT_BORDER_COLOR, + ); + print_string( + &mut self.window.lock(), + &Rect::new(rect.width, rect.height, 300, 22), + &self.text.text, + DEFAULT_TEXT_COLOR, + DEFAULT_WINDOW_COLOR, + 0, + 1, + ) + } +} + +pub fn display_window_title(window: &mut MutexGuard, fg_color: u32, bg_color: u32) { + if let Some(title) = window.title.clone() { + let slice = title.as_str(); + let mut border = window.return_title_border(); + let middle = (border.width - (slice.len() * CHARACTER_WIDTH)) / 2; + border.x = middle as isize; + print_string(window, &border, slice, fg_color, bg_color, 0, 0); + } +} + +pub fn print_string( + window: &mut MutexGuard, + rect: &Rect, + slice: &str, + fg_color: u32, + bg_color: u32, + column: usize, + line: usize, +) { + let slice = slice.as_bytes(); + let relative_x = rect.x; + let relative_y = rect.y; + let mut curr_column = column; + let mut curr_line = line; + let start_x = relative_x + (curr_column as isize * CHARACTER_WIDTH as isize); + let start_y = relative_y + (curr_line as isize * CHARACTER_HEIGHT as isize); + let off_set_x = 0; + let off_set_y = 0; + + let mut j = off_set_x; + let mut i = off_set_y; + let mut z = 0; + let mut index_j = j; + loop { + let x = start_x + j as isize; + let y = start_y + i as isize; + if j % CHARACTER_WIDTH == 0 { + index_j = 0; + } + let color = if index_j >= 1 { + let index = index_j - 1; + let char_font = FONT_BASIC[slice[z] as usize][i]; + index_j += 1; + if get_bit(char_font, index) != 0 { + fg_color + } else { + bg_color + } + } else { + index_j += 1; + bg_color + }; + window.draw_unchecked(x, y, color); + + j += 1; + if j == CHARACTER_WIDTH + || j % CHARACTER_WIDTH == 0 + || start_x + j as isize == rect.width as isize + { + if slice.len() >= 1 && z < slice.len() - 1 { + z += 1; + } + + if j >= CHARACTER_WIDTH * slice.len() && j % (CHARACTER_WIDTH * slice.len()) == 0 { + i += 1; + z = 0; + j = off_set_x; + } + + if i == CHARACTER_HEIGHT || start_y + i as isize == rect.height as isize { + break; + } + } } } +fn get_bit(char_font: u8, i: usize) -> u8 { + char_font & (0x80 >> i) +} +// TODO: Implement proper `types` for width height etc pub struct TextDisplay { width: usize, height: usize, @@ -91,79 +193,8 @@ impl TextDisplay { } } - pub fn print_string(&mut self, slice: &str, window: &mut MutexGuard) { - let rect = window.rect; - let buffer_width = rect.width / CHARACTER_WIDTH; - let buffer_height = rect.height / CHARACTER_HEIGHT; - let (x, y) = (rect.x, rect.y); - - let some_slice = slice.as_bytes(); - - self.print_ascii_character(some_slice, window); - } - - // TODO: Try to simplify this - pub fn print_ascii_character(&mut self, slice: &[u8], window: &mut MutexGuard) { - let rect = window.rect; - let relative_x = rect.x; - let relative_y = rect.y; - let start_x = relative_x + (self.next_col as isize * CHARACTER_WIDTH as isize); - let start_y = relative_y + (self.next_line as isize * CHARACTER_HEIGHT as isize); - - let buffer_width = rect.width; - let buffer_height = rect.height; - - let off_set_x = 0; - let off_set_y = 0; - - let mut j = off_set_x; - let mut i = off_set_y; - let mut z = 0; - let mut index_j = j; - loop { - let x = start_x + j as isize; - let y = start_y + i as isize; - if j % CHARACTER_WIDTH == 0 { - index_j = 0; - } - let color = if index_j >= 1 { - let index = index_j - 1; - let char_font = font::FONT_BASIC[slice[z] as usize][i]; - index_j += 1; - if self.get_bit(char_font, index) != 0 { - self.fg_color - } else { - self.bg_color - } - } else { - index_j += 1; - self.bg_color - }; - window.draw_relative(x, y, color); - - j += 1; - if j == CHARACTER_WIDTH - || j % CHARACTER_WIDTH == 0 - || start_x + j as isize == buffer_width as isize - { - if slice.len() >= 1 && z < slice.len() - 1 { - z += 1; - } - - if j >= CHARACTER_WIDTH * slice.len() && j % (CHARACTER_WIDTH * slice.len()) == 0 { - i += 1; - z = 0; - j = off_set_x; - } - - if i == CHARACTER_HEIGHT || start_y + i as isize == buffer_height as isize { - break; - } - } - } - } - fn get_bit(&self, char_font: u8, i: usize) -> u8 { - char_font & (0x80 >> i) + pub fn append_char(&mut self, char: char) { + self.text.push(char); } } @@ -212,6 +243,27 @@ impl Rect { false } } + + pub fn on_screen_window(&self, screen_width: isize, screen_height: isize) -> Rect { + let mut start_x = self.x; + let start_y = self.y; + let mut end_x = self.width as isize; + let mut end_y = self.height as isize; + if self.x < 0 { + start_x = 0; + end_x = self.x + self.width as isize; + } else if self.x + self.width as isize > screen_width as isize { + start_x = self.x; + let gap = (self.x + self.width as isize) - screen_width as isize; + end_x = self.width as isize - gap; + } + if self.y + self.height as isize > screen_height { + let gap = (self.y + self.height as isize) - screen_height; + end_y = self.height as isize - gap; + } + let f = Rect::new(end_x as usize, end_y as usize, start_x, start_y); + f + } } pub struct FrameBuffer { @@ -257,7 +309,8 @@ impl FrameBuffer { #[cfg(target_arch = "x86_64")] { - if page_attribute_table::is_supported() { + let use_pat = page_attribute_table::init().is_ok(); + if use_pat { flags = flags.pat_index( page_attribute_table::MemoryCachingType::WriteCombining.pat_slot_index(), ); @@ -302,47 +355,92 @@ impl FrameBuffer { } } - pub fn get_pixel(&self, x: isize, y: isize) -> u32 { - self.buffer[(self.width * y as usize) + x as usize] + pub fn blank(&mut self) { + for pixel in self.buffer.iter_mut() { + *pixel = 0x000000; + } } - pub fn draw_rectangle(&mut self, rect: &Rect) { - for y in rect.start_y()..rect.end_y() { - for x in rect.start_x()..rect.end_x() { - self.draw_something(x, y, 0xF123999); - } - } + fn index(&self, x: isize, y: isize) -> usize { + let index = (self.width as isize * y) + x; + index as usize } - pub fn blank(&mut self) { - for pixel in self.buffer.iter_mut() { - *pixel = 0x000000; + fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { + let window_screen = window.on_screen_window(self.width as isize, self.height as isize); + + let w_it = window.return_framebuffer_iterator(); + let f = self.indexer(window_screen); + + for (w_color, pixel) in w_it.zip(f) { + *pixel = *w_color; } } - pub fn blank_rect(&mut self, rect: &Rect) { - for y in rect.y..rect.end_y() { - for x in rect.x..rect.end_x() { - self.draw_something(x, y, 0x000000); + fn copy_window_only(&mut self, window: &mut MutexGuard) { + /* + (ouz-a):I feel like(because at this point it's very hard to benchmark performance as our resolution is small) + this version is faster than iterator version below, could be improved with a lot of work, but still would + require `unsafe`. + + let bounding_box = window.on_screen_window(self.width as isize, self.height as isize); + for y in 0..bounding_box.height { + let x = 0; + let y = y as isize; + let real_x = x + bounding_box.x; + let real_y = y + bounding_box.y; + let index = self.index(real_x, real_y); + let index_end = index + bounding_box.width; + let color_index = window.frame_buffer.index(x, y); + let color_index_end = color_index + bounding_box.width; + unsafe { + let color = window.frame_buffer.buffer.get_unchecked(color_index..color_index_end); + let buffer = self.buffer.get_unchecked_mut(index..index_end); + buffer.copy_from_slice(&color); } } + */ + + // (ouz-a):I like this version better, it's easy to read very flexible and could be simplfied with little more work + // not really sure about how to improve it's performance maybe we could use chunks and then copy slices but + // or we could + self.copy_window_from_iterators(window); } - fn copy_window_only(&mut self, window: &MutexGuard) { - let mut it = window.frame_buffer.buffer.iter(); - for y in 0..window.rect.height { - for x in 0..window.rect.width { - let x = x as isize; - let y = y as isize; - { - self.draw_something( - x as isize + window.rect.x, - y as isize + window.rect.y, - // This is safe because size of Window's framebuffer same as it's width * height - *it.next().unwrap(), - ); + fn indexer(&mut self, rect: Rect) -> impl Iterator { + let width = self.width; + let x = rect.x; + let mut y = rect.y; + let starter = ((width as isize * y) + x) as usize; + let mut keeper = starter; + let buffer = self + .buffer + .iter_mut() + .enumerate() + .filter(move |(size, _)| { + if y >= rect.height as isize + rect.y as isize { + return false; } - } + if *size > starter && size % (keeper + rect.width) == 0 { + y += 1; + keeper = ((width as isize * y) + x) as usize; + } + if size >= &keeper { + true + } else { + false + } + }) + .map(|(_, b)| b); + buffer + } + // TODO: clear api conflict between window and framebuffer, either name them better or + // make it clear which function belongs to which. + fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { + unsafe { + let index = (self.width * y as usize) + x as usize; + let pixel = self.buffer.get_unchecked_mut(index); + *pixel = col; } } } @@ -409,7 +507,7 @@ impl WindowManager { WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); } - fn new_window(dimensions: &Rect) -> Arc> { + fn new_window(dimensions: &Rect, title: Option) -> Arc> { let mut manager = WINDOW_MANAGER.get().unwrap().lock(); let len = manager.windows.len(); @@ -417,6 +515,7 @@ impl WindowManager { let window = Window::new( *dimensions, FrameBuffer::new(dimensions.width, dimensions.height, None).unwrap(), + title, ); let arc_window = Arc::new(Mutex::new(window)); manager.windows.push(Arc::downgrade(&arc_window.clone())); @@ -426,7 +525,7 @@ impl WindowManager { fn draw_windows(&mut self) { for order in self.window_rendering_order.iter() { self.v_framebuffer - .copy_window_only(&self.windows[*order].upgrade().unwrap().lock()); + .copy_window_only(&mut self.windows[*order].upgrade().unwrap().lock()); } for window in self.windows.iter() { window.upgrade().unwrap().lock().blank(); @@ -434,12 +533,16 @@ impl WindowManager { } fn draw_mouse(&mut self) { - let mouse = self.mouse; - for y in mouse.y..mouse.y + mouse.height as isize { - for x in mouse.x..mouse.x + mouse.width as isize { - let color = MOUSE_POINTER_IMAGE[(x - mouse.x) as usize][(y - mouse.y) as usize]; + let bounding_box = self.mouse.on_screen_window( + self.v_framebuffer.width as isize, + self.v_framebuffer.height as isize, + ); + for y in bounding_box.y..bounding_box.y + bounding_box.height as isize { + for x in bounding_box.x..bounding_box.x + bounding_box.width as isize { + let color = MOUSE_POINTER_IMAGE[(x - bounding_box.x) as usize] + [(y - bounding_box.y) as usize]; if color != 0xFF0000 { - self.v_framebuffer.draw_something(x, y, color); + self.v_framebuffer.draw_unchecked(x, y, color); } } } @@ -451,6 +554,7 @@ impl WindowManager { self.draw_mouse(); } + // TODO: Remove magic numbers fn update_mouse_position(&mut self, x: isize, y: isize) { let mut new_pos_x = self.mouse.x + x; let mut new_pos_y = self.mouse.y - y; @@ -459,19 +563,24 @@ impl WindowManager { if (new_pos_x + (self.mouse.width as isize / 2)) < 0 { new_pos_x = self.mouse.x; } + + if new_pos_x < 0 { + new_pos_x = 0; + } + // handle right - if new_pos_x + (self.mouse.width as isize / 2) > self.v_framebuffer.width as isize { - new_pos_x = self.mouse.x; + if new_pos_x > (self.v_framebuffer.width) as isize - 3 { + new_pos_x = self.v_framebuffer.width as isize - 3; } // handle top if new_pos_y < 0 { - new_pos_y = self.mouse.y; + new_pos_y = 0; } // handle bottom - if new_pos_y + (self.mouse.height as isize / 2) > self.v_framebuffer.height as isize { - new_pos_y = self.mouse.y; + if new_pos_y > self.v_framebuffer.height as isize - 3 { + new_pos_y = self.v_framebuffer.height as isize - 3; } self.mouse.x = new_pos_x; @@ -483,6 +592,7 @@ impl WindowManager { match self.mouse_holding { Holding::Background => todo!(), Holding::Nothing => { + // This costs nothing let rendering_o = self.window_rendering_order.clone(); for &i in rendering_o.iter().rev() { let window = &mut self.windows[i]; @@ -490,7 +600,7 @@ impl WindowManager { .upgrade() .unwrap() .lock() - .rect + .return_dynamic_border_pos() .detect_collision(&self.mouse) { if i != *self.window_rendering_order.last().unwrap() { @@ -508,6 +618,7 @@ impl WindowManager { self.mouse_holding = Holding::Nothing; } } + // TODO: Fix the bug that allows you to move the window while mouse position is still Holding::Window(i) => { let window = &mut self.windows[i]; let window_rect = window.upgrade().unwrap().lock().rect; @@ -525,7 +636,7 @@ impl WindowManager { } //handle top - if new_pos_y <= 0 { + if new_pos_y < 0 { new_pos_y = window_rect.y; } @@ -570,18 +681,21 @@ impl WindowManager { } } +// TODO: We need to two different coordinate systems, one for window oriented and one for screen oriented tasks pub struct Window { rect: Rect, pub frame_buffer: FrameBuffer, resized: bool, + title: Option, } impl Window { - fn new(rect: Rect, frame_buffer: FrameBuffer) -> Window { + fn new(rect: Rect, frame_buffer: FrameBuffer, title: Option) -> Window { Window { rect, frame_buffer, resized: false, + title, } } @@ -591,32 +705,51 @@ impl Window { } } - pub fn blank_with_color(&mut self, rect: &Rect, col: u32) { - for y in rect.x..rect.height as isize { - for x in rect.y..rect.width as isize { - self.draw_something(x as isize, y as isize, col); - } - } + /// Returns Window's border area width height with default position + pub fn return_title_border(&self) -> Rect { + let border = Rect::new(self.rect.width, TITLE_BAR_HEIGHT, 0, 0); + border } - pub fn draw_absolute(&mut self, x: isize, y: isize, col: u32) { - self.draw_something(x, y, col); + pub fn return_dynamic_border_pos(&self) -> Rect { + let mut rect = self.rect; + rect.height = TITLE_BAR_HEIGHT; + rect } - pub fn draw_relative(&mut self, x: isize, y: isize, col: u32) { - let x = x - self.rect.x; - let y = y - self.rect.y; + // We don't want user to draw on top a border + pub fn return_drawable_area(&self) -> Rect { + let border = self.return_title_border(); + let x = 0; + let y = border.height; + let width = border.width; + let height = self.rect.height - y; + let drawable_area = Rect::new(width, height, x, y as isize); + drawable_area + } - self.draw_something(x, y, col); + pub fn draw_border(&mut self) { + let buffer = self.frame_buffer.indexer(self.return_title_border()); + for pixel in buffer { + *pixel = DEFAULT_BORDER_COLOR; + } } - // TODO: Change the name - fn draw_something(&mut self, x: isize, y: isize, col: u32) { - if x >= 0 && x <= self.rect.width as isize && y >= 0 && y <= self.rect.height as isize { - self.frame_buffer.buffer[(self.frame_buffer.width * y as usize) + x as usize] = col; + // I'm not exactly sure if using `unsafe` is right bet here + // but since we are dealing with arrays/slices most of the time + // we need to only prove they are within bounds once and this let's us safely call `unsafe` + fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { + let x = x; + let y = y; + unsafe { + let index = (self.frame_buffer.width * y as usize) + x as usize; + let pixel = self.frame_buffer.buffer.get_unchecked_mut(index); + *pixel = col; } } + // TODO: add better(line,box..etc) drawing functions + pub fn draw_rectangle(&mut self, col: u32) { // TODO: This should be somewhere else and it should be a function if self.resized { @@ -626,7 +759,9 @@ impl Window { for pixel in self.frame_buffer.buffer.iter_mut() { *pixel = col; } + self.draw_border(); } + pub fn set_position(&mut self, x: isize, y: isize) { self.rect.x = x; self.rect.y = y; @@ -635,14 +770,78 @@ impl Window { fn resize_framebuffer(&mut self) { self.frame_buffer = FrameBuffer::new(self.rect.width, self.rect.height, None).unwrap(); } + + fn return_framebuffer_iterator(&mut self) -> impl Iterator { + if self.bottom_side_out() || self.left_side_out() || self.right_side_out() { + let mut bounding_box = + self.on_screen_window(SCREEN_WIDTH as isize, SCREEN_HEIGHT as isize); + bounding_box.x = 0; + if self.left_side_out() { + bounding_box.x = (self.rect.width - bounding_box.width) as isize; + } + bounding_box.y = 0; + let buffer = self.frame_buffer.indexer(bounding_box); + buffer + } else { + let rect = Rect::new(self.frame_buffer.width, self.frame_buffer.height, 0, 0); + let buffer = self.frame_buffer.indexer(rect); + buffer + } + } + + pub fn left_side_out(&self) -> bool { + if self.rect.x < 0 { + true + } else { + false + } + } + pub fn right_side_out(&self) -> bool { + if (self.rect.x + self.rect.width as isize) > SCREEN_WIDTH as isize { + true + } else { + false + } + } + + pub fn bottom_side_out(&self) -> bool { + if (self.rect.y + self.rect.height as isize) > SCREEN_HEIGHT as isize { + true + } else { + false + } + } + + // TODO: This should be moved to somewhere else + // and renamed + pub fn on_screen_window(&self, screen_width: isize, screen_height: isize) -> Rect { + let mut start_x = self.rect.x; + let start_y = self.rect.y; + let mut end_x = self.rect.width as isize; + let mut end_y = self.rect.height as isize; + if self.rect.x < 0 { + start_x = 0; + end_x = self.rect.x + self.rect.width as isize; + } else if self.rect.x + self.rect.width as isize > screen_width as isize { + start_x = self.rect.x; + let gap = (self.rect.x + self.rect.width as isize) - screen_width as isize; + end_x = self.rect.width as isize - gap; + } + if self.rect.y + self.rect.height as isize > screen_height { + let gap = (self.rect.y + self.rect.height as isize) - screen_height; + end_y = self.rect.height as isize - gap; + } + let f = Rect::new(end_x as usize, end_y as usize, start_x, start_y); + f + } } fn port_loop( (key_consumer, mouse_consumer): (Queue, Queue), ) -> Result<(), &'static str> { let window_manager = WINDOW_MANAGER.get().unwrap(); - let window_3 = WindowManager::new_window(&Rect::new(400, 200, 0, 0)); - let window_2 = WindowManager::new_window(&Rect::new(200, 200, 20, 20)); + let window_3 = WindowManager::new_window(&Rect::new(400, 200, 30, 100), None); + let window_2 = WindowManager::new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic"))); let text = TextDisplay { width: 400, height: 400, @@ -705,16 +904,16 @@ fn port_loop( } if x != 0 || y != 0 { window_manager.lock().update_mouse_position(x, y); + window_manager.lock().drag_windows(x, y, &mouse_event); } - window_manager.lock().drag_windows(x, y, &mouse_event); } _ => (), } } - if diff >= 1 { - window_3.lock().draw_rectangle(0x194888); + if diff >= 0 { app.draw(); + window_3.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); window_manager.lock().update(); window_manager.lock().render(); From 45c0d0f776b0409829690a68be557590585c6c0f Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 28 Dec 2022 15:58:12 +0300 Subject: [PATCH 05/32] different types for virtual and physical buffers --- applications/porthole/src/lib.rs | 256 ++++++++++++++++--------------- 1 file changed, 136 insertions(+), 120 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index bcf239d8ba..41559bce3b 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -266,13 +266,97 @@ impl Rect { } } -pub struct FrameBuffer { +/// FrameBuffer with no actual physical memory mapped, +/// used for Window and WindowManager's backbuffer. +pub struct VirtualFrameBuffer { width: usize, height: usize, buffer: BorrowedSliceMappedPages, } -impl FrameBuffer { - fn init_front_buffer() -> Result { + +impl VirtualFrameBuffer { + pub fn new(width: usize, height: usize) -> Result { + let kernel_mmi_ref = + memory::get_kernel_mmi_ref().ok_or("KERNEL_MMI was not yet initialized!")?; + let size = width * height * core::mem::size_of::(); + let pages = memory::allocate_pages_by_bytes(size) + .ok_or("could not allocate pages for a new framebuffer")?; + let mapped_buffer = kernel_mmi_ref + .lock() + .page_table + .map_allocated_pages(pages, PteFlags::new().valid(true).writable(true))?; + Ok(VirtualFrameBuffer { + width, + height, + buffer: mapped_buffer + .into_borrowed_slice_mut(0, width * height) + .map_err(|(_mp, s)| s)?, + }) + } + + fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { + let window_screen = window.on_screen_window(self.width as isize, self.height as isize); + + let w_it = window.return_framebuffer_iterator(); + let f = buffer_indexer(&mut self.buffer, self.width, window_screen); + + for (w_color, pixel) in w_it.zip(f) { + *pixel = *w_color; + } + } + + fn copy_window_only(&mut self, window: &mut MutexGuard) { + /* + (ouz-a):I feel like(because at this point it's very hard to benchmark performance as our resolution is small) + this version is faster than iterator version below, could be improved with a lot of work, but still would + require `unsafe`. + + let bounding_box = window.on_screen_window(self.width as isize, self.height as isize); + for y in 0..bounding_box.height { + let x = 0; + let y = y as isize; + let real_x = x + bounding_box.x; + let real_y = y + bounding_box.y; + let index = self.index(real_x, real_y); + let index_end = index + bounding_box.width; + let color_index = window.frame_buffer.index(x, y); + let color_index_end = color_index + bounding_box.width; + unsafe { + let color = window.frame_buffer.buffer.get_unchecked(color_index..color_index_end); + let buffer = self.buffer.get_unchecked_mut(index..index_end); + buffer.copy_from_slice(&color); + } + } + */ + + // (ouz-a):I like this version better, it's easy to read very flexible and could be simplfied with little more work + // not really sure about how to improve it's performance maybe we could use chunks and then copy slices but + // or we could + self.copy_window_from_iterators(window); + } + + fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { + unsafe { + let index = (self.width * y as usize) + x as usize; + let pixel = self.buffer.get_unchecked_mut(index); + *pixel = col; + } + } + pub fn blank(&mut self) { + for pixel in self.buffer.iter_mut() { + *pixel = 0x000000; + } + } +} + +/// Physical framebuffer we use for final rendering to the screen. +pub struct PhysicalFrameBuffer { + width: usize, + height: usize, + buffer: BorrowedSliceMappedPages, +} +impl PhysicalFrameBuffer { + fn init_front_buffer() -> Result { let graphic_info = multicore_bringup::GRAPHIC_INFO.lock(); if graphic_info.physical_address() == 0 { return Err("wrong physical address for porthole"); @@ -282,10 +366,10 @@ impl FrameBuffer { let buffer_width = graphic_info.width() as usize; let buffer_height = graphic_info.height() as usize; - let framebuffer = FrameBuffer::new( + let framebuffer = PhysicalFrameBuffer::new( buffer_width, buffer_height, - Some(vesa_display_phys_start.unwrap()), + vesa_display_phys_start.unwrap(), )?; Ok(framebuffer) } @@ -293,15 +377,15 @@ impl FrameBuffer { pub fn new( width: usize, height: usize, - physical_address: Option, - ) -> Result { + physical_address: PhysicalAddress, + ) -> Result { let kernel_mmi_ref = memory::get_kernel_mmi_ref().ok_or("KERNEL_MMI was not yet initialized!")?; let size = width * height * core::mem::size_of::(); let pages = memory::allocate_pages_by_bytes(size) .ok_or("could not allocate pages for a new framebuffer")?; - let mapped_framebuffer = if let Some(address) = physical_address { + let mapped_framebuffer = { // For best performance, we map the real physical framebuffer memory // as write-combining using the PAT (on x86 only). // If PAT isn't available, fall back to disabling caching altogether. @@ -325,7 +409,7 @@ impl FrameBuffer { flags = flags.device_memory(true); } - let frames = memory::allocate_frames_by_bytes_at(address, size) + let frames = memory::allocate_frames_by_bytes_at(physical_address, size) .map_err(|_e| "Couldn't allocate frames for the final framebuffer")?; let fb_mp = kernel_mmi_ref .lock() @@ -333,14 +417,8 @@ impl FrameBuffer { .map_allocated_pages_to(pages, frames, flags)?; debug!("Mapped real physical framebuffer: {fb_mp:?}"); fb_mp - } else { - kernel_mmi_ref - .lock() - .page_table - .map_allocated_pages(pages, PteFlags::new().valid(true).writable(true))? }; - - Ok(FrameBuffer { + Ok(PhysicalFrameBuffer { width, height, buffer: mapped_framebuffer @@ -348,101 +426,37 @@ impl FrameBuffer { .map_err(|(_mp, s)| s)?, }) } +} - pub fn draw_something(&mut self, x: isize, y: isize, col: u32) { - if x > 0 && x < self.width as isize && y > 0 && y < self.height as isize { - self.buffer[(self.width * y as usize) + x as usize] = col; - } - } - - pub fn blank(&mut self) { - for pixel in self.buffer.iter_mut() { - *pixel = 0x000000; - } - } - - fn index(&self, x: isize, y: isize) -> usize { - let index = (self.width as isize * y) + x; - index as usize - } - - fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { - let window_screen = window.on_screen_window(self.width as isize, self.height as isize); - - let w_it = window.return_framebuffer_iterator(); - let f = self.indexer(window_screen); - - for (w_color, pixel) in w_it.zip(f) { - *pixel = *w_color; - } - } - - fn copy_window_only(&mut self, window: &mut MutexGuard) { - /* - (ouz-a):I feel like(because at this point it's very hard to benchmark performance as our resolution is small) - this version is faster than iterator version below, could be improved with a lot of work, but still would - require `unsafe`. - - let bounding_box = window.on_screen_window(self.width as isize, self.height as isize); - for y in 0..bounding_box.height { - let x = 0; - let y = y as isize; - let real_x = x + bounding_box.x; - let real_y = y + bounding_box.y; - let index = self.index(real_x, real_y); - let index_end = index + bounding_box.width; - let color_index = window.frame_buffer.index(x, y); - let color_index_end = color_index + bounding_box.width; - unsafe { - let color = window.frame_buffer.buffer.get_unchecked(color_index..color_index_end); - let buffer = self.buffer.get_unchecked_mut(index..index_end); - buffer.copy_from_slice(&color); +pub fn buffer_indexer( + buffer: &mut BorrowedSliceMappedPages, + buffer_width: usize, + rect: Rect, +) -> impl Iterator { + let width = buffer_width; + let x = rect.x; + let mut y = rect.y; + let starter = ((width as isize * y) + x) as usize; + let mut keeper = starter; + let buffer = buffer + .iter_mut() + .enumerate() + .filter(move |(size, _)| { + if y >= rect.height as isize + rect.y as isize { + return false; } - } - */ - - // (ouz-a):I like this version better, it's easy to read very flexible and could be simplfied with little more work - // not really sure about how to improve it's performance maybe we could use chunks and then copy slices but - // or we could - self.copy_window_from_iterators(window); - } - - fn indexer(&mut self, rect: Rect) -> impl Iterator { - let width = self.width; - let x = rect.x; - let mut y = rect.y; - let starter = ((width as isize * y) + x) as usize; - let mut keeper = starter; - let buffer = self - .buffer - .iter_mut() - .enumerate() - .filter(move |(size, _)| { - if y >= rect.height as isize + rect.y as isize { - return false; - } - if *size > starter && size % (keeper + rect.width) == 0 { - y += 1; - keeper = ((width as isize * y) + x) as usize; - } - if size >= &keeper { - true - } else { - false - } - }) - .map(|(_, b)| b); - buffer - } - // TODO: clear api conflict between window and framebuffer, either name them better or - // make it clear which function belongs to which. - fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { - unsafe { - let index = (self.width * y as usize) + x as usize; - let pixel = self.buffer.get_unchecked_mut(index); - *pixel = col; - } - } + if *size > starter && size % (keeper + rect.width) == 0 { + y += 1; + keeper = ((width as isize * y) + x) as usize; + } + if size >= &keeper { + true + } else { + false + } + }) + .map(|(_, b)| b); + buffer } pub fn main(_args: Vec) -> isize { @@ -483,17 +497,17 @@ pub enum Holding { pub struct WindowManager { windows: Vec>>, window_rendering_order: Vec, - v_framebuffer: FrameBuffer, - p_framebuffer: FrameBuffer, + v_framebuffer: VirtualFrameBuffer, + p_framebuffer: PhysicalFrameBuffer, pub mouse: Rect, mouse_holding: Holding, } impl WindowManager { fn init() { - let p_framebuffer = FrameBuffer::init_front_buffer().unwrap(); + let p_framebuffer = PhysicalFrameBuffer::init_front_buffer().unwrap(); let v_framebuffer = - FrameBuffer::new(p_framebuffer.width, p_framebuffer.height, None).unwrap(); + VirtualFrameBuffer::new(p_framebuffer.width, p_framebuffer.height).unwrap(); let mouse = Rect::new(11, 18, 200, 200); let window_manager = WindowManager { @@ -514,7 +528,7 @@ impl WindowManager { manager.window_rendering_order.push(len); let window = Window::new( *dimensions, - FrameBuffer::new(dimensions.width, dimensions.height, None).unwrap(), + VirtualFrameBuffer::new(dimensions.width, dimensions.height).unwrap(), title, ); let arc_window = Arc::new(Mutex::new(window)); @@ -684,13 +698,13 @@ impl WindowManager { // TODO: We need to two different coordinate systems, one for window oriented and one for screen oriented tasks pub struct Window { rect: Rect, - pub frame_buffer: FrameBuffer, + pub frame_buffer: VirtualFrameBuffer, resized: bool, title: Option, } impl Window { - fn new(rect: Rect, frame_buffer: FrameBuffer, title: Option) -> Window { + fn new(rect: Rect, frame_buffer: VirtualFrameBuffer, title: Option) -> Window { Window { rect, frame_buffer, @@ -729,7 +743,8 @@ impl Window { } pub fn draw_border(&mut self) { - let buffer = self.frame_buffer.indexer(self.return_title_border()); + let border = self.return_title_border(); + let buffer = buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, border); for pixel in buffer { *pixel = DEFAULT_BORDER_COLOR; } @@ -768,7 +783,7 @@ impl Window { } fn resize_framebuffer(&mut self) { - self.frame_buffer = FrameBuffer::new(self.rect.width, self.rect.height, None).unwrap(); + self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); } fn return_framebuffer_iterator(&mut self) -> impl Iterator { @@ -780,11 +795,12 @@ impl Window { bounding_box.x = (self.rect.width - bounding_box.width) as isize; } bounding_box.y = 0; - let buffer = self.frame_buffer.indexer(bounding_box); + let buffer = + buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, bounding_box); buffer } else { let rect = Rect::new(self.frame_buffer.width, self.frame_buffer.height, 0, 0); - let buffer = self.frame_buffer.indexer(rect); + let buffer = buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, rect); buffer } } From 03d423b8bb6e7d57b868bfaeb38d1f9fca3ad23d Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 29 Dec 2022 00:38:26 +0300 Subject: [PATCH 06/32] typeset Color = u32 --- applications/porthole/src/lib.rs | 42 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 41559bce3b..71351823a5 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -30,10 +30,12 @@ static TITLE_BAR_HEIGHT: usize = 20; static SCREEN_WIDTH: usize = 1024; static SCREEN_HEIGHT: usize = 768; -// TODO: Create an abstraction for COLOR -static DEFAULT_BORDER_COLOR: u32 = 0x141414; -static DEFAULT_TEXT_COLOR: u32 = 0xFBF1C7; -static DEFAULT_WINDOW_COLOR: u32 = 0x3C3836; +// We could do some fancy stuff with this like a trait, that can convert rgb to hex +// hex to rgb hsl etc, but for now it feels like bikeshedding +type Color = u32; +static DEFAULT_BORDER_COLOR: Color = 0x141414; +static DEFAULT_TEXT_COLOR: Color = 0xFBF1C7; +static DEFAULT_WINDOW_COLOR: Color = 0x3C3836; static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { const T: u32 = 0xFF0000; @@ -82,7 +84,7 @@ impl App { } } -pub fn display_window_title(window: &mut MutexGuard, fg_color: u32, bg_color: u32) { +pub fn display_window_title(window: &mut MutexGuard, fg_color: Color, bg_color: Color) { if let Some(title) = window.title.clone() { let slice = title.as_str(); let mut border = window.return_title_border(); @@ -96,8 +98,8 @@ pub fn print_string( window: &mut MutexGuard, rect: &Rect, slice: &str, - fg_color: u32, - bg_color: u32, + fg_color: Color, + bg_color: Color, column: usize, line: usize, ) { @@ -168,8 +170,8 @@ pub struct TextDisplay { next_col: usize, next_line: usize, text: String, - fg_color: u32, - bg_color: u32, + fg_color: Color, + bg_color: Color, } impl TextDisplay { @@ -179,8 +181,8 @@ impl TextDisplay { next_col: usize, next_line: usize, text: String, - fg_color: u32, - bg_color: u32, + fg_color: Color, + bg_color: Color, ) -> Self { Self { width, @@ -198,6 +200,16 @@ impl TextDisplay { } } +pub struct RelativePos { + x: i32, + y: i32, +} + +pub struct WorldPos { + x: i32, + y: i32, +} + #[derive(Clone, Copy, Debug)] pub struct Rect { pub width: usize, @@ -335,7 +347,7 @@ impl VirtualFrameBuffer { self.copy_window_from_iterators(window); } - fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { + fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { unsafe { let index = (self.width * y as usize) + x as usize; let pixel = self.buffer.get_unchecked_mut(index); @@ -753,7 +765,7 @@ impl Window { // I'm not exactly sure if using `unsafe` is right bet here // but since we are dealing with arrays/slices most of the time // we need to only prove they are within bounds once and this let's us safely call `unsafe` - fn draw_unchecked(&mut self, x: isize, y: isize, col: u32) { + fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { let x = x; let y = y; unsafe { @@ -765,7 +777,7 @@ impl Window { // TODO: add better(line,box..etc) drawing functions - pub fn draw_rectangle(&mut self, col: u32) { + pub fn draw_rectangle(&mut self, col: Color) { // TODO: This should be somewhere else and it should be a function if self.resized { self.resize_framebuffer(); @@ -880,7 +892,7 @@ fn port_loop( .as_ref() .ok_or("couldn't get HPET timer")? .get_counter(); - let diff = (end - start) * hpet_freq / 1_000_000_000_000; + let diff = (end - start) * hpet_freq / 1_000_000; let event_opt = key_consumer .pop() .or_else(|| mouse_consumer.pop()) From 347dedd242bb750fa1646cc0cf1cf51d7bc01096 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 29 Dec 2022 15:20:40 +0300 Subject: [PATCH 07/32] Use RelativePos for Window related functions --- applications/porthole/src/lib.rs | 87 +++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 71351823a5..163b15c3b8 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -10,6 +10,8 @@ extern crate multicore_bringup; extern crate scheduler; extern crate spin; extern crate task; +use core::ops::Add; + use alloc::format; use alloc::sync::{Arc, Weak}; use log::{debug, info}; @@ -74,7 +76,8 @@ impl App { ); print_string( &mut self.window.lock(), - &Rect::new(rect.width, rect.height, 300, 22), + &rect.as_dimension(), + &RelativePos::new(0, 0), &self.text.text, DEFAULT_TEXT_COLOR, DEFAULT_WINDOW_COLOR, @@ -87,16 +90,16 @@ impl App { pub fn display_window_title(window: &mut MutexGuard, fg_color: Color, bg_color: Color) { if let Some(title) = window.title.clone() { let slice = title.as_str(); - let mut border = window.return_title_border(); - let middle = (border.width - (slice.len() * CHARACTER_WIDTH)) / 2; - border.x = middle as isize; - print_string(window, &border, slice, fg_color, bg_color, 0, 0); + let border = window.return_title_border().as_dimension(); + let title_pos = window.return_title_pos(&slice.len()); + print_string(window, &border, &title_pos, slice, fg_color, bg_color, 0, 0); } } pub fn print_string( window: &mut MutexGuard, - rect: &Rect, + dimensions: &Dimensions, + pos: &RelativePos, slice: &str, fg_color: Color, bg_color: Color, @@ -104,12 +107,12 @@ pub fn print_string( line: usize, ) { let slice = slice.as_bytes(); - let relative_x = rect.x; - let relative_y = rect.y; + let relative_x = pos.x; + let relative_y = pos.y; let mut curr_column = column; let mut curr_line = line; - let start_x = relative_x + (curr_column as isize * CHARACTER_WIDTH as isize); - let start_y = relative_y + (curr_line as isize * CHARACTER_HEIGHT as isize); + let start_x = relative_x + (curr_column as u32 * CHARACTER_WIDTH as u32); + let start_y = relative_y + (curr_line as u32 * CHARACTER_HEIGHT as u32); let off_set_x = 0; let off_set_y = 0; @@ -118,8 +121,8 @@ pub fn print_string( let mut z = 0; let mut index_j = j; loop { - let x = start_x + j as isize; - let y = start_y + i as isize; + let x = start_x + j as u32; + let y = start_y + i as u32; if j % CHARACTER_WIDTH == 0 { index_j = 0; } @@ -136,12 +139,12 @@ pub fn print_string( index_j += 1; bg_color }; - window.draw_unchecked(x, y, color); + window.draw_unchecked(&RelativePos::new(x, y), color); j += 1; if j == CHARACTER_WIDTH || j % CHARACTER_WIDTH == 0 - || start_x + j as isize == rect.width as isize + || start_x + j as u32 == dimensions.width as u32 { if slice.len() >= 1 && z < slice.len() - 1 { z += 1; @@ -153,7 +156,7 @@ pub fn print_string( j = off_set_x; } - if i == CHARACTER_HEIGHT || start_y + i as isize == rect.height as isize { + if i == CHARACTER_HEIGHT || start_y + i as u32 == dimensions.height as u32 { break; } } @@ -200,14 +203,37 @@ impl TextDisplay { } } +pub struct Dimensions { + pub width: usize, + pub height: usize, +} + +impl Dimensions { + pub fn new(width: usize, height: usize) -> Self { + Self { width, height } + } +} + pub struct RelativePos { - x: i32, - y: i32, + pub x: u32, + pub y: u32, +} + +impl RelativePos { + pub fn new(x: u32, y: u32) -> Self { + Self { x, y } + } } -pub struct WorldPos { - x: i32, - y: i32, +pub struct ScreenPos { + pub x: i32, + pub y: i32, +} + +impl ScreenPos { + pub fn new(x: i32, y: i32) -> Self { + Self { x, y } + } } #[derive(Clone, Copy, Debug)] @@ -228,6 +254,13 @@ impl Rect { } } + fn as_dimension(&self) -> Dimensions { + Dimensions { + width: self.width, + height: self.height, + } + } + fn start_x(&self) -> isize { self.x } @@ -754,6 +787,13 @@ impl Window { drawable_area } + pub fn return_title_pos(&self, slice_len: &usize) -> RelativePos { + let border = self.return_title_border(); + let pos = (border.width - (slice_len * CHARACTER_WIDTH)) / 2; + let relative_pos = RelativePos::new(pos as u32, 0); + relative_pos + } + pub fn draw_border(&mut self) { let border = self.return_title_border(); let buffer = buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, border); @@ -765,9 +805,9 @@ impl Window { // I'm not exactly sure if using `unsafe` is right bet here // but since we are dealing with arrays/slices most of the time // we need to only prove they are within bounds once and this let's us safely call `unsafe` - fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { - let x = x; - let y = y; + fn draw_unchecked(&mut self, relative_pos: &RelativePos, col: Color) { + let x = relative_pos.x; + let y = relative_pos.y; unsafe { let index = (self.frame_buffer.width * y as usize) + x as usize; let pixel = self.frame_buffer.buffer.get_unchecked_mut(index); @@ -798,6 +838,7 @@ impl Window { self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); } + /// Gives framebuffer iterator for the whole screen fn return_framebuffer_iterator(&mut self) -> impl Iterator { if self.bottom_side_out() || self.left_side_out() || self.right_side_out() { let mut bounding_box = From 8816e1c0254a44fd3a888d2998d4a948953cf555 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 29 Dec 2022 16:08:46 +0300 Subject: [PATCH 08/32] use new types in appropriate places --- applications/porthole/src/lib.rs | 117 ++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 163b15c3b8..6f860254e0 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -236,6 +236,28 @@ impl ScreenPos { } } +impl Add for ScreenPos { + type Output = Self; + + fn add(self, other: Self) -> Self { + Self { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +impl Add for ScreenPos { + type Output = Self; + + fn add(self, other: Rect) -> Self { + Self { + x: self.x + other.x as i32, + y: self.y + other.y as i32, + } + } +} + #[derive(Clone, Copy, Debug)] pub struct Rect { pub width: usize, @@ -607,6 +629,11 @@ impl WindowManager { } } + pub fn set_mouse_pos(&mut self, screen_pos: &ScreenPos) { + self.mouse.x = screen_pos.x as isize; + self.mouse.y = screen_pos.y as isize; + } + fn update(&mut self) { self.v_framebuffer.blank(); self.draw_windows(); @@ -614,39 +641,36 @@ impl WindowManager { } // TODO: Remove magic numbers - fn update_mouse_position(&mut self, x: isize, y: isize) { - let mut new_pos_x = self.mouse.x + x; - let mut new_pos_y = self.mouse.y - y; + fn update_mouse_position(&mut self, screen_pos: ScreenPos) { + let mut new_pos = screen_pos + self.mouse; // handle left - if (new_pos_x + (self.mouse.width as isize / 2)) < 0 { - new_pos_x = self.mouse.x; + if (new_pos.x + (self.mouse.width as i32 / 2)) < 0 { + new_pos.x = self.mouse.x as i32; } - if new_pos_x < 0 { - new_pos_x = 0; + if new_pos.x < 0 { + new_pos.x = 0; } // handle right - if new_pos_x > (self.v_framebuffer.width) as isize - 3 { - new_pos_x = self.v_framebuffer.width as isize - 3; + if new_pos.x > (self.v_framebuffer.width) as i32 - 3 { + new_pos.x = self.v_framebuffer.width as i32 - 3; } // handle top - if new_pos_y < 0 { - new_pos_y = 0; + if new_pos.y < 0 { + new_pos.y = 0; } // handle bottom - if new_pos_y > self.v_framebuffer.height as isize - 3 { - new_pos_y = self.v_framebuffer.height as isize - 3; + if new_pos.y > self.v_framebuffer.height as i32 - 3 { + new_pos.y = self.v_framebuffer.height as i32 - 3; } - - self.mouse.x = new_pos_x; - self.mouse.y = new_pos_y; + self.set_mouse_pos(&new_pos); } - fn drag_windows(&mut self, x: isize, y: isize, mouse_event: &MouseEvent) { + fn drag_windows(&mut self, screen_pos: ScreenPos, mouse_event: &MouseEvent) { if mouse_event.buttons.left() { match self.mouse_holding { Holding::Background => todo!(), @@ -681,30 +705,28 @@ impl WindowManager { Holding::Window(i) => { let window = &mut self.windows[i]; let window_rect = window.upgrade().unwrap().lock().rect; - let mut new_pos_x = window_rect.x + x; - let mut new_pos_y = window_rect.y - y; + let mut new_pos = screen_pos + window_rect; //handle left - if (new_pos_x + (window_rect.width as isize - 20)) < 0 { - new_pos_x = window_rect.x; + if (new_pos.x + (window_rect.width as i32 - 20)) < 0 { + new_pos.x = window_rect.x as i32; } //handle right - if (new_pos_x + 20) > self.v_framebuffer.width as isize { - new_pos_x = window_rect.x; + if (new_pos.x + 20) > self.v_framebuffer.width as i32 { + new_pos.x = window_rect.x as i32; } //handle top - if new_pos_y < 0 { - new_pos_y = window_rect.y; + if new_pos.y < 0 { + new_pos.y = window_rect.y as i32; } - if new_pos_y + 20 > self.v_framebuffer.height as isize { - new_pos_y = window_rect.y; + if new_pos.y + 20 > self.v_framebuffer.height as i32 { + new_pos.y = window_rect.y as i32; } - window.upgrade().unwrap().lock().rect.x = new_pos_x; - window.upgrade().unwrap().lock().rect.y = new_pos_y; + window.upgrade().unwrap().lock().set_pos(&new_pos); } } } else if mouse_event.buttons.right() { @@ -721,8 +743,8 @@ impl WindowManager { self.mouse.y, )) { - window.upgrade().unwrap().lock().rect.width += x as usize; - window.upgrade().unwrap().lock().rect.height -= y as usize; + window.upgrade().unwrap().lock().rect.width += screen_pos.x as usize; + window.upgrade().unwrap().lock().rect.height -= screen_pos.y as usize; window.upgrade().unwrap().lock().resized = true; } } @@ -758,6 +780,24 @@ impl Window { } } + pub fn width(&self) -> usize { + self.rect.width + } + + pub fn height(&self) -> usize { + self.rect.height + } + + pub fn screen_pos(&self) -> ScreenPos { + let screen_pos = ScreenPos::new(self.rect.x as i32, self.rect.y as i32); + screen_pos + } + + pub fn set_pos(&mut self, screen_pos: &ScreenPos) { + self.rect.x = screen_pos.x as isize; + self.rect.y = screen_pos.y as isize; + } + pub fn blank(&mut self) { for pixel in self.frame_buffer.buffer.iter_mut() { *pixel = 0x000000; @@ -829,16 +869,11 @@ impl Window { self.draw_border(); } - pub fn set_position(&mut self, x: isize, y: isize) { - self.rect.x = x; - self.rect.y = y; - } - fn resize_framebuffer(&mut self) { self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); } - /// Gives framebuffer iterator for the whole screen + /// Gives mutable framebuffer iterator for the whole window fn return_framebuffer_iterator(&mut self) -> impl Iterator { if self.bottom_side_out() || self.left_side_out() || self.right_side_out() { let mut bounding_box = @@ -972,8 +1007,12 @@ fn port_loop( } } if x != 0 || y != 0 { - window_manager.lock().update_mouse_position(x, y); - window_manager.lock().drag_windows(x, y, &mouse_event); + window_manager + .lock() + .update_mouse_position(ScreenPos::new(x as i32, -(y as i32))); + window_manager + .lock() + .drag_windows(ScreenPos::new(x as i32, -(y as i32)), &mouse_event); } } _ => (), From dc560da26f22e609a00a8695b5544b65e469c72f Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 30 Dec 2022 15:58:16 +0300 Subject: [PATCH 09/32] only clone window title when needed --- applications/porthole/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 6f860254e0..219947cee7 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -88,7 +88,8 @@ impl App { } pub fn display_window_title(window: &mut MutexGuard, fg_color: Color, bg_color: Color) { - if let Some(title) = window.title.clone() { + if window.title.is_some() { + let title = window.title.as_mut().unwrap().clone(); let slice = title.as_str(); let border = window.return_title_border().as_dimension(); let title_pos = window.return_title_pos(&slice.len()); From d351b6576e24a3d851b7e0cc5bf2cd04bf7271a9 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 30 Dec 2022 16:15:31 +0300 Subject: [PATCH 10/32] fix window ref --- applications/porthole/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 219947cee7..54ced4d883 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -87,7 +87,7 @@ impl App { } } -pub fn display_window_title(window: &mut MutexGuard, fg_color: Color, bg_color: Color) { +pub fn display_window_title(window: &mut Window, fg_color: Color, bg_color: Color) { if window.title.is_some() { let title = window.title.as_mut().unwrap().clone(); let slice = title.as_str(); @@ -98,7 +98,7 @@ pub fn display_window_title(window: &mut MutexGuard, fg_color: Color, bg } pub fn print_string( - window: &mut MutexGuard, + window: &mut Window, dimensions: &Dimensions, pos: &RelativePos, slice: &str, From 84e4acc88ef0fbcaa477879156164785d9a61ae5 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 30 Dec 2022 17:25:35 +0300 Subject: [PATCH 11/32] cache ubiquitous rectangles --- applications/porthole/src/lib.rs | 62 +++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 54ced4d883..a9527569a1 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -215,6 +215,7 @@ impl Dimensions { } } +#[derive(Clone, Copy)] pub struct RelativePos { pub x: u32, pub y: u32, @@ -730,6 +731,7 @@ impl WindowManager { window.upgrade().unwrap().lock().set_pos(&new_pos); } } + // FIXME: Resizing is broken if windows are on top of each other } else if mouse_event.buttons.right() { for window in self.windows.iter_mut() { if window @@ -745,7 +747,13 @@ impl WindowManager { )) { window.upgrade().unwrap().lock().rect.width += screen_pos.x as usize; - window.upgrade().unwrap().lock().rect.height -= screen_pos.y as usize; + window.upgrade().unwrap().lock().rect.height += screen_pos.y as usize; + window.upgrade().unwrap().lock().reset_drawable_area(); + window + .upgrade() + .unwrap() + .lock() + .reset_title_pos_and_border(); window.upgrade().unwrap().lock().resized = true; } } @@ -763,12 +771,14 @@ impl WindowManager { } } -// TODO: We need to two different coordinate systems, one for window oriented and one for screen oriented tasks pub struct Window { rect: Rect, pub frame_buffer: VirtualFrameBuffer, resized: bool, title: Option, + title_border: Option, + title_pos: Option, + drawable_area: Option, } impl Window { @@ -778,6 +788,9 @@ impl Window { frame_buffer, resized: false, title, + title_border: None, + title_pos: None, + drawable_area: None, } } @@ -805,10 +818,21 @@ impl Window { } } + pub fn reset_drawable_area(&mut self) { + self.drawable_area = None; + } + + pub fn reset_title_pos_and_border(&mut self) { + self.title_border = None; + self.title_pos = None; + } + /// Returns Window's border area width height with default position - pub fn return_title_border(&self) -> Rect { - let border = Rect::new(self.rect.width, TITLE_BAR_HEIGHT, 0, 0); - border + pub fn return_title_border(&mut self) -> Rect { + let border = + self.title_border + .get_or_insert(Rect::new(self.rect.width, TITLE_BAR_HEIGHT, 0, 0)); + *border } pub fn return_dynamic_border_pos(&self) -> Rect { @@ -818,21 +842,27 @@ impl Window { } // We don't want user to draw on top a border - pub fn return_drawable_area(&self) -> Rect { + pub fn return_drawable_area(&mut self) -> Rect { let border = self.return_title_border(); - let x = 0; - let y = border.height; - let width = border.width; - let height = self.rect.height - y; - let drawable_area = Rect::new(width, height, x, y as isize); - drawable_area + let drawable_area = self.drawable_area.get_or_insert({ + let x = 0; + let y = border.height; + let width = border.width; + let height = self.rect.height - y; + let drawable_area = Rect::new(width, height, x, y as isize); + drawable_area + }); + *drawable_area } - pub fn return_title_pos(&self, slice_len: &usize) -> RelativePos { + pub fn return_title_pos(&mut self, slice_len: &usize) -> RelativePos { let border = self.return_title_border(); - let pos = (border.width - (slice_len * CHARACTER_WIDTH)) / 2; - let relative_pos = RelativePos::new(pos as u32, 0); - relative_pos + let relative_pos = self.title_pos.get_or_insert({ + let pos = (border.width - (slice_len * CHARACTER_WIDTH)) / 2; + let relative_pos = RelativePos::new(pos as u32, 0); + relative_pos + }); + *relative_pos } pub fn draw_border(&mut self) { From 55bf2dc5c214825150a5409a234f9cac1f62f111 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 30 Dec 2022 17:29:02 +0300 Subject: [PATCH 12/32] windows shouldn't be smaller than 50x50 --- applications/porthole/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index a9527569a1..799c02d1d3 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -746,8 +746,7 @@ impl WindowManager { self.mouse.y, )) { - window.upgrade().unwrap().lock().rect.width += screen_pos.x as usize; - window.upgrade().unwrap().lock().rect.height += screen_pos.y as usize; + window.upgrade().unwrap().lock().resize_window(screen_pos.x, screen_pos.y); window.upgrade().unwrap().lock().reset_drawable_area(); window .upgrade() @@ -818,6 +817,15 @@ impl Window { } } + pub fn resize_window(&mut self,width:i32,height:i32){ + let new_width = self.width() + width as usize; + let new_height = self.height() + height as usize; + if new_width >= 50 && new_height >= 50 { + self.rect.width = new_width; + self.rect.height = new_height; + } + } + pub fn reset_drawable_area(&mut self) { self.drawable_area = None; } From df21b36434e11084444bb0bd7048368667eabc33 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 2 Jan 2023 13:44:52 +0300 Subject: [PATCH 13/32] make it readable --- applications/porthole/src/lib.rs | 235 +++++++++++-------------------- 1 file changed, 85 insertions(+), 150 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 799c02d1d3..22ce19986a 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -108,56 +108,54 @@ pub fn print_string( line: usize, ) { let slice = slice.as_bytes(); - let relative_x = pos.x; - let relative_y = pos.y; - let mut curr_column = column; - let mut curr_line = line; - let start_x = relative_x + (curr_column as u32 * CHARACTER_WIDTH as u32); - let start_y = relative_y + (curr_line as u32 * CHARACTER_HEIGHT as u32); - let off_set_x = 0; - let off_set_y = 0; - - let mut j = off_set_x; - let mut i = off_set_y; - let mut z = 0; - let mut index_j = j; + let start_x = pos.x + (column as u32 * CHARACTER_WIDTH as u32); + let start_y = pos.y + (line as u32 * CHARACTER_HEIGHT as u32); + + let mut x_pixel = 0; + let mut row_controller = 0; + let mut char_index = 0; + let mut char_color_on_x_axis = x_pixel; loop { - let x = start_x + j as u32; - let y = start_y + i as u32; - if j % CHARACTER_WIDTH == 0 { - index_j = 0; - } - let color = if index_j >= 1 { - let index = index_j - 1; - let char_font = FONT_BASIC[slice[z] as usize][i]; - index_j += 1; + let x = start_x + x_pixel as u32; + let y = start_y + row_controller as u32; + if x_pixel % CHARACTER_WIDTH == 0 { + char_color_on_x_axis = 0; + } + let color = if char_color_on_x_axis >= 1 { + let index = char_color_on_x_axis - 1; + let char_font = FONT_BASIC[slice[char_index] as usize][row_controller]; + char_color_on_x_axis += 1; if get_bit(char_font, index) != 0 { fg_color } else { bg_color } } else { - index_j += 1; + char_color_on_x_axis += 1; bg_color }; window.draw_unchecked(&RelativePos::new(x, y), color); - j += 1; - if j == CHARACTER_WIDTH - || j % CHARACTER_WIDTH == 0 - || start_x + j as u32 == dimensions.width as u32 + x_pixel += 1; + if x_pixel == CHARACTER_WIDTH + || x_pixel % CHARACTER_WIDTH == 0 + || start_x + x_pixel as u32 == dimensions.width as u32 { - if slice.len() >= 1 && z < slice.len() - 1 { - z += 1; + if slice.len() >= 1 && char_index < slice.len() - 1 { + char_index += 1; } - if j >= CHARACTER_WIDTH * slice.len() && j % (CHARACTER_WIDTH * slice.len()) == 0 { - i += 1; - z = 0; - j = off_set_x; + if x_pixel >= CHARACTER_WIDTH * slice.len() + && x_pixel % (CHARACTER_WIDTH * slice.len()) == 0 + { + row_controller += 1; + char_index = 0; + x_pixel = 0; } - if i == CHARACTER_HEIGHT || start_y + i as u32 == dimensions.height as u32 { + if row_controller == CHARACTER_HEIGHT + || start_y + row_controller as u32 == dimensions.height as u32 + { break; } } @@ -313,30 +311,29 @@ impl Rect { } } - pub fn on_screen_window(&self, screen_width: isize, screen_height: isize) -> Rect { + /// Creates a new `Rect` from visible parts of itself. + pub fn return_visible_rect(&self) -> Rect { let mut start_x = self.x; let start_y = self.y; let mut end_x = self.width as isize; let mut end_y = self.height as isize; if self.x < 0 { start_x = 0; - end_x = self.x + self.width as isize; - } else if self.x + self.width as isize > screen_width as isize { + end_x = self.end_x(); + } else if self.end_x() > SCREEN_WIDTH as isize { start_x = self.x; - let gap = (self.x + self.width as isize) - screen_width as isize; + let gap = (self.x + self.width as isize) - SCREEN_HEIGHT as isize; end_x = self.width as isize - gap; } - if self.y + self.height as isize > screen_height { - let gap = (self.y + self.height as isize) - screen_height; + if self.end_y() > SCREEN_HEIGHT as isize { + let gap = (self.y + self.height as isize) - SCREEN_HEIGHT as isize; end_y = self.height as isize - gap; } - let f = Rect::new(end_x as usize, end_y as usize, start_x, start_y); - f + let visible_rect = Rect::new(end_x as usize, end_y as usize, start_x, start_y); + visible_rect } } -/// FrameBuffer with no actual physical memory mapped, -/// used for Window and WindowManager's backbuffer. pub struct VirtualFrameBuffer { width: usize, height: usize, @@ -364,43 +361,18 @@ impl VirtualFrameBuffer { } fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { - let window_screen = window.on_screen_window(self.width as isize, self.height as isize); + let window_screen = window.rect.return_visible_rect(); - let w_it = window.return_framebuffer_iterator(); - let f = buffer_indexer(&mut self.buffer, self.width, window_screen); + let window_iterator = window.return_framebuffer_iterator(); + let framebuffer_iterator = + ret_fbiter_for_given_rect(&mut self.buffer, self.width, window_screen); - for (w_color, pixel) in w_it.zip(f) { + for (w_color, pixel) in window_iterator.zip(framebuffer_iterator) { *pixel = *w_color; } } fn copy_window_only(&mut self, window: &mut MutexGuard) { - /* - (ouz-a):I feel like(because at this point it's very hard to benchmark performance as our resolution is small) - this version is faster than iterator version below, could be improved with a lot of work, but still would - require `unsafe`. - - let bounding_box = window.on_screen_window(self.width as isize, self.height as isize); - for y in 0..bounding_box.height { - let x = 0; - let y = y as isize; - let real_x = x + bounding_box.x; - let real_y = y + bounding_box.y; - let index = self.index(real_x, real_y); - let index_end = index + bounding_box.width; - let color_index = window.frame_buffer.index(x, y); - let color_index_end = color_index + bounding_box.width; - unsafe { - let color = window.frame_buffer.buffer.get_unchecked(color_index..color_index_end); - let buffer = self.buffer.get_unchecked_mut(index..index_end); - buffer.copy_from_slice(&color); - } - } - */ - - // (ouz-a):I like this version better, it's easy to read very flexible and could be simplfied with little more work - // not really sure about how to improve it's performance maybe we could use chunks and then copy slices but - // or we could self.copy_window_from_iterators(window); } @@ -497,7 +469,7 @@ impl PhysicalFrameBuffer { } } -pub fn buffer_indexer( +pub fn ret_fbiter_for_given_rect( buffer: &mut BorrowedSliceMappedPages, buffer_width: usize, rect: Rect, @@ -577,6 +549,7 @@ impl WindowManager { let p_framebuffer = PhysicalFrameBuffer::init_front_buffer().unwrap(); let v_framebuffer = VirtualFrameBuffer::new(p_framebuffer.width, p_framebuffer.height).unwrap(); + // FIXME: Don't use magic numbers let mouse = Rect::new(11, 18, 200, 200); let window_manager = WindowManager { @@ -615,11 +588,9 @@ impl WindowManager { } } + // TODO: Do stop indexing mouse image create iterator for it, also draw the thing with iterators fn draw_mouse(&mut self) { - let bounding_box = self.mouse.on_screen_window( - self.v_framebuffer.width as isize, - self.v_framebuffer.height as isize, - ); + let bounding_box = self.mouse.return_visible_rect(); for y in bounding_box.y..bounding_box.y + bounding_box.height as isize { for x in bounding_box.x..bounding_box.x + bounding_box.width as isize { let color = MOUSE_POINTER_IMAGE[(x - bounding_box.x) as usize] @@ -647,28 +618,15 @@ impl WindowManager { let mut new_pos = screen_pos + self.mouse; // handle left - if (new_pos.x + (self.mouse.width as i32 / 2)) < 0 { - new_pos.x = self.mouse.x as i32; - } - - if new_pos.x < 0 { - new_pos.x = 0; - } - + new_pos.x = core::cmp::max(new_pos.x, 0); // handle right - if new_pos.x > (self.v_framebuffer.width) as i32 - 3 { - new_pos.x = self.v_framebuffer.width as i32 - 3; - } + new_pos.x = core::cmp::min(new_pos.x, self.v_framebuffer.width as i32 - 3); // handle top - if new_pos.y < 0 { - new_pos.y = 0; - } - + new_pos.y = core::cmp::max(new_pos.y, 0); // handle bottom - if new_pos.y > self.v_framebuffer.height as i32 - 3 { - new_pos.y = self.v_framebuffer.height as i32 - 3; - } + new_pos.y = core::cmp::min(new_pos.y, self.v_framebuffer.height as i32 - 3); + self.set_mouse_pos(&new_pos); } @@ -746,7 +704,11 @@ impl WindowManager { self.mouse.y, )) { - window.upgrade().unwrap().lock().resize_window(screen_pos.x, screen_pos.y); + window + .upgrade() + .unwrap() + .lock() + .resize_window(screen_pos.x, screen_pos.y); window.upgrade().unwrap().lock().reset_drawable_area(); window .upgrade() @@ -817,15 +779,15 @@ impl Window { } } - pub fn resize_window(&mut self,width:i32,height:i32){ + pub fn resize_window(&mut self, width: i32, height: i32) { let new_width = self.width() + width as usize; let new_height = self.height() + height as usize; - if new_width >= 50 && new_height >= 50 { + if new_width > 50 && new_height > 50 { self.rect.width = new_width; self.rect.height = new_height; } } - + pub fn reset_drawable_area(&mut self) { self.drawable_area = None; } @@ -875,7 +837,8 @@ impl Window { pub fn draw_border(&mut self) { let border = self.return_title_border(); - let buffer = buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, border); + let buffer = + ret_fbiter_for_given_rect(&mut self.frame_buffer.buffer, self.rect.width, border); for pixel in buffer { *pixel = DEFAULT_BORDER_COLOR; } @@ -894,14 +857,17 @@ impl Window { } } - // TODO: add better(line,box..etc) drawing functions - - pub fn draw_rectangle(&mut self, col: Color) { - // TODO: This should be somewhere else and it should be a function + fn should_resize_framebuffer(&mut self) { if self.resized { self.resize_framebuffer(); self.resized = false; } + } + + // TODO: add better(line,box..etc) drawing functions + pub fn draw_rectangle(&mut self, col: Color) { + self.should_resize_framebuffer(); + for pixel in self.frame_buffer.buffer.iter_mut() { *pixel = col; } @@ -915,67 +881,36 @@ impl Window { /// Gives mutable framebuffer iterator for the whole window fn return_framebuffer_iterator(&mut self) -> impl Iterator { if self.bottom_side_out() || self.left_side_out() || self.right_side_out() { - let mut bounding_box = - self.on_screen_window(SCREEN_WIDTH as isize, SCREEN_HEIGHT as isize); + let mut bounding_box = self.rect.return_visible_rect(); bounding_box.x = 0; if self.left_side_out() { bounding_box.x = (self.rect.width - bounding_box.width) as isize; } bounding_box.y = 0; - let buffer = - buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, bounding_box); + let buffer = ret_fbiter_for_given_rect( + &mut self.frame_buffer.buffer, + self.rect.width, + bounding_box, + ); buffer } else { let rect = Rect::new(self.frame_buffer.width, self.frame_buffer.height, 0, 0); - let buffer = buffer_indexer(&mut self.frame_buffer.buffer, self.rect.width, rect); + let buffer = + ret_fbiter_for_given_rect(&mut self.frame_buffer.buffer, self.rect.width, rect); buffer } } pub fn left_side_out(&self) -> bool { - if self.rect.x < 0 { - true - } else { - false - } + self.rect.x < 0 } + pub fn right_side_out(&self) -> bool { - if (self.rect.x + self.rect.width as isize) > SCREEN_WIDTH as isize { - true - } else { - false - } + self.rect.x + self.rect.width as isize > SCREEN_WIDTH as isize } pub fn bottom_side_out(&self) -> bool { - if (self.rect.y + self.rect.height as isize) > SCREEN_HEIGHT as isize { - true - } else { - false - } - } - - // TODO: This should be moved to somewhere else - // and renamed - pub fn on_screen_window(&self, screen_width: isize, screen_height: isize) -> Rect { - let mut start_x = self.rect.x; - let start_y = self.rect.y; - let mut end_x = self.rect.width as isize; - let mut end_y = self.rect.height as isize; - if self.rect.x < 0 { - start_x = 0; - end_x = self.rect.x + self.rect.width as isize; - } else if self.rect.x + self.rect.width as isize > screen_width as isize { - start_x = self.rect.x; - let gap = (self.rect.x + self.rect.width as isize) - screen_width as isize; - end_x = self.rect.width as isize - gap; - } - if self.rect.y + self.rect.height as isize > screen_height { - let gap = (self.rect.y + self.rect.height as isize) - screen_height; - end_y = self.rect.height as isize - gap; - } - let f = Rect::new(end_x as usize, end_y as usize, start_x, start_y); - f + self.rect.y + self.rect.height as isize > SCREEN_HEIGHT as isize } } @@ -990,7 +925,7 @@ fn port_loop( height: 400, next_col: 1, next_line: 1, - text: "asdasd".to_string(), + text: "Hello World".to_string(), fg_color: 0xFFFFFF, bg_color: 0x0F0FFF, }; From 8ca8adf45671830f4332209a35374ea38b18dc1a Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 4 Jan 2023 20:51:38 +0300 Subject: [PATCH 14/32] introduce FrameBufferChunker --- applications/porthole/src/lib.rs | 127 +++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 31 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 22ce19986a..76add78830 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] - +#![feature(slice_ptr_get)] extern crate alloc; extern crate device_manager; extern crate hpet; @@ -10,7 +10,9 @@ extern crate multicore_bringup; extern crate scheduler; extern crate spin; extern crate task; +use core::marker::PhantomData; use core::ops::Add; +use core::slice::IterMut; use alloc::format; use alloc::sync::{Arc, Weak}; @@ -322,7 +324,7 @@ impl Rect { end_x = self.end_x(); } else if self.end_x() > SCREEN_WIDTH as isize { start_x = self.x; - let gap = (self.x + self.width as isize) - SCREEN_HEIGHT as isize; + let gap = (self.x + self.width as isize) - SCREEN_WIDTH as isize; end_x = self.width as isize - gap; } if self.end_y() > SCREEN_HEIGHT as isize { @@ -362,14 +364,22 @@ impl VirtualFrameBuffer { fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { let window_screen = window.rect.return_visible_rect(); + let window_stride = window.frame_buffer.width as usize; - let window_iterator = window.return_framebuffer_iterator(); - let framebuffer_iterator = - ret_fbiter_for_given_rect(&mut self.buffer, self.width, window_screen); + // FIXME: Handle errors with error types + let chunker = FramebufferChunker::new(&mut self.buffer, window_screen, self.width).unwrap(); + let relative_visible_rect = window.return_relative_visible_rect(); - for (w_color, pixel) in window_iterator.zip(framebuffer_iterator) { - *pixel = *w_color; + let w_chunker = FramebufferChunker::new( + &mut window.frame_buffer.buffer, + relative_visible_rect, + window_stride, + ) + .unwrap(); + for (screen, window) in chunker.zip(w_chunker) { + screen.copy_from_slice(window); } + } fn copy_window_only(&mut self, window: &mut MutexGuard) { @@ -469,6 +479,62 @@ impl PhysicalFrameBuffer { } } +struct FramebufferChunker<'a, T: 'a> { + fb: *mut [T], + rect: Rect, + stride: usize, + row_index_beg: usize, + row_index_end: usize, + current_column: usize, + _marker: PhantomData<&'a mut T>, +} + +impl<'a, T: 'a> FramebufferChunker<'a, T> { + #[inline] + pub fn new(slice: &'a mut [T], rect: Rect, stride: usize) -> Option { + if rect.width <= stride { + let current_column = rect.y as usize; + let row_index_beg = (stride * current_column) + rect.x as usize; + let row_index_end = (stride * current_column) + rect.end_x() as usize; + Some(Self { + fb: slice, + rect, + stride, + row_index_beg, + row_index_end, + current_column, + _marker: PhantomData, + }) + } else { + None + } + } + + fn calculate_next_row(&mut self) { + self.row_index_beg = (self.stride * self.current_column) + self.rect.x as usize; + self.row_index_end = (self.stride * self.current_column) + self.rect.end_x() as usize; + } +} + +impl<'a, T> Iterator for FramebufferChunker<'a, T> { + type Item = &'a mut [T]; + + fn next(&mut self) -> Option<&'a mut [T]> { + if self.current_column < self.rect.end_y() as usize { + let chunk = unsafe { + self.fb + .get_unchecked_mut(self.row_index_beg..self.row_index_end) + }; + self.current_column += 1; + self.calculate_next_row(); + let chunk = { unsafe { &mut *chunk } }; + Some(chunk) + } else { + None + } + } +} + pub fn ret_fbiter_for_given_rect( buffer: &mut BorrowedSliceMappedPages, buffer_width: usize, @@ -655,6 +721,7 @@ impl WindowManager { self.window_rendering_order.remove(wind_index); self.window_rendering_order.push(i); } + // FIXME: Don't hold a window if its behind another window self.mouse_holding = Holding::Window(i); break; } @@ -837,10 +904,16 @@ impl Window { pub fn draw_border(&mut self) { let border = self.return_title_border(); - let buffer = - ret_fbiter_for_given_rect(&mut self.frame_buffer.buffer, self.rect.width, border); - for pixel in buffer { - *pixel = DEFAULT_BORDER_COLOR; + if let Some(chunker) = FramebufferChunker::new( + &mut self.frame_buffer.buffer, + border, + self.frame_buffer.width, + ) { + for row in chunker { + for pixel in row { + *pixel = DEFAULT_BORDER_COLOR; + } + } } } @@ -878,27 +951,17 @@ impl Window { self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); } - /// Gives mutable framebuffer iterator for the whole window - fn return_framebuffer_iterator(&mut self) -> impl Iterator { - if self.bottom_side_out() || self.left_side_out() || self.right_side_out() { - let mut bounding_box = self.rect.return_visible_rect(); - bounding_box.x = 0; - if self.left_side_out() { - bounding_box.x = (self.rect.width - bounding_box.width) as isize; - } - bounding_box.y = 0; - let buffer = ret_fbiter_for_given_rect( - &mut self.frame_buffer.buffer, - self.rect.width, - bounding_box, - ); - buffer - } else { - let rect = Rect::new(self.frame_buffer.width, self.frame_buffer.height, 0, 0); - let buffer = - ret_fbiter_for_given_rect(&mut self.frame_buffer.buffer, self.rect.width, rect); - buffer + /// Returns visible part of self's `rect` with relative bounds applied + /// e.g if visible rect is `Rect{width: 358, height: 400, x: 0, y: 0}` + /// this will return `Rect{width: 358, height: 400, x: 42, y: 0}` + pub fn return_relative_visible_rect(&self) -> Rect { + let mut bounding_box = self.rect.return_visible_rect(); + bounding_box.x = 0; + if self.left_side_out() { + bounding_box.x = (self.rect.width - bounding_box.width) as isize; } + bounding_box.y = 0; + bounding_box } pub fn left_side_out(&self) -> bool { @@ -936,6 +999,8 @@ fn port_loop( .ok_or("couldn't get HPET timer")? .get_counter(); let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; + let mut counter = 0; + let mut total_time = 0; loop { let end = hpet From 94f4af0550d3e88bc96a44a3862404319867fa11 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 5 Jan 2023 21:35:36 +0300 Subject: [PATCH 15/32] make the core more readable --- applications/porthole/src/lib.rs | 224 +++++++++++++------------------ 1 file changed, 91 insertions(+), 133 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 76add78830..f75e4c6c95 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -78,7 +78,8 @@ impl App { ); print_string( &mut self.window.lock(), - &rect.as_dimension(), + rect.width, + rect.height, &RelativePos::new(0, 0), &self.text.text, DEFAULT_TEXT_COLOR, @@ -93,15 +94,16 @@ pub fn display_window_title(window: &mut Window, fg_color: Color, bg_color: Colo if window.title.is_some() { let title = window.title.as_mut().unwrap().clone(); let slice = title.as_str(); - let border = window.return_title_border().as_dimension(); - let title_pos = window.return_title_pos(&slice.len()); - print_string(window, &border, &title_pos, slice, fg_color, bg_color, 0, 0); + let border = window.title_border(); + let title_pos = window.title_pos(&slice.len()); + print_string(window, border.width,border.height, &title_pos, slice, fg_color, bg_color, 0, 0); } } pub fn print_string( window: &mut Window, - dimensions: &Dimensions, + width: usize, + height: usize, pos: &RelativePos, slice: &str, fg_color: Color, @@ -113,14 +115,14 @@ pub fn print_string( let start_x = pos.x + (column as u32 * CHARACTER_WIDTH as u32); let start_y = pos.y + (line as u32 * CHARACTER_HEIGHT as u32); - let mut x_pixel = 0; + let mut x_index = 0; let mut row_controller = 0; let mut char_index = 0; - let mut char_color_on_x_axis = x_pixel; + let mut char_color_on_x_axis = x_index; loop { - let x = start_x + x_pixel as u32; + let x = start_x + x_index as u32; let y = start_y + row_controller as u32; - if x_pixel % CHARACTER_WIDTH == 0 { + if x_index % CHARACTER_WIDTH == 0 { char_color_on_x_axis = 0; } let color = if char_color_on_x_axis >= 1 { @@ -138,25 +140,25 @@ pub fn print_string( }; window.draw_unchecked(&RelativePos::new(x, y), color); - x_pixel += 1; - if x_pixel == CHARACTER_WIDTH - || x_pixel % CHARACTER_WIDTH == 0 - || start_x + x_pixel as u32 == dimensions.width as u32 + x_index += 1; + if x_index == CHARACTER_WIDTH + || x_index % CHARACTER_WIDTH == 0 + || start_x + x_index as u32 == width as u32 { if slice.len() >= 1 && char_index < slice.len() - 1 { char_index += 1; } - if x_pixel >= CHARACTER_WIDTH * slice.len() - && x_pixel % (CHARACTER_WIDTH * slice.len()) == 0 + if x_index >= CHARACTER_WIDTH * slice.len() + && x_index % (CHARACTER_WIDTH * slice.len()) == 0 { row_controller += 1; char_index = 0; - x_pixel = 0; + x_index = 0; } if row_controller == CHARACTER_HEIGHT - || start_y + row_controller as u32 == dimensions.height as u32 + || start_y + row_controller as u32 == height as u32 { break; } @@ -215,6 +217,7 @@ impl Dimensions { } } +/// Position that is relative to a `Window` #[derive(Clone, Copy)] pub struct RelativePos { pub x: u32, @@ -225,8 +228,13 @@ impl RelativePos { pub fn new(x: u32, y: u32) -> Self { Self { x, y } } + + pub fn to_1d_pos(&self,target_stride: u32) -> usize{ + ((target_stride * self.y) + self.x) as usize + } } +/// Position that is relative to the screen pub struct ScreenPos { pub x: i32, pub y: i32, @@ -236,6 +244,10 @@ impl ScreenPos { pub fn new(x: i32, y: i32) -> Self { Self { x, y } } + + pub fn to_1d_pos(&self) -> usize{ + ((SCREEN_WIDTH as i32 * self.y) + self.x) as usize + } } impl Add for ScreenPos { @@ -278,34 +290,19 @@ impl Rect { } } - fn as_dimension(&self) -> Dimensions { - Dimensions { - width: self.width, - height: self.height, - } - } - - fn start_x(&self) -> isize { - self.x - } - - fn end_x(&self) -> isize { + fn x_plus_width(&self) -> isize { self.x + self.width as isize } - fn start_y(&self) -> isize { - self.y - } - - fn end_y(&self) -> isize { + fn y_plus_height(&self) -> isize { self.y + self.height as isize } fn detect_collision(&self, other: &Rect) -> bool { - if self.x < other.end_x() - && self.end_x() > other.x - && self.y < other.end_y() - && self.end_y() > other.y + if self.x < other.x_plus_width() + && self.x_plus_width() > other.x + && self.y < other.y_plus_height() + && self.y_plus_height() > other.y { true } else { @@ -314,24 +311,24 @@ impl Rect { } /// Creates a new `Rect` from visible parts of itself. - pub fn return_visible_rect(&self) -> Rect { - let mut start_x = self.x; - let start_y = self.y; - let mut end_x = self.width as isize; - let mut end_y = self.height as isize; + pub fn visible_rect(&self) -> Rect { + let mut x = self.x; + let y = self.y; + let mut width = self.width as isize; + let mut height = self.height as isize; if self.x < 0 { - start_x = 0; - end_x = self.end_x(); - } else if self.end_x() > SCREEN_WIDTH as isize { - start_x = self.x; + x = 0; + width = self.x_plus_width(); + } else if self.x_plus_width() > SCREEN_WIDTH as isize { + x = self.x; let gap = (self.x + self.width as isize) - SCREEN_WIDTH as isize; - end_x = self.width as isize - gap; + width = self.width as isize - gap; } - if self.end_y() > SCREEN_HEIGHT as isize { + if self.y_plus_height() > SCREEN_HEIGHT as isize { let gap = (self.y + self.height as isize) - SCREEN_HEIGHT as isize; - end_y = self.height as isize - gap; + height = self.height as isize - gap; } - let visible_rect = Rect::new(end_x as usize, end_y as usize, start_x, start_y); + let visible_rect = Rect::new(width as usize, height as usize, x, y); visible_rect } } @@ -362,30 +359,27 @@ impl VirtualFrameBuffer { }) } - fn copy_window_from_iterators(&mut self, window: &mut MutexGuard) { - let window_screen = window.rect.return_visible_rect(); + fn copy_windows_into_main_vbuffer(&mut self, window: &mut MutexGuard) { + let window_screen = window.rect.visible_rect(); let window_stride = window.frame_buffer.width as usize; // FIXME: Handle errors with error types - let chunker = FramebufferChunker::new(&mut self.buffer, window_screen, self.width).unwrap(); - let relative_visible_rect = window.return_relative_visible_rect(); + let screen_rows = FramebufferRowChunks::new(&mut self.buffer, window_screen, self.width).unwrap(); + // To handle rendering when the window is partially outside the screen we use relative version of visible rect + let relative_visible_rect = window.relative_visible_rect(); - let w_chunker = FramebufferChunker::new( + let window_rows = FramebufferRowChunks::new( &mut window.frame_buffer.buffer, relative_visible_rect, window_stride, ) .unwrap(); - for (screen, window) in chunker.zip(w_chunker) { - screen.copy_from_slice(window); + for (screen_row, window_row) in screen_rows.zip(window_rows) { + screen_row.copy_from_slice(window_row); } } - fn copy_window_only(&mut self, window: &mut MutexGuard) { - self.copy_window_from_iterators(window); - } - fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { unsafe { let index = (self.width * y as usize) + x as usize; @@ -437,9 +431,6 @@ impl PhysicalFrameBuffer { .ok_or("could not allocate pages for a new framebuffer")?; let mapped_framebuffer = { - // For best performance, we map the real physical framebuffer memory - // as write-combining using the PAT (on x86 only). - // If PAT isn't available, fall back to disabling caching altogether. let mut flags: PteFlagsArch = PteFlags::new().valid(true).writable(true).into(); #[cfg(target_arch = "x86_64")] @@ -479,7 +470,7 @@ impl PhysicalFrameBuffer { } } -struct FramebufferChunker<'a, T: 'a> { +struct FramebufferRowChunks<'a, T: 'a> { fb: *mut [T], rect: Rect, stride: usize, @@ -489,13 +480,13 @@ struct FramebufferChunker<'a, T: 'a> { _marker: PhantomData<&'a mut T>, } -impl<'a, T: 'a> FramebufferChunker<'a, T> { +impl<'a, T: 'a> FramebufferRowChunks<'a, T> { #[inline] pub fn new(slice: &'a mut [T], rect: Rect, stride: usize) -> Option { if rect.width <= stride { let current_column = rect.y as usize; let row_index_beg = (stride * current_column) + rect.x as usize; - let row_index_end = (stride * current_column) + rect.end_x() as usize; + let row_index_end = (stride * current_column) + rect.x_plus_width() as usize; Some(Self { fb: slice, rect, @@ -512,15 +503,15 @@ impl<'a, T: 'a> FramebufferChunker<'a, T> { fn calculate_next_row(&mut self) { self.row_index_beg = (self.stride * self.current_column) + self.rect.x as usize; - self.row_index_end = (self.stride * self.current_column) + self.rect.end_x() as usize; + self.row_index_end = (self.stride * self.current_column) + self.rect.x_plus_width() as usize; } } -impl<'a, T> Iterator for FramebufferChunker<'a, T> { +impl<'a, T> Iterator for FramebufferRowChunks<'a, T> { type Item = &'a mut [T]; fn next(&mut self) -> Option<&'a mut [T]> { - if self.current_column < self.rect.end_y() as usize { + if self.current_column < self.rect.y_plus_height() as usize { let chunk = unsafe { self.fb .get_unchecked_mut(self.row_index_beg..self.row_index_end) @@ -535,37 +526,6 @@ impl<'a, T> Iterator for FramebufferChunker<'a, T> { } } -pub fn ret_fbiter_for_given_rect( - buffer: &mut BorrowedSliceMappedPages, - buffer_width: usize, - rect: Rect, -) -> impl Iterator { - let width = buffer_width; - let x = rect.x; - let mut y = rect.y; - let starter = ((width as isize * y) + x) as usize; - let mut keeper = starter; - let buffer = buffer - .iter_mut() - .enumerate() - .filter(move |(size, _)| { - if y >= rect.height as isize + rect.y as isize { - return false; - } - if *size > starter && size % (keeper + rect.width) == 0 { - y += 1; - keeper = ((width as isize * y) + x) as usize; - } - if size >= &keeper { - true - } else { - false - } - }) - .map(|(_, b)| b); - buffer -} - pub fn main(_args: Vec) -> isize { let mouse_consumer = Queue::with_capacity(100); let mouse_producer = mouse_consumer.clone(); @@ -629,14 +589,14 @@ impl WindowManager { WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); } - fn new_window(dimensions: &Rect, title: Option) -> Arc> { + fn new_window(rect: &Rect, title: Option) -> Arc> { let mut manager = WINDOW_MANAGER.get().unwrap().lock(); let len = manager.windows.len(); manager.window_rendering_order.push(len); let window = Window::new( - *dimensions, - VirtualFrameBuffer::new(dimensions.width, dimensions.height).unwrap(), + *rect, + VirtualFrameBuffer::new(rect.width, rect.height).unwrap(), title, ); let arc_window = Arc::new(Mutex::new(window)); @@ -647,16 +607,16 @@ impl WindowManager { fn draw_windows(&mut self) { for order in self.window_rendering_order.iter() { self.v_framebuffer - .copy_window_only(&mut self.windows[*order].upgrade().unwrap().lock()); + .copy_windows_into_main_vbuffer(&mut self.windows[*order].upgrade().unwrap().lock()); } for window in self.windows.iter() { window.upgrade().unwrap().lock().blank(); } } - // TODO: Do stop indexing mouse image create iterator for it, also draw the thing with iterators + // TODO: Stop indexing mouse image create iterator for it, also draw the thing with iterators fn draw_mouse(&mut self) { - let bounding_box = self.mouse.return_visible_rect(); + let bounding_box = self.mouse.visible_rect(); for y in bounding_box.y..bounding_box.y + bounding_box.height as isize { for x in bounding_box.x..bounding_box.x + bounding_box.width as isize { let color = MOUSE_POINTER_IMAGE[(x - bounding_box.x) as usize] @@ -701,7 +661,6 @@ impl WindowManager { match self.mouse_holding { Holding::Background => todo!(), Holding::Nothing => { - // This costs nothing let rendering_o = self.window_rendering_order.clone(); for &i in rendering_o.iter().rev() { let window = &mut self.windows[i]; @@ -709,7 +668,7 @@ impl WindowManager { .upgrade() .unwrap() .lock() - .return_dynamic_border_pos() + .dynamic_title_border_pos() .detect_collision(&self.mouse) { if i != *self.window_rendering_order.last().unwrap() { @@ -749,11 +708,12 @@ impl WindowManager { new_pos.y = window_rect.y as i32; } + // handle bottom if new_pos.y + 20 > self.v_framebuffer.height as i32 { new_pos.y = window_rect.y as i32; } - window.upgrade().unwrap().lock().set_pos(&new_pos); + window.upgrade().unwrap().lock().set_screen_pos(&new_pos); } } // FIXME: Resizing is broken if windows are on top of each other @@ -835,7 +795,7 @@ impl Window { screen_pos } - pub fn set_pos(&mut self, screen_pos: &ScreenPos) { + pub fn set_screen_pos(&mut self, screen_pos: &ScreenPos) { self.rect.x = screen_pos.x as isize; self.rect.y = screen_pos.y as isize; } @@ -864,23 +824,24 @@ impl Window { self.title_pos = None; } - /// Returns Window's border area width height with default position - pub fn return_title_border(&mut self) -> Rect { + /// Returns Window's border area width and height with 0 as position + pub fn title_border(&mut self) -> Rect { let border = self.title_border .get_or_insert(Rect::new(self.rect.width, TITLE_BAR_HEIGHT, 0, 0)); *border } - pub fn return_dynamic_border_pos(&self) -> Rect { + /// Return's title border's position in screen coordinates + pub fn dynamic_title_border_pos(&self) -> Rect { let mut rect = self.rect; rect.height = TITLE_BAR_HEIGHT; rect } - // We don't want user to draw on top a border - pub fn return_drawable_area(&mut self) -> Rect { - let border = self.return_title_border(); + /// Return's drawable area + pub fn drawable_area(&mut self) -> Rect { + let border = self.title_border(); let drawable_area = self.drawable_area.get_or_insert({ let x = 0; let y = border.height; @@ -892,8 +853,8 @@ impl Window { *drawable_area } - pub fn return_title_pos(&mut self, slice_len: &usize) -> RelativePos { - let border = self.return_title_border(); + pub fn title_pos(&mut self, slice_len: &usize) -> RelativePos { + let border = self.title_border(); let relative_pos = self.title_pos.get_or_insert({ let pos = (border.width - (slice_len * CHARACTER_WIDTH)) / 2; let relative_pos = RelativePos::new(pos as u32, 0); @@ -902,14 +863,14 @@ impl Window { *relative_pos } - pub fn draw_border(&mut self) { - let border = self.return_title_border(); - if let Some(chunker) = FramebufferChunker::new( + pub fn draw_title_border(&mut self) { + let border = self.title_border(); + if let Some(rows) = FramebufferRowChunks::new( &mut self.frame_buffer.buffer, border, self.frame_buffer.width, ) { - for row in chunker { + for row in rows { for pixel in row { *pixel = DEFAULT_BORDER_COLOR; } @@ -917,9 +878,7 @@ impl Window { } } - // I'm not exactly sure if using `unsafe` is right bet here - // but since we are dealing with arrays/slices most of the time - // we need to only prove they are within bounds once and this let's us safely call `unsafe` + // TODO: look into this fn draw_unchecked(&mut self, relative_pos: &RelativePos, col: Color) { let x = relative_pos.x; let y = relative_pos.y; @@ -937,16 +896,17 @@ impl Window { } } - // TODO: add better(line,box..etc) drawing functions + /// Draws the rectangular shape representing the `Window` pub fn draw_rectangle(&mut self, col: Color) { self.should_resize_framebuffer(); for pixel in self.frame_buffer.buffer.iter_mut() { *pixel = col; } - self.draw_border(); + self.draw_title_border(); } + /// Resizes framebuffer after to Window's width and height fn resize_framebuffer(&mut self) { self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); } @@ -954,8 +914,8 @@ impl Window { /// Returns visible part of self's `rect` with relative bounds applied /// e.g if visible rect is `Rect{width: 358, height: 400, x: 0, y: 0}` /// this will return `Rect{width: 358, height: 400, x: 42, y: 0}` - pub fn return_relative_visible_rect(&self) -> Rect { - let mut bounding_box = self.rect.return_visible_rect(); + pub fn relative_visible_rect(&self) -> Rect { + let mut bounding_box = self.rect.visible_rect(); bounding_box.x = 0; if self.left_side_out() { bounding_box.x = (self.rect.width - bounding_box.width) as isize; @@ -999,8 +959,6 @@ fn port_loop( .ok_or("couldn't get HPET timer")? .get_counter(); let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; - let mut counter = 0; - let mut total_time = 0; loop { let end = hpet From 2f2007c599c4360ce5b6ca2e7c50b107228ec764 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 5 Jan 2023 21:45:58 +0300 Subject: [PATCH 16/32] use new way to get graphic info --- applications/porthole/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index f75e4c6c95..0376c0e235 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -34,8 +34,6 @@ static TITLE_BAR_HEIGHT: usize = 20; static SCREEN_WIDTH: usize = 1024; static SCREEN_HEIGHT: usize = 768; -// We could do some fancy stuff with this like a trait, that can convert rgb to hex -// hex to rgb hsl etc, but for now it feels like bikeshedding type Color = u32; static DEFAULT_BORDER_COLOR: Color = 0x141414; static DEFAULT_TEXT_COLOR: Color = 0xFBF1C7; @@ -402,7 +400,7 @@ pub struct PhysicalFrameBuffer { } impl PhysicalFrameBuffer { fn init_front_buffer() -> Result { - let graphic_info = multicore_bringup::GRAPHIC_INFO.lock(); + let graphic_info = multicore_bringup::get_graphic_info().unwrap(); if graphic_info.physical_address() == 0 { return Err("wrong physical address for porthole"); } From 45ada86545e72a8a6d2177de22714a1faf65969e Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 6 Jan 2023 00:10:26 +0300 Subject: [PATCH 17/32] fix window bounce add stride info --- applications/porthole/src/lib.rs | 55 ++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 0376c0e235..2d8042bc27 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -34,6 +34,8 @@ static TITLE_BAR_HEIGHT: usize = 20; static SCREEN_WIDTH: usize = 1024; static SCREEN_HEIGHT: usize = 768; +// We could do some fancy stuff with this like a trait, that can convert rgb to hex +// hex to rgb hsl etc, but for now it feels like bikeshedding type Color = u32; static DEFAULT_BORDER_COLOR: Color = 0x141414; static DEFAULT_TEXT_COLOR: Color = 0xFBF1C7; @@ -94,7 +96,17 @@ pub fn display_window_title(window: &mut Window, fg_color: Color, bg_color: Colo let slice = title.as_str(); let border = window.title_border(); let title_pos = window.title_pos(&slice.len()); - print_string(window, border.width,border.height, &title_pos, slice, fg_color, bg_color, 0, 0); + print_string( + window, + border.width, + border.height, + &title_pos, + slice, + fg_color, + bg_color, + 0, + 0, + ); } } @@ -227,12 +239,12 @@ impl RelativePos { Self { x, y } } - pub fn to_1d_pos(&self,target_stride: u32) -> usize{ + pub fn to_1d_pos(&self, target_stride: u32) -> usize { ((target_stride * self.y) + self.x) as usize } } -/// Position that is relative to the screen +/// Position that is relative to the screen pub struct ScreenPos { pub x: i32, pub y: i32, @@ -243,7 +255,7 @@ impl ScreenPos { Self { x, y } } - pub fn to_1d_pos(&self) -> usize{ + pub fn to_1d_pos(&self) -> usize { ((SCREEN_WIDTH as i32 * self.y) + self.x) as usize } } @@ -362,7 +374,8 @@ impl VirtualFrameBuffer { let window_stride = window.frame_buffer.width as usize; // FIXME: Handle errors with error types - let screen_rows = FramebufferRowChunks::new(&mut self.buffer, window_screen, self.width).unwrap(); + let screen_rows = + FramebufferRowChunks::new(&mut self.buffer, window_screen, self.width).unwrap(); // To handle rendering when the window is partially outside the screen we use relative version of visible rect let relative_visible_rect = window.relative_visible_rect(); @@ -375,7 +388,6 @@ impl VirtualFrameBuffer { for (screen_row, window_row) in screen_rows.zip(window_rows) { screen_row.copy_from_slice(window_row); } - } fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { @@ -396,6 +408,7 @@ impl VirtualFrameBuffer { pub struct PhysicalFrameBuffer { width: usize, height: usize, + stride: usize, buffer: BorrowedSliceMappedPages, } impl PhysicalFrameBuffer { @@ -408,10 +421,13 @@ impl PhysicalFrameBuffer { PhysicalAddress::new(graphic_info.physical_address() as usize).ok_or("Invalid address"); let buffer_width = graphic_info.width() as usize; let buffer_height = graphic_info.height() as usize; + // We are assuming a pixel is 4 bytes big + let stride = graphic_info.bytes_per_scanline() / 4; let framebuffer = PhysicalFrameBuffer::new( buffer_width, buffer_height, + stride as usize, vesa_display_phys_start.unwrap(), )?; Ok(framebuffer) @@ -420,6 +436,7 @@ impl PhysicalFrameBuffer { pub fn new( width: usize, height: usize, + stride: usize, physical_address: PhysicalAddress, ) -> Result { let kernel_mmi_ref = @@ -461,6 +478,7 @@ impl PhysicalFrameBuffer { Ok(PhysicalFrameBuffer { width, height, + stride, buffer: mapped_framebuffer .into_borrowed_slice_mut(0, width * height) .map_err(|(_mp, s)| s)?, @@ -501,7 +519,8 @@ impl<'a, T: 'a> FramebufferRowChunks<'a, T> { fn calculate_next_row(&mut self) { self.row_index_beg = (self.stride * self.current_column) + self.rect.x as usize; - self.row_index_end = (self.stride * self.current_column) + self.rect.x_plus_width() as usize; + self.row_index_end = + (self.stride * self.current_column) + self.rect.x_plus_width() as usize; } } @@ -604,8 +623,9 @@ impl WindowManager { fn draw_windows(&mut self) { for order in self.window_rendering_order.iter() { - self.v_framebuffer - .copy_windows_into_main_vbuffer(&mut self.windows[*order].upgrade().unwrap().lock()); + self.v_framebuffer.copy_windows_into_main_vbuffer( + &mut self.windows[*order].upgrade().unwrap().lock(), + ); } for window in self.windows.iter() { window.upgrade().unwrap().lock().blank(); @@ -693,22 +713,22 @@ impl WindowManager { //handle left if (new_pos.x + (window_rect.width as i32 - 20)) < 0 { - new_pos.x = window_rect.x as i32; + new_pos.x = -(window_rect.width as i32 - 20); } //handle right if (new_pos.x + 20) > self.v_framebuffer.width as i32 { - new_pos.x = window_rect.x as i32; + new_pos.x = SCREEN_WIDTH as i32 - 20 } //handle top if new_pos.y < 0 { - new_pos.y = window_rect.y as i32; + new_pos.y = 0 } // handle bottom if new_pos.y + 20 > self.v_framebuffer.height as i32 { - new_pos.y = window_rect.y as i32; + new_pos.y = (SCREEN_HEIGHT - 20) as i32; } window.upgrade().unwrap().lock().set_screen_pos(&new_pos); @@ -957,6 +977,8 @@ fn port_loop( .ok_or("couldn't get HPET timer")? .get_counter(); let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; + let mut counter = 0; + let mut total_time = 0; loop { let end = hpet @@ -1019,6 +1041,13 @@ fn port_loop( window_3.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); window_manager.lock().update(); window_manager.lock().render(); + if counter == 1000 { + log::info!("time {}", total_time / counter); + counter = 0; + total_time = 0; + } + counter += 1; + total_time += diff; start = hpet.as_ref().unwrap().get_counter(); } From ea2269a25f1b8f294e4110f7af519ac49e78324c Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 6 Jan 2023 00:28:16 +0300 Subject: [PATCH 18/32] some more clean up --- applications/porthole/src/lib.rs | 47 +++++++++++++------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 2d8042bc27..ead967647a 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -12,7 +12,6 @@ extern crate spin; extern crate task; use core::marker::PhantomData; use core::ops::Add; -use core::slice::IterMut; use alloc::format; use alloc::sync::{Arc, Weak}; @@ -20,7 +19,6 @@ use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; use event_types::Event; -use keycodes_ascii::{KeyAction, KeyEvent, Keycode}; use mpmc::Queue; use alloc::string::{String, ToString}; @@ -61,16 +59,15 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { }; pub struct App { window: Arc>, - text: TextDisplay, + text: TextDisplayInfo, } impl App { - pub fn new(window: Arc>, text: TextDisplay) -> Self { + pub fn new(window: Arc>, text: TextDisplayInfo) -> Self { Self { window, text } } pub fn draw(&mut self) { self.window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); - let rect = self.window.lock().rect; display_window_title( &mut self.window.lock(), DEFAULT_TEXT_COLOR, @@ -78,14 +75,14 @@ impl App { ); print_string( &mut self.window.lock(), - rect.width, - rect.height, - &RelativePos::new(0, 0), + self.text.width, + self.text.height, + &self.text.pos, &self.text.text, - DEFAULT_TEXT_COLOR, - DEFAULT_WINDOW_COLOR, - 0, - 1, + self.text.fg_color, + self.text.bg_color, + self.text.next_col, + self.text.next_line, ) } } @@ -179,10 +176,10 @@ fn get_bit(char_font: u8, i: usize) -> u8 { char_font & (0x80 >> i) } -// TODO: Implement proper `types` for width height etc -pub struct TextDisplay { +pub struct TextDisplayInfo { width: usize, height: usize, + pos: RelativePos, next_col: usize, next_line: usize, text: String, @@ -190,10 +187,11 @@ pub struct TextDisplay { bg_color: Color, } -impl TextDisplay { +impl TextDisplayInfo { pub fn new( width: usize, height: usize, + pos: RelativePos, next_col: usize, next_line: usize, text: String, @@ -203,6 +201,7 @@ impl TextDisplay { Self { width, height, + pos, next_col, next_line, text, @@ -961,14 +960,15 @@ fn port_loop( let window_manager = WINDOW_MANAGER.get().unwrap(); let window_3 = WindowManager::new_window(&Rect::new(400, 200, 30, 100), None); let window_2 = WindowManager::new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic"))); - let text = TextDisplay { + let text = TextDisplayInfo { width: 400, height: 400, + pos: RelativePos::new(0, 0), next_col: 1, next_line: 1, text: "Hello World".to_string(), - fg_color: 0xFFFFFF, - bg_color: 0x0F0FFF, + fg_color: DEFAULT_TEXT_COLOR, + bg_color: DEFAULT_BORDER_COLOR, }; let mut app = App::new(window_2, text); let hpet = get_hpet(); @@ -977,8 +977,6 @@ fn port_loop( .ok_or("couldn't get HPET timer")? .get_counter(); let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; - let mut counter = 0; - let mut total_time = 0; loop { let end = hpet @@ -1036,18 +1034,11 @@ fn port_loop( } } - if diff >= 0 { + if diff > 0 { app.draw(); window_3.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); window_manager.lock().update(); window_manager.lock().render(); - if counter == 1000 { - log::info!("time {}", total_time / counter); - counter = 0; - total_time = 0; - } - counter += 1; - total_time += diff; start = hpet.as_ref().unwrap().get_counter(); } From 6022562fd09261240ef40240864851166dd4229d Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 6 Jan 2023 00:39:09 +0300 Subject: [PATCH 19/32] clippy lints --- applications/porthole/src/lib.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index ead967647a..23713c1726 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -308,15 +308,10 @@ impl Rect { } fn detect_collision(&self, other: &Rect) -> bool { - if self.x < other.x_plus_width() + self.x < other.x_plus_width() && self.x_plus_width() > other.x && self.y < other.y_plus_height() && self.y_plus_height() > other.y - { - true - } else { - false - } } /// Creates a new `Rect` from visible parts of itself. @@ -616,7 +611,7 @@ impl WindowManager { title, ); let arc_window = Arc::new(Mutex::new(window)); - manager.windows.push(Arc::downgrade(&arc_window.clone())); + manager.windows.push(Arc::downgrade(&arc_window)); arc_window } From cec65e92f65431ca085329e20712ef7132852af5 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 7 Jan 2023 00:54:47 +0300 Subject: [PATCH 20/32] fix a mouse bug --- applications/porthole/src/lib.rs | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 23713c1726..327763e463 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -572,6 +572,19 @@ pub enum Holding { Window(usize), } +impl Holding { + fn nothing(&self) -> bool { + *self == Holding::Nothing + } + + fn backgrond(&self) -> bool { + *self == Holding::Background + } + + fn window(&self) -> bool { + !self.nothing() && !self.backgrond() + } +} pub struct WindowManager { windows: Vec>>, window_rendering_order: Vec, @@ -671,7 +684,7 @@ impl WindowManager { fn drag_windows(&mut self, screen_pos: ScreenPos, mouse_event: &MouseEvent) { if mouse_event.buttons.left() { match self.mouse_holding { - Holding::Background => todo!(), + Holding::Background => {} Holding::Nothing => { let rendering_o = self.window_rendering_order.clone(); for &i in rendering_o.iter().rev() { @@ -680,7 +693,7 @@ impl WindowManager { .upgrade() .unwrap() .lock() - .dynamic_title_border_pos() + .rect .detect_collision(&self.mouse) { if i != *self.window_rendering_order.last().unwrap() { @@ -692,12 +705,23 @@ impl WindowManager { self.window_rendering_order.remove(wind_index); self.window_rendering_order.push(i); } - // FIXME: Don't hold a window if its behind another window - self.mouse_holding = Holding::Window(i); + if window + .upgrade() + .unwrap() + .lock() + .dynamic_title_border_pos() + .detect_collision(&self.mouse) + { + self.mouse_holding = Holding::Window(i); + } break; } self.mouse_holding = Holding::Nothing; } + // If couldn't hold onto anything we must have hold onto background + if self.mouse_holding.nothing() { + self.mouse_holding = Holding::Background; + } } // TODO: Fix the bug that allows you to move the window while mouse position is still Holding::Window(i) => { @@ -726,6 +750,9 @@ impl WindowManager { } window.upgrade().unwrap().lock().set_screen_pos(&new_pos); + log::info!("mouse pos is {:?}", self.mouse); + let window_rect = window.upgrade().unwrap().lock().rect; + log::info!("window rect is {:?}", &window_rect); } } // FIXME: Resizing is broken if windows are on top of each other From 965557ea6e653e8d267f784286c578f6e8415ab9 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 7 Jan 2023 00:56:32 +0300 Subject: [PATCH 21/32] remove logs --- applications/porthole/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 327763e463..18333f0add 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -750,9 +750,6 @@ impl WindowManager { } window.upgrade().unwrap().lock().set_screen_pos(&new_pos); - log::info!("mouse pos is {:?}", self.mouse); - let window_rect = window.upgrade().unwrap().lock().rect; - log::info!("window rect is {:?}", &window_rect); } } // FIXME: Resizing is broken if windows are on top of each other From c00e901d9524661825807dbaa9fac897f3832fa9 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 7 Jan 2023 14:49:59 +0300 Subject: [PATCH 22/32] fix window movement bug --- applications/porthole/src/lib.rs | 46 +++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 18333f0add..377733e642 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -11,7 +11,7 @@ extern crate scheduler; extern crate spin; extern crate task; use core::marker::PhantomData; -use core::ops::Add; +use core::ops::{Add, Sub}; use alloc::format; use alloc::sync::{Arc, Weak}; @@ -244,6 +244,7 @@ impl RelativePos { } /// Position that is relative to the screen +#[derive(Debug, Clone, Copy)] pub struct ScreenPos { pub x: i32, pub y: i32, @@ -270,6 +271,17 @@ impl Add for ScreenPos { } } +impl Sub for ScreenPos { + type Output = Self; + + fn sub(self, other: Self) -> Self { + Self { + x: self.x - other.x, + y: self.y - other.y, + } + } +} + impl Add for ScreenPos { type Output = Self; @@ -299,6 +311,13 @@ impl Rect { } } + pub fn to_screen_pos(&self) -> ScreenPos { + ScreenPos { + x: self.x as i32, + y: self.y as i32, + } + } + fn x_plus_width(&self) -> isize { self.x + self.width as isize } @@ -591,6 +610,7 @@ pub struct WindowManager { v_framebuffer: VirtualFrameBuffer, p_framebuffer: PhysicalFrameBuffer, pub mouse: Rect, + prev_mouse_pos: ScreenPos, mouse_holding: Holding, } @@ -608,6 +628,7 @@ impl WindowManager { v_framebuffer, p_framebuffer, mouse, + prev_mouse_pos: mouse.to_screen_pos(), mouse_holding: Holding::Nothing, }; WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); @@ -664,9 +685,8 @@ impl WindowManager { self.draw_mouse(); } - // TODO: Remove magic numbers - fn update_mouse_position(&mut self, screen_pos: ScreenPos) { - let mut new_pos = screen_pos + self.mouse; + fn calculate_next_mouse_pos(&self, curr_pos: ScreenPos, next_pos: ScreenPos) -> ScreenPos { + let mut new_pos = next_pos + curr_pos; // handle left new_pos.x = core::cmp::max(new_pos.x, 0); @@ -678,6 +698,14 @@ impl WindowManager { // handle bottom new_pos.y = core::cmp::min(new_pos.y, self.v_framebuffer.height as i32 - 3); + new_pos + } + + // TODO: Remove magic numbers + fn update_mouse_position(&mut self, screen_pos: ScreenPos) { + self.prev_mouse_pos = self.mouse.to_screen_pos(); + let new_pos = self.calculate_next_mouse_pos(self.mouse.to_screen_pos(), screen_pos); + self.set_mouse_pos(&new_pos); } @@ -720,14 +748,18 @@ impl WindowManager { } // If couldn't hold onto anything we must have hold onto background if self.mouse_holding.nothing() { - self.mouse_holding = Holding::Background; + self.mouse_holding = Holding::Background } } - // TODO: Fix the bug that allows you to move the window while mouse position is still Holding::Window(i) => { + // These calculations are required because we do want finer control + // over a window's movement. + let prev_mouse_pos = self.prev_mouse_pos; + let next_mouse_pos = self.calculate_next_mouse_pos(prev_mouse_pos, screen_pos); let window = &mut self.windows[i]; let window_rect = window.upgrade().unwrap().lock().rect; - let mut new_pos = screen_pos + window_rect; + let diff = next_mouse_pos - prev_mouse_pos; + let mut new_pos = diff + window_rect.to_screen_pos(); //handle left if (new_pos.x + (window_rect.width as i32 - 20)) < 0 { From 53695c933d3f01d4d0822a55fe5eba7f796f8cfc Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 7 Jan 2023 22:27:43 +0300 Subject: [PATCH 23/32] fix window resizing bug --- applications/porthole/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 377733e642..452addf9ec 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -784,9 +784,10 @@ impl WindowManager { window.upgrade().unwrap().lock().set_screen_pos(&new_pos); } } - // FIXME: Resizing is broken if windows are on top of each other } else if mouse_event.buttons.right() { - for window in self.windows.iter_mut() { + let rendering_o = self.window_rendering_order.clone(); + for &i in rendering_o.iter().rev() { + let window = &mut self.windows[i]; if window .upgrade() .unwrap() @@ -811,6 +812,7 @@ impl WindowManager { .lock() .reset_title_pos_and_border(); window.upgrade().unwrap().lock().resized = true; + break; } } } From 02afd8934ebd101f662bd421bdd776b6458f15a8 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 9 Jan 2023 13:14:40 +0300 Subject: [PATCH 24/32] remove every unwrap --- applications/porthole/src/lib.rs | 281 ++++++++++++++----------------- 1 file changed, 130 insertions(+), 151 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 452addf9ec..798dea216f 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -58,52 +58,33 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { ] }; pub struct App { - window: Arc>, + window: Weak>, text: TextDisplayInfo, } impl App { - pub fn new(window: Arc>, text: TextDisplayInfo) -> Self { + pub fn new(window: Weak>, text: TextDisplayInfo) -> Self { Self { window, text } } - pub fn draw(&mut self) { - self.window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); - display_window_title( - &mut self.window.lock(), - DEFAULT_TEXT_COLOR, - DEFAULT_BORDER_COLOR, - ); - print_string( - &mut self.window.lock(), - self.text.width, - self.text.height, - &self.text.pos, - &self.text.text, - self.text.fg_color, - self.text.bg_color, - self.text.next_col, - self.text.next_line, - ) - } -} - -pub fn display_window_title(window: &mut Window, fg_color: Color, bg_color: Color) { - if window.title.is_some() { - let title = window.title.as_mut().unwrap().clone(); - let slice = title.as_str(); - let border = window.title_border(); - let title_pos = window.title_pos(&slice.len()); - print_string( - window, - border.width, - border.height, - &title_pos, - slice, - fg_color, - bg_color, - 0, - 0, - ); + pub fn draw(&mut self) -> Result<(), &'static str> { + if let Some(window) = self.window.upgrade() { + window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR)?; + window + .lock() + .display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); + print_string( + &mut window.lock(), + self.text.width, + self.text.height, + &self.text.pos, + &self.text.text, + self.text.fg_color, + self.text.bg_color, + self.text.next_col, + self.text.next_line, + ); + } + Ok(()) } } @@ -215,17 +196,6 @@ impl TextDisplayInfo { } } -pub struct Dimensions { - pub width: usize, - pub height: usize, -} - -impl Dimensions { - pub fn new(width: usize, height: usize) -> Self { - Self { width, height } - } -} - /// Position that is relative to a `Window` #[derive(Clone, Copy)] pub struct RelativePos { @@ -382,24 +352,24 @@ impl VirtualFrameBuffer { }) } - fn copy_windows_into_main_vbuffer(&mut self, window: &mut MutexGuard) { + fn copy_window_into_main_vbuffer(&mut self, window: &mut MutexGuard) { let window_screen = window.rect.visible_rect(); let window_stride = window.frame_buffer.width as usize; - // FIXME: Handle errors with error types - let screen_rows = - FramebufferRowChunks::new(&mut self.buffer, window_screen, self.width).unwrap(); - // To handle rendering when the window is partially outside the screen we use relative version of visible rect - let relative_visible_rect = window.relative_visible_rect(); - - let window_rows = FramebufferRowChunks::new( - &mut window.frame_buffer.buffer, - relative_visible_rect, - window_stride, - ) - .unwrap(); - for (screen_row, window_row) in screen_rows.zip(window_rows) { - screen_row.copy_from_slice(window_row); + if let Some(screen_rows) = + FramebufferRowChunks::new(&mut self.buffer, window_screen, self.width) + { + // To handle rendering when the window is partially outside the screen we use relative version of visible rect + let relative_visible_rect = window.relative_visible_rect(); + if let Some(window_rows) = FramebufferRowChunks::new( + &mut window.frame_buffer.buffer, + relative_visible_rect, + window_stride, + ) { + for (screen_row, window_row) in screen_rows.zip(window_rows) { + screen_row.copy_from_slice(window_row); + } + } } } @@ -426,12 +396,14 @@ pub struct PhysicalFrameBuffer { } impl PhysicalFrameBuffer { fn init_front_buffer() -> Result { - let graphic_info = multicore_bringup::get_graphic_info().unwrap(); + let graphic_info = + multicore_bringup::get_graphic_info().ok_or("Failed to get graphic info")?; if graphic_info.physical_address() == 0 { return Err("wrong physical address for porthole"); } let vesa_display_phys_start = - PhysicalAddress::new(graphic_info.physical_address() as usize).ok_or("Invalid address"); + PhysicalAddress::new(graphic_info.physical_address() as usize) + .ok_or("Invalid address")?; let buffer_width = graphic_info.width() as usize; let buffer_height = graphic_info.height() as usize; // We are assuming a pixel is 4 bytes big @@ -441,7 +413,7 @@ impl PhysicalFrameBuffer { buffer_width, buffer_height, stride as usize, - vesa_display_phys_start.unwrap(), + vesa_display_phys_start, )?; Ok(framebuffer) } @@ -556,13 +528,14 @@ impl<'a, T> Iterator for FramebufferRowChunks<'a, T> { } } -pub fn main(_args: Vec) -> isize { +pub fn main(_args: Vec) -> Result { let mouse_consumer = Queue::with_capacity(100); let mouse_producer = mouse_consumer.clone(); let key_consumer = Queue::with_capacity(100); let key_producer = mouse_consumer.clone(); - WindowManager::init(); - device_manager::init(key_producer, mouse_producer).unwrap(); + WindowManager::init()?; + device_manager::init(key_producer, mouse_producer) + .or(Err("Failed to initialize device manager"))?; let _task_ref = match spawn::new_task_builder(port_loop, (mouse_consumer, key_consumer)) .name("port_loop".to_string()) @@ -572,11 +545,14 @@ pub fn main(_args: Vec) -> isize { Err(err) => { log::error!("{}", err); log::error!("failed to spawn shell"); - return -1; + return Err("failed to spawn shell"); } }; - task::get_my_current_task().unwrap().block().unwrap(); + task::get_my_current_task() + .ok_or("Failed to get the current task")? + .block() + .or(Err("Failed to block the current task"))?; scheduler::schedule(); loop { @@ -605,20 +581,20 @@ impl Holding { } } pub struct WindowManager { - windows: Vec>>, + windows: Vec>>, window_rendering_order: Vec, v_framebuffer: VirtualFrameBuffer, p_framebuffer: PhysicalFrameBuffer, pub mouse: Rect, prev_mouse_pos: ScreenPos, mouse_holding: Holding, + active_window_index: usize, } impl WindowManager { - fn init() { - let p_framebuffer = PhysicalFrameBuffer::init_front_buffer().unwrap(); - let v_framebuffer = - VirtualFrameBuffer::new(p_framebuffer.width, p_framebuffer.height).unwrap(); + fn init() -> Result<(), &'static str> { + let p_framebuffer = PhysicalFrameBuffer::init_front_buffer()?; + let v_framebuffer = VirtualFrameBuffer::new(p_framebuffer.width, p_framebuffer.height)?; // FIXME: Don't use magic numbers let mouse = Rect::new(11, 18, 200, 200); @@ -630,33 +606,38 @@ impl WindowManager { mouse, prev_mouse_pos: mouse.to_screen_pos(), mouse_holding: Holding::Nothing, + active_window_index: 0, }; WINDOW_MANAGER.call_once(|| Mutex::new(window_manager)); + Ok(()) } - fn new_window(rect: &Rect, title: Option) -> Arc> { - let mut manager = WINDOW_MANAGER.get().unwrap().lock(); - let len = manager.windows.len(); + fn new_window( + &mut self, + rect: &Rect, + title: Option, + ) -> Result>, &'static str> { + let len = self.windows.len(); - manager.window_rendering_order.push(len); + self.window_rendering_order.push(len); let window = Window::new( *rect, - VirtualFrameBuffer::new(rect.width, rect.height).unwrap(), + VirtualFrameBuffer::new(rect.width, rect.height)?, title, ); let arc_window = Arc::new(Mutex::new(window)); - manager.windows.push(Arc::downgrade(&arc_window)); - arc_window + let weak = Arc::downgrade(&arc_window); + self.windows.push(arc_window); + Ok(weak) } fn draw_windows(&mut self) { for order in self.window_rendering_order.iter() { - self.v_framebuffer.copy_windows_into_main_vbuffer( - &mut self.windows[*order].upgrade().unwrap().lock(), - ); + self.v_framebuffer + .copy_window_into_main_vbuffer(&mut self.windows[*order].lock()); } for window in self.windows.iter() { - window.upgrade().unwrap().lock().blank(); + window.lock().blank(); } } @@ -715,32 +696,20 @@ impl WindowManager { Holding::Background => {} Holding::Nothing => { let rendering_o = self.window_rendering_order.clone(); - for &i in rendering_o.iter().rev() { - let window = &mut self.windows[i]; - if window - .upgrade() - .unwrap() - .lock() - .rect - .detect_collision(&self.mouse) - { - if i != *self.window_rendering_order.last().unwrap() { - let wind_index = self - .window_rendering_order - .iter() - .position(|ii| ii == &i) - .unwrap(); - self.window_rendering_order.remove(wind_index); - self.window_rendering_order.push(i); + for (window_index, pos) in rendering_o.iter().enumerate().rev() { + let window = &mut self.windows[window_index]; + if window.lock().rect.detect_collision(&self.mouse) { + if window_index != self.active_window_index { + let last_one = self.window_rendering_order.len() - 1; + self.window_rendering_order.swap(last_one, *pos); } if window - .upgrade() - .unwrap() .lock() .dynamic_title_border_pos() .detect_collision(&self.mouse) { - self.mouse_holding = Holding::Window(i); + self.active_window_index = window_index; + self.mouse_holding = Holding::Window(window_index); } break; } @@ -757,7 +726,7 @@ impl WindowManager { let prev_mouse_pos = self.prev_mouse_pos; let next_mouse_pos = self.calculate_next_mouse_pos(prev_mouse_pos, screen_pos); let window = &mut self.windows[i]; - let window_rect = window.upgrade().unwrap().lock().rect; + let window_rect = window.lock().rect; let diff = next_mouse_pos - prev_mouse_pos; let mut new_pos = diff + window_rect.to_screen_pos(); @@ -781,37 +750,23 @@ impl WindowManager { new_pos.y = (SCREEN_HEIGHT - 20) as i32; } - window.upgrade().unwrap().lock().set_screen_pos(&new_pos); + window.lock().set_screen_pos(&new_pos); } } } else if mouse_event.buttons.right() { let rendering_o = self.window_rendering_order.clone(); for &i in rendering_o.iter().rev() { let window = &mut self.windows[i]; - if window - .upgrade() - .unwrap() - .lock() - .rect - .detect_collision(&Rect::new( - self.mouse.width, - self.mouse.height, - self.mouse.x, - self.mouse.y, - )) - { - window - .upgrade() - .unwrap() - .lock() - .resize_window(screen_pos.x, screen_pos.y); - window.upgrade().unwrap().lock().reset_drawable_area(); - window - .upgrade() - .unwrap() - .lock() - .reset_title_pos_and_border(); - window.upgrade().unwrap().lock().resized = true; + if window.lock().rect.detect_collision(&Rect::new( + self.mouse.width, + self.mouse.height, + self.mouse.x, + self.mouse.y, + )) { + window.lock().resize_window(screen_pos.x, screen_pos.y); + window.lock().reset_drawable_area(); + window.lock().reset_title_pos_and_border(); + window.lock().resized = true; break; } } @@ -852,6 +807,24 @@ impl Window { } } + pub fn display_window_title(&mut self, fg_color: Color, bg_color: Color) { + if let Some(title) = self.title.clone() { + let slice = title.as_str(); + let border = self.title_border(); + let title_pos = self.title_pos(&slice.len()); + print_string( + self, + border.width, + border.height, + &title_pos, + slice, + fg_color, + bg_color, + 0, + 0, + ); + } + } pub fn width(&self) -> usize { self.rect.width } @@ -959,26 +932,31 @@ impl Window { } } - fn should_resize_framebuffer(&mut self) { + fn should_resize_framebuffer(&mut self) -> Result<(), &'static str> { if self.resized { - self.resize_framebuffer(); + self.resize_framebuffer()?; self.resized = false; } + Ok(()) } /// Draws the rectangular shape representing the `Window` - pub fn draw_rectangle(&mut self, col: Color) { - self.should_resize_framebuffer(); + pub fn draw_rectangle(&mut self, col: Color) -> Result<(), &'static str> { + self.should_resize_framebuffer()?; for pixel in self.frame_buffer.buffer.iter_mut() { *pixel = col; } self.draw_title_border(); + Ok(()) } /// Resizes framebuffer after to Window's width and height - fn resize_framebuffer(&mut self) { - self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).unwrap(); + fn resize_framebuffer(&mut self) -> Result<(), &'static str> { + self.frame_buffer = VirtualFrameBuffer::new(self.rect.width, self.rect.height).or(Err( + "Unable to resize framebuffer to current width and height", + ))?; + Ok(()) } /// Returns visible part of self's `rect` with relative bounds applied @@ -1010,9 +988,10 @@ impl Window { fn port_loop( (key_consumer, mouse_consumer): (Queue, Queue), ) -> Result<(), &'static str> { - let window_manager = WINDOW_MANAGER.get().unwrap(); - let window_3 = WindowManager::new_window(&Rect::new(400, 200, 30, 100), None); - let window_2 = WindowManager::new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic"))); + let window_manager = WINDOW_MANAGER.get().ok_or("Unable to get WindowManager")?; + let window_2 = window_manager + .lock() + .new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic")))?; let text = TextDisplayInfo { width: 400, height: 400, @@ -1023,6 +1002,7 @@ fn port_loop( fg_color: DEFAULT_TEXT_COLOR, bg_color: DEFAULT_BORDER_COLOR, }; + // let window_3 = window_manager.lock().new_window(&Rect::new(100, 100, 0, 0), Some(format!("window 3")))?; let mut app = App::new(window_2, text); let hpet = get_hpet(); let mut start = hpet @@ -1078,22 +1058,21 @@ fn port_loop( window_manager .lock() .update_mouse_position(ScreenPos::new(x as i32, -(y as i32))); - window_manager - .lock() - .drag_windows(ScreenPos::new(x as i32, -(y as i32)), &mouse_event); } + window_manager + .lock() + .drag_windows(ScreenPos::new(x as i32, -(y as i32)), &mouse_event); } _ => (), } } if diff > 0 { - app.draw(); - window_3.lock().draw_rectangle(DEFAULT_WINDOW_COLOR); + app.draw()?; window_manager.lock().update(); window_manager.lock().render(); - start = hpet.as_ref().unwrap().get_counter(); + start = hpet.as_ref().ok_or("Unable to get timer")?.get_counter(); } } Ok(()) From 8fd710671affdde095bbcdb34941392c79265521 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 9 Jan 2023 13:25:59 +0300 Subject: [PATCH 25/32] apps are strong again --- applications/porthole/src/lib.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 798dea216f..051f1fbe1d 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -14,7 +14,7 @@ use core::marker::PhantomData; use core::ops::{Add, Sub}; use alloc::format; -use alloc::sync::{Arc, Weak}; +use alloc::sync::Arc; use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; @@ -58,22 +58,21 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { ] }; pub struct App { - window: Weak>, + window: Arc>, text: TextDisplayInfo, } impl App { - pub fn new(window: Weak>, text: TextDisplayInfo) -> Self { + pub fn new(window: Arc>, text: TextDisplayInfo) -> Self { Self { window, text } } pub fn draw(&mut self) -> Result<(), &'static str> { - if let Some(window) = self.window.upgrade() { - window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR)?; - window - .lock() - .display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); + let mut window = self.window.lock(); + { + window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; + window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); print_string( - &mut window.lock(), + &mut window, self.text.width, self.text.height, &self.text.pos, @@ -616,7 +615,7 @@ impl WindowManager { &mut self, rect: &Rect, title: Option, - ) -> Result>, &'static str> { + ) -> Result>, &'static str> { let len = self.windows.len(); self.window_rendering_order.push(len); @@ -626,9 +625,9 @@ impl WindowManager { title, ); let arc_window = Arc::new(Mutex::new(window)); - let weak = Arc::downgrade(&arc_window); + let returned_window = arc_window.clone(); self.windows.push(arc_window); - Ok(weak) + Ok(returned_window) } fn draw_windows(&mut self) { From 529f173cb8715c234f4f47691fd6cfb7e17b8640 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 9 Jan 2023 20:08:43 +0300 Subject: [PATCH 26/32] use iterator to draw mouse --- applications/porthole/src/lib.rs | 85 +++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 051f1fbe1d..2981e38518 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(slice_ptr_get)] +#![feature(slice_flatten)] extern crate alloc; extern crate device_manager; extern crate hpet; @@ -10,11 +11,10 @@ extern crate multicore_bringup; extern crate scheduler; extern crate spin; extern crate task; -use core::marker::PhantomData; -use core::ops::{Add, Sub}; - use alloc::format; use alloc::sync::Arc; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; @@ -57,6 +57,7 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { [T, T, T, T, T, T, T, T, T, T, B, T, T, T, T, T, T, T], ] }; + pub struct App { window: Arc>, text: TextDisplayInfo, @@ -372,13 +373,6 @@ impl VirtualFrameBuffer { } } - fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { - unsafe { - let index = (self.width * y as usize) + x as usize; - let pixel = self.buffer.get_unchecked_mut(index); - *pixel = col; - } - } pub fn blank(&mut self) { for pixel in self.buffer.iter_mut() { *pixel = 0x000000; @@ -470,6 +464,60 @@ impl PhysicalFrameBuffer { } } +/// Our mouse image is [`MOUSE_POINTER_IMAGE`] column major 2D array +/// This type returns us row major, 1D vec of that image +pub struct MouseImageRowIterator<'a> { + /// Mouse image [`MOUSE_POINTER_IMAGE`] + mouse_image: &'a [[u32; 18]; 11], + /// Rect of our mouse + bounding_box: Rect, + /// Since image is column major we will iterate will use + /// individual columns to create a row, think of it as y axis + current_column: usize, + /// Used to traverse image in x axis + current_row: usize, +} + +impl<'a> MouseImageRowIterator<'a> { + fn new(mouse_image: &'a [[u32; 18]; 11], bounding_box: Rect) -> Self { + Self { + mouse_image, + bounding_box, + current_column: 0, + current_row: 0, + } + } +} + +impl<'a> Iterator for MouseImageRowIterator<'a> { + type Item = Vec; + + fn next(&mut self) -> Option> { + // We start from MOUSE_POINTER_IMAGE[0][0], get the color on that index push it to our `row` + // then move to MOUSE_POINTER_IMAGE[1][0] do the same thing + // until we hit `bounding_box.width -1` then we reset our `current_column` to `0` and increase + // our `current_row` by `1` + if self.current_row < self.bounding_box.height - 1 { + let mut row = Vec::new(); + while self.current_column < self.bounding_box.width { + let color = unsafe { + self.mouse_image.get_unchecked(self.current_column)[self.current_row] + }; + row.push(color); + self.current_column += 1; + if self.current_column == self.bounding_box.width - 1 { + self.current_column = 0; + break; + } + } + self.current_row += 1; + Some(row) + } else { + None + } + } +} + struct FramebufferRowChunks<'a, T: 'a> { fb: *mut [T], rect: Rect, @@ -640,15 +688,18 @@ impl WindowManager { } } - // TODO: Stop indexing mouse image create iterator for it, also draw the thing with iterators fn draw_mouse(&mut self) { let bounding_box = self.mouse.visible_rect(); - for y in bounding_box.y..bounding_box.y + bounding_box.height as isize { - for x in bounding_box.x..bounding_box.x + bounding_box.width as isize { - let color = MOUSE_POINTER_IMAGE[(x - bounding_box.x) as usize] - [(y - bounding_box.y) as usize]; - if color != 0xFF0000 { - self.v_framebuffer.draw_unchecked(x, y, color); + + let mouse_image = MouseImageRowIterator::new(&MOUSE_POINTER_IMAGE, bounding_box); + let chunker = + FramebufferRowChunks::new(&mut self.v_framebuffer.buffer, bounding_box, SCREEN_WIDTH) + .unwrap(); + + for (screen_row, mouse_image_row) in chunker.zip(mouse_image) { + for (screen_pixel, mouse_pixel) in screen_row.iter_mut().zip(mouse_image_row.iter()) { + if mouse_pixel != &0xFF0000 { + *screen_pixel = *mouse_pixel; } } } From 8d53776085f7291fb98448e01f3a912da8d2425c Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 10 Jan 2023 01:08:25 +0300 Subject: [PATCH 27/32] don't use unsafe when rendering text --- applications/porthole/src/lib.rs | 140 ++++++++++++++++++------------- 1 file changed, 84 insertions(+), 56 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 2981e38518..efbc1b0c6f 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -15,6 +15,7 @@ use alloc::format; use alloc::sync::Arc; use core::marker::PhantomData; use core::ops::{Add, Sub}; +use core::slice::IterMut; use log::{debug, info}; use spin::{Mutex, MutexGuard, Once}; @@ -71,44 +72,52 @@ impl App { let mut window = self.window.lock(); { window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; - window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); + //window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); print_string( &mut window, - self.text.width, - self.text.height, &self.text.pos, &self.text.text, self.text.fg_color, self.text.bg_color, - self.text.next_col, - self.text.next_line, - ); + )?; } Ok(()) } } +/// Prints a line of string from the start of the Window +/// +/// *Prints from left -> right* +/// +/// * `window` - Window we are printing to. +/// * `position` - This indicates where line will be. +/// * `slice` - Text we are printing +/// * `fg_color` - Foreground color of the text +/// * `bg_color` - Background color of the text pub fn print_string( window: &mut Window, - width: usize, - height: usize, - pos: &RelativePos, + position: &RelativePos, slice: &str, fg_color: Color, bg_color: Color, - column: usize, - line: usize, -) { +) -> Result<(), &'static str> { let slice = slice.as_bytes(); - let start_x = pos.x + (column as u32 * CHARACTER_WIDTH as u32); - let start_y = pos.y + (line as u32 * CHARACTER_HEIGHT as u32); + let start_y = position.y; let mut x_index = 0; let mut row_controller = 0; let mut char_index = 0; let mut char_color_on_x_axis = x_index; + + let window_width = window.width(); + let mut row_of_pixels = FramebufferRowChunks::get_a_row( + &mut window.frame_buffer.buffer, + window.rect, + window_width, + start_y as usize, + )?; + loop { - let x = start_x + x_index as u32; let y = start_y + row_controller as u32; if x_index % CHARACTER_WIDTH == 0 { char_color_on_x_axis = 0; @@ -126,13 +135,14 @@ pub fn print_string( char_color_on_x_axis += 1; bg_color }; - window.draw_unchecked(&RelativePos::new(x, y), color); + + // Altough bit ugly, this works quite well with our current way of rendering fonts + if let Some(pixel) = row_of_pixels.next() { + *pixel = color; + } x_index += 1; - if x_index == CHARACTER_WIDTH - || x_index % CHARACTER_WIDTH == 0 - || start_x + x_index as u32 == width as u32 - { + if x_index == CHARACTER_WIDTH || x_index % CHARACTER_WIDTH == 0 { if slice.len() >= 1 && char_index < slice.len() - 1 { char_index += 1; } @@ -140,18 +150,23 @@ pub fn print_string( if x_index >= CHARACTER_WIDTH * slice.len() && x_index % (CHARACTER_WIDTH * slice.len()) == 0 { + row_of_pixels = FramebufferRowChunks::get_a_row( + &mut window.frame_buffer.buffer, + window.rect, + window_width, + y as usize, + )?; row_controller += 1; char_index = 0; x_index = 0; } - if row_controller == CHARACTER_HEIGHT - || start_y + row_controller as u32 == height as u32 - { + if row_controller == CHARACTER_HEIGHT { break; } } } + Ok(()) } fn get_bit(char_font: u8, i: usize) -> u8 { char_font & (0x80 >> i) @@ -518,7 +533,7 @@ impl<'a> Iterator for MouseImageRowIterator<'a> { } } -struct FramebufferRowChunks<'a, T: 'a> { +pub struct FramebufferRowChunks<'a, T: 'a> { fb: *mut [T], rect: Rect, stride: usize, @@ -549,6 +564,36 @@ impl<'a, T: 'a> FramebufferRowChunks<'a, T> { } } + pub fn get_a_row( + slice: &'a mut [T], + rect: Rect, + stride: usize, + row: usize, + ) -> Result, &'static str> { + if rect.width <= stride { + let mut rect = rect; + rect.y = row as isize; + rect.height = 1; + let current_column = rect.y as usize; + let row_index_beg = stride * current_column; + let row_index_end = (stride * current_column) + rect.width as usize; + let mut row = Some(Self { + fb: slice, + rect, + stride, + row_index_beg, + row_index_end, + current_column, + _marker: PhantomData, + }) + .ok_or("Unable to get a row of pixels from given row")?; + let row_iterator = row.next().ok_or("Error created empty row")?.iter_mut(); + Ok(row_iterator) + } else { + Err("Unable to create row if given width is bigger than stride") + } + } + fn calculate_next_row(&mut self) { self.row_index_beg = (self.stride * self.current_column) + self.rect.x as usize; self.row_index_end = @@ -857,23 +902,17 @@ impl Window { } } - pub fn display_window_title(&mut self, fg_color: Color, bg_color: Color) { + pub fn display_window_title( + &mut self, + fg_color: Color, + bg_color: Color, + ) -> Result<(), &'static str> { if let Some(title) = self.title.clone() { let slice = title.as_str(); - let border = self.title_border(); let title_pos = self.title_pos(&slice.len()); - print_string( - self, - border.width, - border.height, - &title_pos, - slice, - fg_color, - bg_color, - 0, - 0, - ); + print_string(self, &title_pos, slice, fg_color, bg_color)?; } + Ok(()) } pub fn width(&self) -> usize { self.rect.width @@ -971,17 +1010,6 @@ impl Window { } } - // TODO: look into this - fn draw_unchecked(&mut self, relative_pos: &RelativePos, col: Color) { - let x = relative_pos.x; - let y = relative_pos.y; - unsafe { - let index = (self.frame_buffer.width * y as usize) + x as usize; - let pixel = self.frame_buffer.buffer.get_unchecked_mut(index); - *pixel = col; - } - } - fn should_resize_framebuffer(&mut self) -> Result<(), &'static str> { if self.resized { self.resize_framebuffer()?; @@ -1042,17 +1070,17 @@ fn port_loop( let window_2 = window_manager .lock() .new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic")))?; + let drawable_area = window_2.lock().drawable_area(); let text = TextDisplayInfo { - width: 400, - height: 400, - pos: RelativePos::new(0, 0), - next_col: 1, - next_line: 1, - text: "Hello World".to_string(), + width: drawable_area.width, + height: drawable_area.height, + pos: RelativePos::new(drawable_area.x as u32, drawable_area.y as u32), + next_col: 0, + next_line: 0, + text: "Helloaaaaaaaaaaaa World".to_string(), fg_color: DEFAULT_TEXT_COLOR, - bg_color: DEFAULT_BORDER_COLOR, + bg_color: DEFAULT_WINDOW_COLOR, }; - // let window_3 = window_manager.lock().new_window(&Rect::new(100, 100, 0, 0), Some(format!("window 3")))?; let mut app = App::new(window_2, text); let hpet = get_hpet(); let mut start = hpet From 6d29a72efa64073336881e4f15bdd83db7ef0266 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 10 Jan 2023 01:11:59 +0300 Subject: [PATCH 28/32] handle unwrap --- applications/porthole/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index efbc1b0c6f..4673762924 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -736,15 +736,16 @@ impl WindowManager { fn draw_mouse(&mut self) { let bounding_box = self.mouse.visible_rect(); - let mouse_image = MouseImageRowIterator::new(&MOUSE_POINTER_IMAGE, bounding_box); - let chunker = + if let Some(screen_rows) = FramebufferRowChunks::new(&mut self.v_framebuffer.buffer, bounding_box, SCREEN_WIDTH) - .unwrap(); - - for (screen_row, mouse_image_row) in chunker.zip(mouse_image) { - for (screen_pixel, mouse_pixel) in screen_row.iter_mut().zip(mouse_image_row.iter()) { - if mouse_pixel != &0xFF0000 { - *screen_pixel = *mouse_pixel; + { + let mouse_image = MouseImageRowIterator::new(&MOUSE_POINTER_IMAGE, bounding_box); + for (screen_row, mouse_image_row) in screen_rows.zip(mouse_image) { + for (screen_pixel, mouse_pixel) in screen_row.iter_mut().zip(mouse_image_row.iter()) + { + if mouse_pixel != &0xFF0000 { + *screen_pixel = *mouse_pixel; + } } } } From 6eccb691c781291ce4b94b13c8a9e63c9034f3ab Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 10 Jan 2023 02:29:01 +0300 Subject: [PATCH 29/32] refactor --- applications/porthole/src/lib.rs | 196 ++++++++++++++++++------------- 1 file changed, 112 insertions(+), 84 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 4673762924..6ef031164f 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -33,8 +33,12 @@ static TITLE_BAR_HEIGHT: usize = 20; static SCREEN_WIDTH: usize = 1024; static SCREEN_HEIGHT: usize = 768; -// We could do some fancy stuff with this like a trait, that can convert rgb to hex -// hex to rgb hsl etc, but for now it feels like bikeshedding +/// Controls amount of visible `Window` we see when we move a `Window` out of the screen +static WINDOW_VISIBLE_GAP: i32 = 20; + +/// Controls amount of visible mouse we see when we move the mouse out of the screen +static MOUSE_VISIBLE_GAP: i32 = 3; + type Color = u32; static DEFAULT_BORDER_COLOR: Color = 0x141414; static DEFAULT_TEXT_COLOR: Color = 0xFBF1C7; @@ -72,7 +76,7 @@ impl App { let mut window = self.window.lock(); { window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; - //window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR); + window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR)?; print_string( &mut window, &self.text.pos, @@ -85,12 +89,10 @@ impl App { } } -/// Prints a line of string from the start of the Window +/// Prints a line of string to the `Window` /// -/// *Prints from left -> right* -/// /// * `window` - Window we are printing to. -/// * `position` - This indicates where line will be. +/// * `position` - This indicates where line of text will be. /// * `slice` - Text we are printing /// * `fg_color` - Foreground color of the text /// * `bg_color` - Background color of the text @@ -102,6 +104,7 @@ pub fn print_string( bg_color: Color, ) -> Result<(), &'static str> { let slice = slice.as_bytes(); + let start_x = position.x; let start_y = position.y; let mut x_index = 0; @@ -109,11 +112,12 @@ pub fn print_string( let mut char_index = 0; let mut char_color_on_x_axis = x_index; - let window_width = window.width(); - let mut row_of_pixels = FramebufferRowChunks::get_a_row( + let mut window_rect = window.rect; + window_rect.set_position(start_x, start_y); + let mut row_of_pixels = FramebufferRowChunks::get_exact_row( &mut window.frame_buffer.buffer, - window.rect, - window_width, + window_rect, + window_rect.width, start_y as usize, )?; @@ -124,6 +128,7 @@ pub fn print_string( } let color = if char_color_on_x_axis >= 1 { let index = char_color_on_x_axis - 1; + // TODO: Stop indexing here let char_font = FONT_BASIC[slice[char_index] as usize][row_controller]; char_color_on_x_axis += 1; if get_bit(char_font, index) != 0 { @@ -150,10 +155,10 @@ pub fn print_string( if x_index >= CHARACTER_WIDTH * slice.len() && x_index % (CHARACTER_WIDTH * slice.len()) == 0 { - row_of_pixels = FramebufferRowChunks::get_a_row( + row_of_pixels = FramebufferRowChunks::get_exact_row( &mut window.frame_buffer.buffer, - window.rect, - window_width, + window_rect, + window_rect.width, y as usize, )?; row_controller += 1; @@ -303,6 +308,11 @@ impl Rect { } } + pub fn set_position(&mut self, x: u32, y: u32) { + self.x = x as isize; + self.y = y as isize; + } + fn x_plus_width(&self) -> isize { self.x + self.width as isize } @@ -318,21 +328,33 @@ impl Rect { && self.y_plus_height() > other.y } + pub fn left_side_out(&self) -> bool { + self.x < 0 + } + + pub fn right_side_out(&self) -> bool { + self.x + self.width as isize > SCREEN_WIDTH as isize + } + + pub fn bottom_side_out(&self) -> bool { + self.y + self.height as isize > SCREEN_HEIGHT as isize + } + /// Creates a new `Rect` from visible parts of itself. pub fn visible_rect(&self) -> Rect { let mut x = self.x; let y = self.y; let mut width = self.width as isize; let mut height = self.height as isize; - if self.x < 0 { + if self.left_side_out() { x = 0; width = self.x_plus_width(); - } else if self.x_plus_width() > SCREEN_WIDTH as isize { + } else if self.right_side_out() { x = self.x; let gap = (self.x + self.width as isize) - SCREEN_WIDTH as isize; width = self.width as isize - gap; } - if self.y_plus_height() > SCREEN_HEIGHT as isize { + if self.bottom_side_out() { let gap = (self.y + self.height as isize) - SCREEN_HEIGHT as isize; height = self.height as isize - gap; } @@ -533,12 +555,23 @@ impl<'a> Iterator for MouseImageRowIterator<'a> { } } +/// From given mutable `Framebuffer` slice and `Rect` returns +/// rows of slices. +/// +/// Think `Framebuffer` as a big cake and `Rect` as a smaller cake within the `Framebuffer` +/// this returns row of mutable slices from that smaller cake. pub struct FramebufferRowChunks<'a, T: 'a> { + /// Framebuffer we used to get the `rows` from fb: *mut [T], + /// This let's us decide where and how big of a row we want to get rect: Rect, + /// Amount of pixels in a line of `Framebuffer` stride: usize, + /// Where we start the row row_index_beg: usize, + /// Where we end the row row_index_end: usize, + /// The index of the row we are getting current_column: usize, _marker: PhantomData<&'a mut T>, } @@ -564,34 +597,22 @@ impl<'a, T: 'a> FramebufferRowChunks<'a, T> { } } - pub fn get_a_row( + /// Returns a single `IterMut` from specified `row` of the framebuffer + /// + /// * `row` - Specifies which row will be returned from this function + pub fn get_exact_row( slice: &'a mut [T], rect: Rect, stride: usize, row: usize, ) -> Result, &'static str> { - if rect.width <= stride { - let mut rect = rect; - rect.y = row as isize; - rect.height = 1; - let current_column = rect.y as usize; - let row_index_beg = stride * current_column; - let row_index_end = (stride * current_column) + rect.width as usize; - let mut row = Some(Self { - fb: slice, - rect, - stride, - row_index_beg, - row_index_end, - current_column, - _marker: PhantomData, - }) - .ok_or("Unable to get a row of pixels from given row")?; - let row_iterator = row.next().ok_or("Error created empty row")?.iter_mut(); - Ok(row_iterator) - } else { - Err("Unable to create row if given width is bigger than stride") - } + let mut rect = rect; + rect.y = row as isize; + rect.height = 1; + let mut rows = FramebufferRowChunks::new(slice, rect, stride) + .ok_or("Couldn't create `FramebufferRowChunks` from given rect")?; + let row_iterator = rows.next().ok_or("Error created empty row")?.iter_mut(); + Ok(row_iterator) } fn calculate_next_row(&mut self) { @@ -680,6 +701,7 @@ pub struct WindowManager { pub mouse: Rect, prev_mouse_pos: ScreenPos, mouse_holding: Holding, + /// Holds the index of the active window/last element in the `window_rendering_order` active_window_index: usize, } @@ -687,7 +709,7 @@ impl WindowManager { fn init() -> Result<(), &'static str> { let p_framebuffer = PhysicalFrameBuffer::init_front_buffer()?; let v_framebuffer = VirtualFrameBuffer::new(p_framebuffer.width, p_framebuffer.height)?; - // FIXME: Don't use magic numbers + // FIXME: Don't use magic numbers, let mouse = Rect::new(11, 18, 200, 200); let window_manager = WindowManager { @@ -727,6 +749,7 @@ impl WindowManager { for order in self.window_rendering_order.iter() { self.v_framebuffer .copy_window_into_main_vbuffer(&mut self.windows[*order].lock()); + // TODO: Stop indexing ^ here } for window in self.windows.iter() { window.lock().blank(); @@ -734,12 +757,12 @@ impl WindowManager { } fn draw_mouse(&mut self) { - let bounding_box = self.mouse.visible_rect(); + let visible_mouse = self.mouse.visible_rect(); if let Some(screen_rows) = - FramebufferRowChunks::new(&mut self.v_framebuffer.buffer, bounding_box, SCREEN_WIDTH) + FramebufferRowChunks::new(&mut self.v_framebuffer.buffer, visible_mouse, SCREEN_WIDTH) { - let mouse_image = MouseImageRowIterator::new(&MOUSE_POINTER_IMAGE, bounding_box); + let mouse_image = MouseImageRowIterator::new(&MOUSE_POINTER_IMAGE, visible_mouse); for (screen_row, mouse_image_row) in screen_rows.zip(mouse_image) { for (screen_pixel, mouse_pixel) in screen_row.iter_mut().zip(mouse_image_row.iter()) { @@ -751,9 +774,9 @@ impl WindowManager { } } - pub fn set_mouse_pos(&mut self, screen_pos: &ScreenPos) { - self.mouse.x = screen_pos.x as isize; - self.mouse.y = screen_pos.y as isize; + pub fn set_mouse_pos(&mut self, screen_positon: &ScreenPos) { + self.mouse.x = screen_positon.x as isize; + self.mouse.y = screen_positon.y as isize; } fn update(&mut self) { @@ -762,23 +785,32 @@ impl WindowManager { self.draw_mouse(); } - fn calculate_next_mouse_pos(&self, curr_pos: ScreenPos, next_pos: ScreenPos) -> ScreenPos { - let mut new_pos = next_pos + curr_pos; + fn calculate_next_mouse_pos( + &self, + current_position: ScreenPos, + next_position: ScreenPos, + ) -> ScreenPos { + let mut new_pos = next_position + current_position; // handle left new_pos.x = core::cmp::max(new_pos.x, 0); // handle right - new_pos.x = core::cmp::min(new_pos.x, self.v_framebuffer.width as i32 - 3); + new_pos.x = core::cmp::min( + new_pos.x, + self.v_framebuffer.width as i32 - MOUSE_VISIBLE_GAP, + ); // handle top new_pos.y = core::cmp::max(new_pos.y, 0); // handle bottom - new_pos.y = core::cmp::min(new_pos.y, self.v_framebuffer.height as i32 - 3); + new_pos.y = core::cmp::min( + new_pos.y, + self.v_framebuffer.height as i32 - MOUSE_VISIBLE_GAP, + ); new_pos } - // TODO: Remove magic numbers fn update_mouse_position(&mut self, screen_pos: ScreenPos) { self.prev_mouse_pos = self.mouse.to_screen_pos(); let new_pos = self.calculate_next_mouse_pos(self.mouse.to_screen_pos(), screen_pos); @@ -786,18 +818,21 @@ impl WindowManager { self.set_mouse_pos(&new_pos); } - fn drag_windows(&mut self, screen_pos: ScreenPos, mouse_event: &MouseEvent) { + fn drag_windows(&mut self, screen_position: ScreenPos, mouse_event: &MouseEvent) { if mouse_event.buttons.left() { match self.mouse_holding { Holding::Background => {} Holding::Nothing => { - let rendering_o = self.window_rendering_order.clone(); - for (window_index, pos) in rendering_o.iter().enumerate().rev() { + let rendering_order = self.window_rendering_order.clone(); + for (window_index, position_in_iter) in rendering_order.iter().enumerate().rev() + { let window = &mut self.windows[window_index]; if window.lock().rect.detect_collision(&self.mouse) { if window_index != self.active_window_index { + // FIXME: This is half-broken, doesn't handle multiple windows correctly let last_one = self.window_rendering_order.len() - 1; - self.window_rendering_order.swap(last_one, *pos); + self.window_rendering_order + .swap(last_one, *position_in_iter); } if window .lock() @@ -820,20 +855,21 @@ impl WindowManager { // These calculations are required because we do want finer control // over a window's movement. let prev_mouse_pos = self.prev_mouse_pos; - let next_mouse_pos = self.calculate_next_mouse_pos(prev_mouse_pos, screen_pos); + let next_mouse_pos = + self.calculate_next_mouse_pos(prev_mouse_pos, screen_position); let window = &mut self.windows[i]; let window_rect = window.lock().rect; let diff = next_mouse_pos - prev_mouse_pos; let mut new_pos = diff + window_rect.to_screen_pos(); //handle left - if (new_pos.x + (window_rect.width as i32 - 20)) < 0 { - new_pos.x = -(window_rect.width as i32 - 20); + if (new_pos.x + (window_rect.width as i32 - WINDOW_VISIBLE_GAP as i32)) < 0 { + new_pos.x = -(window_rect.width as i32 - WINDOW_VISIBLE_GAP); } //handle right - if (new_pos.x + 20) > self.v_framebuffer.width as i32 { - new_pos.x = SCREEN_WIDTH as i32 - 20 + if (new_pos.x + WINDOW_VISIBLE_GAP) > self.v_framebuffer.width as i32 { + new_pos.x = SCREEN_WIDTH as i32 - WINDOW_VISIBLE_GAP } //handle top @@ -842,8 +878,8 @@ impl WindowManager { } // handle bottom - if new_pos.y + 20 > self.v_framebuffer.height as i32 { - new_pos.y = (SCREEN_HEIGHT - 20) as i32; + if new_pos.y + WINDOW_VISIBLE_GAP > self.v_framebuffer.height as i32 { + new_pos.y = (SCREEN_HEIGHT as i32 - WINDOW_VISIBLE_GAP) as i32; } window.lock().set_screen_pos(&new_pos); @@ -859,7 +895,9 @@ impl WindowManager { self.mouse.x, self.mouse.y, )) { - window.lock().resize_window(screen_pos.x, screen_pos.y); + window + .lock() + .resize_window(screen_position.x, screen_position.y); window.lock().reset_drawable_area(); window.lock().reset_title_pos_and_border(); window.lock().resized = true; @@ -928,9 +966,9 @@ impl Window { screen_pos } - pub fn set_screen_pos(&mut self, screen_pos: &ScreenPos) { - self.rect.x = screen_pos.x as isize; - self.rect.y = screen_pos.y as isize; + pub fn set_screen_pos(&mut self, screen_position: &ScreenPos) { + self.rect.x = screen_position.x as isize; + self.rect.y = screen_position.y as isize; } pub fn blank(&mut self) { @@ -986,10 +1024,11 @@ impl Window { *drawable_area } - pub fn title_pos(&mut self, slice_len: &usize) -> RelativePos { + /// From given title length returns center position of the title border + pub fn title_pos(&mut self, title_length: &usize) -> RelativePos { let border = self.title_border(); let relative_pos = self.title_pos.get_or_insert({ - let pos = (border.width - (slice_len * CHARACTER_WIDTH)) / 2; + let pos = (border.width - (title_length * CHARACTER_WIDTH)) / 2; let relative_pos = RelativePos::new(pos as u32, 0); relative_pos }); @@ -1020,11 +1059,11 @@ impl Window { } /// Draws the rectangular shape representing the `Window` - pub fn draw_rectangle(&mut self, col: Color) -> Result<(), &'static str> { + pub fn draw_rectangle(&mut self, color: Color) -> Result<(), &'static str> { self.should_resize_framebuffer()?; for pixel in self.frame_buffer.buffer.iter_mut() { - *pixel = col; + *pixel = color; } self.draw_title_border(); Ok(()) @@ -1044,24 +1083,12 @@ impl Window { pub fn relative_visible_rect(&self) -> Rect { let mut bounding_box = self.rect.visible_rect(); bounding_box.x = 0; - if self.left_side_out() { + if self.rect.left_side_out() { bounding_box.x = (self.rect.width - bounding_box.width) as isize; } bounding_box.y = 0; bounding_box } - - pub fn left_side_out(&self) -> bool { - self.rect.x < 0 - } - - pub fn right_side_out(&self) -> bool { - self.rect.x + self.rect.width as isize > SCREEN_WIDTH as isize - } - - pub fn bottom_side_out(&self) -> bool { - self.rect.y + self.rect.height as isize > SCREEN_HEIGHT as isize - } } fn port_loop( @@ -1072,6 +1099,7 @@ fn port_loop( .lock() .new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic")))?; let drawable_area = window_2.lock().drawable_area(); + let text = TextDisplayInfo { width: drawable_area.width, height: drawable_area.height, From 7e92836eb21b4b512c86960e68e3bb29e7c40a77 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 10 Jan 2023 20:26:57 +0300 Subject: [PATCH 30/32] fix window dragging and rendering order bug --- applications/porthole/src/lib.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index 6ef031164f..d80970083e 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -652,6 +652,7 @@ pub fn main(_args: Vec) -> Result { let _task_ref = match spawn::new_task_builder(port_loop, (mouse_consumer, key_consumer)) .name("port_loop".to_string()) + .pin_on_core(0) .spawn() { Ok(task_ref) => task_ref, @@ -819,27 +820,36 @@ impl WindowManager { } fn drag_windows(&mut self, screen_position: ScreenPos, mouse_event: &MouseEvent) { + if !mouse_event.buttons.left() { + self.mouse_holding = Holding::Nothing; + } if mouse_event.buttons.left() { match self.mouse_holding { Holding::Background => {} Holding::Nothing => { + // We are cloning this value because we will use it to iterate through our windows while editing the original one let rendering_order = self.window_rendering_order.clone(); - for (window_index, position_in_iter) in rendering_order.iter().enumerate().rev() - { + // `iter_index` = index of the window in `self.window_rendering_order` + // `window_index` = index of the window in `self.windows` + for (iter_index, &window_index) in rendering_order.iter().enumerate().rev() { let window = &mut self.windows[window_index]; if window.lock().rect.detect_collision(&self.mouse) { + // If colliding window is not active one make it active + // we first remove colliding window from it's position in + // window_rendering_order, then push it to the back of + // window_rendering_order, this way we don't have to do any special sorting if window_index != self.active_window_index { - // FIXME: This is half-broken, doesn't handle multiple windows correctly - let last_one = self.window_rendering_order.len() - 1; - self.window_rendering_order - .swap(last_one, *position_in_iter); + self.active_window_index = window_index; + self.window_rendering_order.remove(iter_index); + self.window_rendering_order.push(window_index); } + // If user is holding the window from it's title border pos + // it means user wants to move the window if window .lock() .dynamic_title_border_pos() .detect_collision(&self.mouse) { - self.active_window_index = window_index; self.mouse_holding = Holding::Window(window_index); } break; @@ -905,9 +915,6 @@ impl WindowManager { } } } - if !mouse_event.buttons.left() { - self.mouse_holding = Holding::Nothing; - } } #[inline] @@ -1099,7 +1106,6 @@ fn port_loop( .lock() .new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic")))?; let drawable_area = window_2.lock().drawable_area(); - let text = TextDisplayInfo { width: drawable_area.width, height: drawable_area.height, @@ -1173,7 +1179,6 @@ fn port_loop( _ => (), } } - if diff > 0 { app.draw()?; window_manager.lock().update(); From ed74e2059798aac000f7255b7fa72e2924d38bfa Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 11 Jan 2023 01:20:53 +0300 Subject: [PATCH 31/32] a little cleanup and a small fps counter app --- applications/porthole/src/lib.rs | 188 +++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 44 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index d80970083e..a5948ba82a 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -17,7 +17,7 @@ use core::marker::PhantomData; use core::ops::{Add, Sub}; use core::slice::IterMut; use log::{debug, info}; -use spin::{Mutex, MutexGuard, Once}; +use spin::{Mutex, MutexGuard, Once, RwLockReadGuard}; use event_types::Event; use mpmc::Queue; @@ -25,8 +25,10 @@ use mpmc::Queue; use alloc::string::{String, ToString}; use alloc::vec::Vec; use font::{CHARACTER_HEIGHT, CHARACTER_WIDTH, FONT_BASIC}; -use hpet::get_hpet; -use memory::{BorrowedSliceMappedPages, Mutable, PhysicalAddress, PteFlags, PteFlagsArch}; +use hpet::{get_hpet, Hpet}; +use memory::{ + BorrowedMappedPages, BorrowedSliceMappedPages, Mutable, PhysicalAddress, PteFlags, PteFlagsArch, +}; use mouse_data::MouseEvent; pub static WINDOW_MANAGER: Once> = Once::new(); static TITLE_BAR_HEIGHT: usize = 20; @@ -63,6 +65,118 @@ static MOUSE_POINTER_IMAGE: [[u32; 18]; 11] = { ] }; +// Useful toy application that shows the real time performance +pub struct FpsCounter { + window: Arc>, + hpet: RwLockReadGuard<'static, BorrowedMappedPages>, + time_it_took_to_render: u64, + timer_freq: u64, + total_frames: u64, + total_time: u64, + avg_fps: u64, + avg_time: u64, + avg_fps_str: String, + avg_time_str: String, +} + +impl FpsCounter { + pub fn new(window: Arc>) -> Result { + let hpet = get_hpet().ok_or("Unable to get hpet")?; + let time_it_took_to_render = hpet.get_counter(); + let timer_freq = hpet.counter_period_femtoseconds() as u64; + Ok(Self { + window, + hpet, + time_it_took_to_render, + timer_freq, + total_frames: 0, + total_time: 0, + avg_fps: 0, + avg_time: 0, + avg_fps_str: format!("Frames per second:"), + avg_time_str: format!("Median frame time in micro seconds:"), + }) + } + + fn calculate_next_frame_time(&mut self) { + let time = self.hpet.get_counter(); + let diff = (time - self.time_it_took_to_render) * self.timer_freq / 1_000_000_000; + self.total_time += diff; + self.time_it_took_to_render = time; + self.total_frames += 1; + } + + fn reset_counters(&mut self) { + // this equals to a second + if self.total_time >= 1_000_000 { + self.avg_fps = self.total_frames; + self.avg_time = self.total_time / self.total_frames; + self.total_time = 0; + self.total_frames = 0; + } + } + + pub fn run(&mut self) -> Result<(), &'static str> { + self.calculate_next_frame_time(); + self.reset_counters(); + self.draw()?; + Ok(()) + } + + fn draw(&mut self) -> Result<(), &'static str> { + self.window.lock().draw_rectangle(DEFAULT_WINDOW_COLOR)?; + self.window + .lock() + .display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR)?; + self.print_avg_fps()?; + self.print_avg_time()?; + Ok(()) + } + + fn print_avg_fps(&mut self) -> Result<(), &'static str> { + let mut drawable_area = self.window.lock().drawable_area().to_relative_pos(); + let avg_fps = self.avg_fps.to_string(); + print_string( + &mut self.window.lock(), + &drawable_area, + &self.avg_fps_str, + 0xF8FF0E, + DEFAULT_WINDOW_COLOR, + )?; + drawable_area.x = (CHARACTER_WIDTH * self.avg_fps_str.len()) as u32; + print_string( + &mut self.window.lock(), + &drawable_area, + &avg_fps, + 0x20F065, + DEFAULT_WINDOW_COLOR, + )?; + Ok(()) + } + + fn print_avg_time(&mut self) -> Result<(), &'static str> { + let mut drawable_area = self.window.lock().drawable_area().to_relative_pos(); + drawable_area.y += (CHARACTER_HEIGHT + 1) as u32; + let avg_time = self.avg_time.to_string(); + print_string( + &mut self.window.lock(), + &drawable_area, + &self.avg_time_str, + 0xF8FF0E, + DEFAULT_WINDOW_COLOR, + )?; + drawable_area.x = (CHARACTER_WIDTH * self.avg_time_str.len()) as u32; + print_string( + &mut self.window.lock(), + &drawable_area, + &avg_time, + 0x20F065, + DEFAULT_WINDOW_COLOR, + )?; + Ok(()) + } +} + pub struct App { window: Arc>, text: TextDisplayInfo, @@ -74,17 +188,16 @@ impl App { } pub fn draw(&mut self) -> Result<(), &'static str> { let mut window = self.window.lock(); - { - window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; - window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR)?; - print_string( - &mut window, - &self.text.pos, - &self.text.text, - self.text.fg_color, - self.text.bg_color, - )?; - } + + window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; + window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR)?; + print_string( + &mut window, + &self.text.pos, + &self.text.text, + self.text.fg_color, + self.text.bg_color, + )?; Ok(()) } } @@ -104,6 +217,7 @@ pub fn print_string( bg_color: Color, ) -> Result<(), &'static str> { let slice = slice.as_bytes(); + // FIXME: Text starts overlapping if x + text len is bigger than window.width let start_x = position.x; let start_y = position.y; @@ -217,7 +331,7 @@ impl TextDisplayInfo { } /// Position that is relative to a `Window` -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct RelativePos { pub x: u32, pub y: u32, @@ -308,6 +422,12 @@ impl Rect { } } + pub fn to_relative_pos(&self) -> RelativePos { + let x = core::cmp::max(0, self.x) as u32; + let y = core::cmp::min(SCREEN_HEIGHT as isize, self.y) as u32; + RelativePos { x, y } + } + pub fn set_position(&mut self, x: u32, y: u32) { self.x = x as isize; self.y = y as isize; @@ -752,9 +872,6 @@ impl WindowManager { .copy_window_into_main_vbuffer(&mut self.windows[*order].lock()); // TODO: Stop indexing ^ here } - for window in self.windows.iter() { - window.lock().blank(); - } } fn draw_mouse(&mut self) { @@ -917,7 +1034,6 @@ impl WindowManager { } } - #[inline] fn render(&mut self) { self.p_framebuffer .buffer @@ -978,16 +1094,10 @@ impl Window { self.rect.y = screen_position.y as isize; } - pub fn blank(&mut self) { - for pixel in self.frame_buffer.buffer.iter_mut() { - *pixel = 0x000000; - } - } - pub fn resize_window(&mut self, width: i32, height: i32) { let new_width = self.width() + width as usize; let new_height = self.height() + height as usize; - if new_width > 50 && new_height > 50 { + if new_width > 200 && new_height > 200 { self.rect.width = new_width; self.rect.height = new_height; } @@ -1117,19 +1227,12 @@ fn port_loop( bg_color: DEFAULT_WINDOW_COLOR, }; let mut app = App::new(window_2, text); - let hpet = get_hpet(); - let mut start = hpet - .as_ref() - .ok_or("couldn't get HPET timer")? - .get_counter(); - let hpet_freq = hpet.as_ref().ok_or("ss")?.counter_period_femtoseconds() as u64; + let window_3 = window_manager + .lock() + .new_window(&Rect::new(400, 100, 0, 0), Some(format!("Fps Counter")))?; + let mut fps_counter = FpsCounter::new(window_3)?; loop { - let end = hpet - .as_ref() - .ok_or("couldn't get HPET timer")? - .get_counter(); - let diff = (end - start) * hpet_freq / 1_000_000; let event_opt = key_consumer .pop() .or_else(|| mouse_consumer.pop()) @@ -1179,13 +1282,10 @@ fn port_loop( _ => (), } } - if diff > 0 { - app.draw()?; - window_manager.lock().update(); - window_manager.lock().render(); - - start = hpet.as_ref().ok_or("Unable to get timer")?.get_counter(); - } + app.draw()?; + fps_counter.run()?; + window_manager.lock().update(); + window_manager.lock().render(); } Ok(()) } From e09669b9c3efe9a1d03f942ff02f2d7d1a0bca67 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 17 Jan 2023 22:03:04 +0300 Subject: [PATCH 32/32] no more unsafety --- applications/porthole/src/lib.rs | 53 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/applications/porthole/src/lib.rs b/applications/porthole/src/lib.rs index a5948ba82a..2614531348 100644 --- a/applications/porthole/src/lib.rs +++ b/applications/porthole/src/lib.rs @@ -190,6 +190,7 @@ impl App { let mut window = self.window.lock(); window.draw_rectangle(DEFAULT_WINDOW_COLOR)?; + window.display_window_title(DEFAULT_TEXT_COLOR, DEFAULT_BORDER_COLOR)?; print_string( &mut window, @@ -198,6 +199,7 @@ impl App { self.text.fg_color, self.text.bg_color, )?; + Ok(()) } } @@ -657,10 +659,12 @@ impl<'a> Iterator for MouseImageRowIterator<'a> { if self.current_row < self.bounding_box.height - 1 { let mut row = Vec::new(); while self.current_column < self.bounding_box.width { - let color = unsafe { - self.mouse_image.get_unchecked(self.current_column)[self.current_row] - }; - row.push(color); + let color = self + .mouse_image + .get(self.current_column)? + .get(self.current_row)?; + + row.push(*color); self.current_column += 1; if self.current_column == self.bounding_box.width - 1 { self.current_column = 0; @@ -682,7 +686,7 @@ impl<'a> Iterator for MouseImageRowIterator<'a> { /// this returns row of mutable slices from that smaller cake. pub struct FramebufferRowChunks<'a, T: 'a> { /// Framebuffer we used to get the `rows` from - fb: *mut [T], + fb: &'a mut [T], /// This let's us decide where and how big of a row we want to get rect: Rect, /// Amount of pixels in a line of `Framebuffer` @@ -735,11 +739,6 @@ impl<'a, T: 'a> FramebufferRowChunks<'a, T> { Ok(row_iterator) } - fn calculate_next_row(&mut self) { - self.row_index_beg = (self.stride * self.current_column) + self.rect.x as usize; - self.row_index_end = - (self.stride * self.current_column) + self.rect.x_plus_width() as usize; - } } impl<'a, T> Iterator for FramebufferRowChunks<'a, T> { @@ -747,14 +746,28 @@ impl<'a, T> Iterator for FramebufferRowChunks<'a, T> { fn next(&mut self) -> Option<&'a mut [T]> { if self.current_column < self.rect.y_plus_height() as usize { - let chunk = unsafe { - self.fb - .get_unchecked_mut(self.row_index_beg..self.row_index_end) - }; + // To not fight borrow checker we do this little trick here + let slice = core::mem::replace(&mut self.fb, &mut []); + + if slice.len() < self.row_index_end { + return None; + } self.current_column += 1; - self.calculate_next_row(); - let chunk = { unsafe { &mut *chunk } }; - Some(chunk) + + let (row, rest_of_slice) = slice.split_at_mut(self.row_index_end); + + // We want to keep rest of the slice + self.fb = rest_of_slice; + if let Some(chunk) = row.get_mut(self.row_index_beg..self.row_index_end) { + // Because we are taking part of a slice we need this gap to be added to + // `row_index_beg` and `row_index_end` so we can correctly index the framebuffer slice + let gap = self.stride - self.row_index_end; + self.row_index_beg = self.row_index_beg + gap; + self.row_index_end = self.row_index_end + gap; + return Some(chunk); + } else { + None + } } else { None } @@ -1212,6 +1225,7 @@ fn port_loop( (key_consumer, mouse_consumer): (Queue, Queue), ) -> Result<(), &'static str> { let window_manager = WINDOW_MANAGER.get().ok_or("Unable to get WindowManager")?; + let window_2 = window_manager .lock() .new_window(&Rect::new(400, 400, 500, 20), Some(format!("Basic")))?; @@ -1227,6 +1241,7 @@ fn port_loop( bg_color: DEFAULT_WINDOW_COLOR, }; let mut app = App::new(window_2, text); + let window_3 = window_manager .lock() .new_window(&Rect::new(400, 100, 0, 0), Some(format!("Fps Counter")))?; @@ -1282,10 +1297,12 @@ fn port_loop( _ => (), } } - app.draw()?; fps_counter.run()?; + app.draw()?; window_manager.lock().update(); window_manager.lock().render(); + // app.draw()?; + //fps_counter.run()?; } Ok(()) }