Skip to content

Commit

Permalink
Migrate to layer architecture (osbook_day09a)
Browse files Browse the repository at this point in the history
  • Loading branch information
gifnksm committed May 18, 2021
1 parent 55cd025 commit 08d331a
Show file tree
Hide file tree
Showing 13 changed files with 708 additions and 200 deletions.
162 changes: 139 additions & 23 deletions src/console.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use crate::{
desktop, font, framebuffer,
graphics::{Color, Draw, Point, Rectangle, Size},
layer::{self, Layer, LayerEvent},
prelude::*,
sync::mpsc,
window::{Window, WindowDrawer},
};
use alloc::sync::Arc;
use core::{convert::TryFrom, fmt};
use futures_util::StreamExt as _;
use x86_64::instructions::interrupts;

#[macro_export]
Expand All @@ -21,13 +27,13 @@ pub fn _print(args: fmt::Arguments) {
use core::fmt::Write as _;

interrupts::without_interrupts(|| {
if let Ok(mut framebuffer) = framebuffer::lock_drawer() {
if let Some(mut console) = CONSOLE.try_lock() {
if let Some(mut console) = CONSOLE.try_lock() {
let _ = console.with_writer(|mut writer| {
#[allow(clippy::unwrap_used)]
console.writer(&mut *framebuffer).write_fmt(args).unwrap();
}
writer.write_fmt(args).unwrap();
});
}
});
})
}

const ROWS: usize = 25;
Expand All @@ -38,13 +44,15 @@ static CONSOLE: spin::Mutex<Console> = spin::Mutex::new(Console {
fg_color: desktop::FG_COLOR,
bg_color: desktop::BG_COLOR,
cursor: Point::new(0, 0),
window_drawer: None,
});

pub(crate) struct Console {
buffer: [[u8; COLUMNS]; ROWS],
fg_color: Color,
bg_color: Color,
cursor: Point<usize>,
window_drawer: Option<(Arc<spin::Mutex<WindowDrawer>>, mpsc::Sender<()>)>,
}

struct RedrawArea {
Expand All @@ -63,6 +71,16 @@ impl RedrawArea {
}
}

fn all(fill_bg: bool) -> Self {
Self {
area: Rectangle {
pos: Point::new(0, 0),
size: Size::new(COLUMNS, ROWS),
},
fill_bg,
}
}

fn add(&mut self, p: Point<usize>) {
if self.area.size.x == 0 || self.area.size.y == 0 {
self.area.pos = p;
Expand Down Expand Up @@ -113,23 +131,75 @@ impl Console {
};
}

pub(crate) fn writer<'d, 'c, D>(&'c mut self, drawer: &'d mut D) -> ConsoleWriter<'d, 'c, D> {
ConsoleWriter {
drawer,
console: self,
fn set_window_drawer(
&mut self,
drawer: Option<(Arc<spin::Mutex<WindowDrawer>>, mpsc::Sender<()>)>,
) -> Result<()> {
self.window_drawer = drawer;
self.refresh()?;
Ok(())
}

fn refresh(&mut self) -> Result<()> {
self.with_writer(|mut writer| {
writer.redraw(RedrawArea::all(true));
})
}

fn with_writer(&'_ mut self, f: impl FnOnce(ConsoleWriter<'_, '_>)) -> Result<()> {
assert!(!interrupts::are_enabled());

if let Some((window_drawer, tx)) = self.window_drawer.clone() {
let drawer = Drawer::Window(
window_drawer
.try_lock()
.ok_or(ErrorKind::Deadlock("window_drawer"))?,
);
let writer = ConsoleWriter {
drawer,
console: self,
};
f(writer);
tx.send(())?;
} else {
let drawer = Drawer::FrameBuffer(framebuffer::lock_drawer()?);
let writer = ConsoleWriter {
drawer,
console: self,
};
f(writer);
}
Ok(())
}
}

pub(crate) struct ConsoleWriter<'d, 'c, D> {
drawer: &'d mut D,
enum Drawer<'a> {
FrameBuffer(spin::MutexGuard<'static, framebuffer::Drawer>),
Window(spin::MutexGuard<'a, WindowDrawer>),
}

impl Draw for Drawer<'_> {
fn area(&self) -> Rectangle<i32> {
match self {
Self::FrameBuffer(drawer) => drawer.area(),
Self::Window(drawer) => drawer.area(),
}
}

fn draw(&mut self, p: Point<i32>, c: Color) {
match self {
Self::FrameBuffer(drawer) => drawer.draw(p, c),
Self::Window(drawer) => drawer.draw(p, c),
}
}
}

pub(crate) struct ConsoleWriter<'d, 'c> {
drawer: Drawer<'d>,
console: &'c mut Console,
}

impl<'d, 'c, D> ConsoleWriter<'d, 'c, D>
where
D: Draw,
{
impl<'d, 'c> ConsoleWriter<'d, 'c> {
fn to_draw_point(&self, p: Point<usize>) -> Point<i32> {
let font_size = font::FONT_PIXEL_SIZE;
#[allow(clippy::unwrap_used)]
Expand All @@ -145,14 +215,8 @@ where
size: self.to_draw_point(rect.size),
}
}
}

impl<'d, 'c, D> fmt::Write for ConsoleWriter<'d, 'c, D>
where
D: Draw,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let redraw = self.console.write_str(s);
fn redraw(&mut self, redraw: RedrawArea) {
if redraw.fill_bg {
let rect = self.to_draw_rect(redraw.area);
self.drawer.fill_rect(rect, self.console.bg_color);
Expand All @@ -164,9 +228,61 @@ where

let bytes = &self.console.buffer[console_y][x_range];
let draw_p = self.to_draw_point(console_p);
font::draw_byte_str(self.drawer, draw_p, bytes, self.console.fg_color);
font::draw_byte_str(&mut self.drawer, draw_p, bytes, self.console.fg_color);
}
}
}

impl<'d, 'c> fmt::Write for ConsoleWriter<'d, 'c> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let redraw = self.console.write_str(s);
self.redraw(redraw);
Ok(())
}
}

