bootloader_x86_64_common/
framebuffer.rs1use bootloader_api::info::{FrameBufferInfo, PixelFormat};
2use core::{fmt, ptr};
3use font_constants::BACKUP_CHAR;
4use noto_sans_mono_bitmap::{
5 FontWeight, RasterHeight, RasterizedChar, get_raster, get_raster_width,
6};
7
8const LINE_SPACING: usize = 2;
10const LETTER_SPACING: usize = 0;
12
13const BORDER_PADDING: usize = 1;
15
16mod font_constants {
18 use super::*;
19
20 pub const CHAR_RASTER_HEIGHT: RasterHeight = RasterHeight::Size16;
23
24 pub const CHAR_RASTER_WIDTH: usize = get_raster_width(FontWeight::Regular, CHAR_RASTER_HEIGHT);
26
27 pub const BACKUP_CHAR: char = '�';
30
31 pub const FONT_WEIGHT: FontWeight = FontWeight::Regular;
32}
33
34fn get_char_raster(c: char) -> RasterizedChar {
36 fn get(c: char) -> Option<RasterizedChar> {
37 get_raster(
38 c,
39 font_constants::FONT_WEIGHT,
40 font_constants::CHAR_RASTER_HEIGHT,
41 )
42 }
43 get(c).unwrap_or_else(|| get(BACKUP_CHAR).expect("Should get raster of backup char."))
44}
45
46pub struct FrameBufferWriter {
48 framebuffer: &'static mut [u8],
49 info: FrameBufferInfo,
50 x_pos: usize,
51 y_pos: usize,
52}
53
54impl FrameBufferWriter {
55 pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
57 let mut logger = Self {
58 framebuffer,
59 info,
60 x_pos: 0,
61 y_pos: 0,
62 };
63 logger.clear();
64 logger
65 }
66
67 fn newline(&mut self) {
68 self.y_pos += font_constants::CHAR_RASTER_HEIGHT.val() + LINE_SPACING;
69 self.carriage_return()
70 }
71
72 fn carriage_return(&mut self) {
73 self.x_pos = BORDER_PADDING;
74 }
75
76 pub fn clear(&mut self) {
78 self.x_pos = BORDER_PADDING;
79 self.y_pos = BORDER_PADDING;
80 self.framebuffer.fill(0);
81 }
82
83 fn width(&self) -> usize {
84 self.info.width
85 }
86
87 fn height(&self) -> usize {
88 self.info.height
89 }
90
91 fn write_char(&mut self, c: char) {
94 match c {
95 '\n' => self.newline(),
96 '\r' => self.carriage_return(),
97 c => {
98 let new_xpos = self.x_pos + font_constants::CHAR_RASTER_WIDTH;
99 if new_xpos >= self.width() {
100 self.newline();
101 }
102 let new_ypos =
103 self.y_pos + font_constants::CHAR_RASTER_HEIGHT.val() + BORDER_PADDING;
104 if new_ypos >= self.height() {
105 self.clear();
106 }
107 self.write_rendered_char(get_char_raster(c));
108 }
109 }
110 }
111
112 fn write_rendered_char(&mut self, rendered_char: RasterizedChar) {
115 for (y, row) in rendered_char.raster().iter().enumerate() {
116 for (x, byte) in row.iter().enumerate() {
117 self.write_pixel(self.x_pos + x, self.y_pos + y, *byte);
118 }
119 }
120 self.x_pos += rendered_char.width() + LETTER_SPACING;
121 }
122
123 fn write_pixel(&mut self, x: usize, y: usize, intensity: u8) {
124 let pixel_offset = y * self.info.stride + x;
125 let color = match self.info.pixel_format {
126 PixelFormat::Rgb => [intensity, intensity, intensity / 2, 0],
127 PixelFormat::Bgr => [intensity / 2, intensity, intensity, 0],
128 PixelFormat::U8 => [if intensity > 200 { 0xf } else { 0 }, 0, 0, 0],
129 other => {
130 self.info.pixel_format = PixelFormat::Rgb;
133 panic!("pixel format {:?} not supported in logger", other)
134 }
135 };
136 let bytes_per_pixel = self.info.bytes_per_pixel;
137 let byte_offset = pixel_offset * bytes_per_pixel;
138 self.framebuffer[byte_offset..(byte_offset + bytes_per_pixel)]
139 .copy_from_slice(&color[..bytes_per_pixel]);
140 let _ = unsafe { ptr::read_volatile(&self.framebuffer[byte_offset]) };
141 }
142}
143
144unsafe impl Send for FrameBufferWriter {}
145unsafe impl Sync for FrameBufferWriter {}
146
147impl fmt::Write for FrameBufferWriter {
148 fn write_str(&mut self, s: &str) -> fmt::Result {
149 for c in s.chars() {
150 self.write_char(c);
151 }
152 Ok(())
153 }
154}