-
-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new graphics layer #722
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I left some comments; the biggest issue is the way that offset calculations and bounds checking happens on a per-pixel basis, sometimes more than once per pixel.
kernel/multicore_bringup/src/lib.rs
Outdated
@@ -60,11 +60,11 @@ pub static GRAPHIC_INFO: Mutex<GraphicInfo> = Mutex::new(GraphicInfo::new()); | |||
#[repr(packed)] | |||
pub struct GraphicInfo { | |||
/// The visible width of the screen, in pixels. | |||
width: u16, | |||
pub width: u16, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are private to avoid accidental modification; there are some accessor functions that you can use instead: https://www.theseus-os.com/Theseus/doc/multicore_bringup/struct.GraphicInfo.html#method.width
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed that
applications/porthole/src/lib.rs
Outdated
let buffer_height = rect.height / CHARACTER_HEIGHT; | ||
let (x, y) = (rect.x, rect.y); | ||
|
||
let some_slice = slice.as_bytes(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason why you're converting the string to a byte slice here? I would think it's better to keep it as a string so you can more easily handle wide or multi-byte characters (e.g., emoji, other unicode chars). Reducing it to a byte slice removes important information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's how old api worked to support basic text displaying, supporting multi-byte characters is future work.
applications/porthole/src/lib.rs
Outdated
buffer: BorrowedSliceMappedPages<u32, Mutable>, | ||
} | ||
impl FrameBuffer { | ||
fn init_front_buffer() -> Result<FrameBuffer, &'static str> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a good idea to use two separate types for this:
- A type to represent the real physical framebuffer (or framebuffers, in the case of double buffering) that is mapped to actual graphics memory
- A type to represent virtual framebuffers that are just arbitrary chunks of memory
The idea is that, by design, we can prevent accidentally reading from a real framebuffer by not implementing functions that do that, like get_pixel()
. Only the virtual framebuffer type would allow reading from it, while the real/physical framebuffer type would only allow writing to it.
applications/porthole/src/lib.rs
Outdated
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one of the main goals of an API for drawing things should be to allow the callers to easily avoid the expensive bounds checks and calculations of pixel offsets on a per-pixel basis. Here, you're forcing that to occur not just once, but twice per pixel, which is a lot of overhead.
Instead of using indexing (which requires bound checking), use iterators.
f1ca63a
to
e5b5928
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaving a partial review to share notes
applications/porthole/src/lib.rs
Outdated
} | ||
|
||
pub fn display_window_title(window: &mut MutexGuard<Window>, fg_color: Color, bg_color: Color) { | ||
if let Some(title) = window.title.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this eagerly clones the whole title
String every time. Instead move the .clone()
operation into the inside of the branch
applications/porthole/src/lib.rs
Outdated
} | ||
|
||
pub fn print_string( | ||
window: &mut MutexGuard<Window>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume here you mean &mut Window
, since there's no real reason to take a mutable reference to a MutexGuard
. The only reason you'd pass a guard is if you needed the lock to be released within this function, and if that was the case, you'd need to pass it by ownership
applications/porthole/src/lib.rs
Outdated
} | ||
|
||
/// FrameBuffer with no actual physical memory mapped, | ||
/// used for Window and WindowManager's backbuffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that in the future when we support true double buffering using graphics memory, this will not be true (and thus this type shouldn't be used to represent that backbuffer in graphics memory).
applications/porthole/src/lib.rs
Outdated
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the right idea and, ultimately, the end point for what i was hoping to see once you have obtained an iterator over the window region (source) and an iterator over the framebuffer region (destination).
applications/porthole/src/lib.rs
Outdated
fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { | ||
let x = x; | ||
let y = y; | ||
unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
definitely no need to use unsafe here or anywhere else in this entire crate.
applications/porthole/src/lib.rs
Outdated
} | ||
|
||
// We don't want user to draw on top a border | ||
pub fn return_drawable_area(&self) -> Rect { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider caching the values of rectangular bounding boxes for things like the title rectangle, drawable areas, etc, since they only need to change rarely upon a window resize action.
Then, when the window actually gets resized, you can recalculate them. A great design pattern for this is to use an Option<Rect>
with an accessor function like get_or_insert()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and you have many methods and fields that should be pub but aren't
or you could remove every pub if you don't care about modularity
applications/porthole/src/lib.rs
Outdated
}) | ||
} | ||
|
||
fn copy_windows_into_main_vbuffer(&mut self, window: &mut MutexGuard<Window>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should really be a Window method
fn copy_windows_into_main_vbuffer(&mut self, window: &mut MutexGuard<Window>) { | |
fn copy_into_vbuffer(&mut self, vbuf: &mut VirtualFrameBuffer){ |
applications/porthole/src/lib.rs
Outdated
} | ||
} | ||
|
||
fn draw_unchecked(&mut self, x: isize, y: isize, col: Color) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove unsafety
Closing in favor of #823 |
Porthole
Porthole, is new graphics layer for the Theseus OS, inspired by the old graphic's stack written from ground up Porthole has several goals:
Design
Detailed design of Porthole will be written here.
Tasks:
This is very early phase code most of the it going change after reviews/discussions