pub(crate) async fn handler_task() {
let res = async {
let font_size = font::FONT_PIXEL_SIZE;
let window_size = Size::new(COLUMNS as i32 * font_size.x, ROWS as i32 * font_size.y);
let window = Window::new(window_size);
let (tx, mut rx) = mpsc::channel(100);
{
let drawer = window
.try_lock()
.ok_or(ErrorKind::Deadlock("window"))?
.drawer();
interrupts::without_interrupts(|| {
CONSOLE
.try_lock()
.ok_or(ErrorKind::Deadlock("console::CONSOLE"))?
.set_window_drawer(Some((drawer, tx)))?;
Ok::<(), Error>(())
})?;
}

let mut layer = Layer::new();
let layer_id = layer.id();
layer.set_window(Some(window));
layer.move_to(Point::new(0, 0));

let layer_tx = layer::event_tx()?;
layer_tx.send(LayerEvent::Register { layer })?;
layer_tx.send(LayerEvent::SetHeight {
layer_id,
height: layer::CONSOLE_HEIGHT,
})?;
layer_tx.send(LayerEvent::Draw {})?;

while let Some(()) = rx.next().await {
layer_tx.send(LayerEvent::Draw {})?;
}

Ok::<(), Error>(())
}
.await;

if let Err(err) = res {
panic!("error occurred during handling console vent: {}", err);
}
}
64 changes: 46 additions & 18 deletions src/desktop.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,67 @@
use crate::{
framebuffer,
graphics::{Color, Draw, Point, Rectangle, Size},
Result,
layer::{self, Layer, LayerEvent},
prelude::*,
window::Window,
};

pub(crate) const BG_COLOR: Color = Color::new(45, 118, 237);
pub(crate) const FG_COLOR: Color = Color::WHITE;

pub(crate) fn draw() -> Result<()> {
let screen = *framebuffer::info()?;
let mut drawer = framebuffer::lock_drawer()?;
fn draw(drawer: &mut dyn Draw, size: Size<i32>) {
drawer.fill_rect(
Rectangle::new(
Point::new(0, 0),
Size::new(screen.width, screen.height - 50),
),
Rectangle::new(Point::new(0, 0), Size::new(size.x, size.y - 50)),
BG_COLOR,
);
drawer.fill_rect(
Rectangle::new(
Point::new(0, screen.height - 50),
Size::new(screen.width, 50),
),
Rectangle::new(Point::new(0, size.y - 50), Size::new(size.x, 50)),
Color::new(1, 8, 17),
);
drawer.fill_rect(
Rectangle::new(
Point::new(0, screen.height - 50),
Size::new(screen.width / 5, 50),
),
Rectangle::new(Point::new(0, size.y - 50), Size::new(size.x / 5, 50)),
Color::new(80, 80, 80),
);
drawer.draw_rect(
Rectangle::new(Point::new(10, screen.height - 40), Size::new(30, 30)),
Rectangle::new(Point::new(10, size.y - 40), Size::new(30, 30)),
Color::new(160, 160, 160),
);
Ok(())
}

pub(crate) async fn handler_task() {
let res = async {
let screen_info = *framebuffer::info()?;
let window = Window::new(screen_info.size());

{
let drawer = window
.try_lock()
.ok_or(ErrorKind::Deadlock("window"))?
.drawer();
let mut drawer = drawer
.try_lock()
.ok_or(ErrorKind::Deadlock("window drawer"))?;
draw(&mut *drawer, screen_info.size());
}

let mut layer = Layer::new();
let layer_id = layer.id();
layer.set_window(Some(window));
layer.move_to(Point::new(0, 0));

let tx = layer::event_tx()?;
tx.send(LayerEvent::Register { layer })?;
tx.send(LayerEvent::SetHeight {
layer_id,
height: layer::DESKTOP_HEIGHT,
})?;
tx.send(LayerEvent::Draw {})?;

Ok::<(), Error>(())
}
.await;

if let Err(err) = res {
panic!("error occurred during handling desktop drawing: {}", err);
}
}
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub(crate) enum ErrorKind {
MapTo(MapToError<Size4KiB>),
TryInit(&'static str, TryInitError),
TryGet(&'static str, TryGetError),
FrameBufferNotSupported,
PhysicalMemoryNotMapped,
UnsupportedPixelFormat(PixelFormat),
ParameterTooLarge(&'static str, usize),
Deadlock(&'static str),
Expand Down
20 changes: 15 additions & 5 deletions src/framebuffer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
desktop,
error::ConvertErr as _,
graphics::{Color, Draw, Point, Rectangle},
graphics::{Color, Draw, Point, Rectangle, Size},
prelude::*,
util,
};
Expand All @@ -19,12 +20,14 @@ pub(crate) fn init(framebuffer: FrameBuffer) -> Result<()> {

let info = ScreenInfo::new(&original_info)?;

let drawer = Drawer {
let mut drawer = Drawer {
framebuffer,
info,
pixel_drawer,
};

drawer.fill_rect(info.area(), desktop::BG_COLOR);

INFO.try_init_once(|| info)
.convert_err("framebuffer::INFO")?;
DRAWER
Expand All @@ -37,7 +40,6 @@ pub(crate) fn info() -> Result<&'static ScreenInfo> {
}

pub(crate) fn lock_drawer() -> Result<spin::MutexGuard<'static, Drawer>> {
// TODO: consider interrupts
util::try_get_and_lock(&DRAWER, "framebuffer::DRAWER")
}

Expand All @@ -62,6 +64,14 @@ impl ScreenInfo {
bytes_per_pixel: usize_to_i32("byte_per_pixel", info.bytes_per_pixel)?,
})
}

pub(crate) fn area(&self) -> Rectangle<i32> {
Rectangle::new(Point::new(0, 0), self.size())
}

pub(crate) fn size(&self) -> Size<i32> {
Size::new(self.width, self.height)
}
}

pub(crate) struct Drawer {
Expand All @@ -71,9 +81,9 @@ pub(crate) struct Drawer {
}

impl Draw for Drawer {
fn area(&self) -> crate::graphics::Rectangle<i32> {
fn area(&self) -> Rectangle<i32> {
Rectangle {
pos: Point::new(0i32, 0i32),
pos: Point::new(0, 0),
size: Point::new(self.info.width, self.info.height),
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ pub(crate) trait Draw {
fn area(&self) -> Rectangle<i32>;
fn draw(&mut self, p: Point<i32>, c: Color);

fn size(&self) -> Size<i32> {
self.area().size
}

fn fill_rect(&mut self, rect: Rectangle<i32>, c: Color) {
for p in rect.points() {
self.draw(p, c);
Expand Down
Loading

0 comments on commit 08d331a

Please sign in to comment.