graphics: Only allow passing a single damage area at a time

Currently only fbbootlogd and fbcond make use of support for multiple
damage areas and they are not all that performance critical anyway.
Orbital always passes a single damage area per write call. Out of all
graphics drivers we have and are likely to get only vesad could
potentially benefit from fine-grained damage areas. This commit doesn't
significantly impact performance of fbcond.
This commit is contained in:
bjorn3
2025-03-06 20:36:54 +01:00
parent 1b6d847d2f
commit f48ae933ff
8 changed files with 66 additions and 96 deletions
+28 -35
View File
@@ -1,6 +1,6 @@
extern crate ransid;
use std::collections::{BTreeSet, VecDeque};
use std::collections::VecDeque;
use std::convert::{TryFrom, TryInto};
use std::{cmp, ptr};
@@ -15,7 +15,6 @@ pub struct DisplayMap {
pub struct TextScreen {
console: ransid::Console,
changed: BTreeSet<usize>,
}
impl TextScreen {
@@ -23,7 +22,6 @@ impl TextScreen {
TextScreen {
// Width and height will be filled in on the next write to the console
console: ransid::Console::new(0, 0),
changed: BTreeSet::new(),
}
}
@@ -118,18 +116,24 @@ impl TextScreen {
}
impl TextScreen {
pub fn write(
&mut self,
map: &mut DisplayMap,
buf: &[u8],
input: &mut VecDeque<u8>,
) -> Vec<Damage> {
pub fn write(&mut self, map: &mut DisplayMap, buf: &[u8], input: &mut VecDeque<u8>) -> Damage {
let mut min_changed = usize::MAX;
let mut max_changed = 0;
let mut line_changed = |line| {
if line < min_changed {
min_changed = line;
}
if line > max_changed {
max_changed = line;
}
};
self.console.resize(map.width / 8, map.height / 16);
if self.console.state.x > self.console.state.w {
self.console.state.x = self.console.state.w;
if self.console.state.x >= self.console.state.w {
self.console.state.x = self.console.state.w - 1;
}
if self.console.state.y > self.console.state.h {
self.console.state.y = self.console.state.h;
if self.console.state.y >= self.console.state.h {
self.console.state.y = self.console.state.h - 1;
}
if self.console.state.cursor
@@ -139,7 +143,7 @@ impl TextScreen {
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(map, x * 8, y * 16, 8, 16);
self.changed.insert(y);
line_changed(y);
}
self.console.write(buf, |event| match event {
@@ -152,13 +156,13 @@ impl TextScreen {
..
} => {
Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false);
self.changed.insert(y);
line_changed(y);
}
ransid::Event::Input { data } => input.extend(data),
ransid::Event::Rect { x, y, w, h, color } => {
Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
for y2 in y..y + h {
self.changed.insert(y2);
line_changed(y2);
}
}
ransid::Event::ScreenBuffer { .. } => (),
@@ -195,7 +199,7 @@ impl TextScreen {
}
}
self.changed.insert(to_y + y);
line_changed(to_y + y);
}
}
ransid::Event::Resize { .. } => (),
@@ -209,27 +213,16 @@ impl TextScreen {
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(map, x * 8, y * 16, 8, 16);
self.changed.insert(y);
line_changed(y);
}
let width = map.width.try_into().unwrap();
let mut damage: Vec<Damage> = vec![];
let mut last_change = usize::MAX - 1;
for &change in &self.changed {
if change == last_change + 1 {
damage.last_mut().unwrap().height += 16;
} else {
damage.push(Damage {
x: 0,
y: u32::try_from(change).unwrap() * 16,
width,
height: 16,
});
}
last_change = change;
}
self.changed.clear();
let damage = Damage {
x: 0,
y: u32::try_from(min_changed).unwrap() * 16,
width,
height: u32::try_from(max_changed.saturating_sub(min_changed)).unwrap() * 16,
};
damage
}
+5 -14
View File
@@ -16,12 +16,7 @@ pub trait GraphicsAdapter {
fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer;
fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8;
fn update_plane(
&mut self,
display_id: usize,
framebuffer: &Self::Framebuffer,
damage: &[Damage],
);
fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage);
}
pub trait Framebuffer {
@@ -137,12 +132,12 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
adapter.update_plane(
screen,
framebuffer,
&[Damage {
Damage {
x: 0,
y: 0,
width: framebuffer.width(),
height: framebuffer.height(),
}],
},
);
}
}
@@ -227,12 +222,8 @@ impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
let framebuffer = &self.vts_fb[vt][screen];
let damage = unsafe {
core::slice::from_raw_parts(
buf.as_ptr() as *const Damage,
buf.len() / core::mem::size_of::<Damage>(),
)
};
assert_eq!(buf.len(), std::mem::size_of::<Damage>());
let damage = unsafe { *buf.as_ptr().cast::<Damage>() };
self.adapter.update_plane(*screen, framebuffer, damage);
+1 -1
View File
@@ -102,7 +102,7 @@ impl Scheme for FbbootlogScheme {
);
if let Some(map) = &self.display_map {
map.display_handle.sync_rects(&damage).unwrap();
map.display_handle.sync_rect(damage).unwrap();
}
}
+2 -2
View File
@@ -55,9 +55,9 @@ impl Display {
V1GraphicsHandle::from_file(display_file)
}
pub fn sync_rects(&mut self, sync_rects: Vec<Damage>) {
pub fn sync_rect(&mut self, sync_rect: Damage) {
if let Some(map) = &self.map {
map.display_handle.sync_rects(&sync_rects).unwrap();
map.display_handle.sync_rect(sync_rect).unwrap();
}
}
}
+1 -1
View File
@@ -132,7 +132,7 @@ impl TextScreen {
&mut self.input,
);
self.display.sync_rects(damage);
self.display.sync_rect(damage);
}
Ok(buf.len())
+3 -3
View File
@@ -64,11 +64,11 @@ impl V1GraphicsHandle {
Ok(())
}
pub fn sync_rects(&self, sync_rects: &[Damage]) -> io::Result<()> {
pub fn sync_rect(&self, sync_rect: Damage) -> io::Result<()> {
libredox::call::write(self.file.as_raw_fd() as usize, unsafe {
slice::from_raw_parts(
sync_rects.as_ptr() as *const u8,
sync_rects.len() * mem::size_of::<Damage>(),
ptr::addr_of!(sync_rect).cast::<u8>(),
mem::size_of::<Damage>(),
)
})?;
Ok(())
+19 -26
View File
@@ -34,12 +34,7 @@ impl GraphicsAdapter for FbAdapter {
framebuffer.ptr.as_ptr().cast::<u8>()
}
fn update_plane(
&mut self,
display_id: usize,
framebuffer: &Self::Framebuffer,
damage: &[Damage],
) {
fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) {
framebuffer.sync(&mut self.framebuffers[display_id], damage)
}
}
@@ -89,29 +84,27 @@ impl Framebuffer for GraphicScreen {
}
impl GraphicScreen {
fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) {
for sync_rect in sync_rects {
let sync_rect = sync_rect.clip(
self.width.try_into().unwrap(),
self.height.try_into().unwrap(),
);
fn sync(&self, framebuffer: &mut FrameBuffer, sync_rect: Damage) {
let sync_rect = sync_rect.clip(
self.width.try_into().unwrap(),
self.height.try_into().unwrap(),
);
let start_x: usize = sync_rect.x.try_into().unwrap();
let start_y: usize = sync_rect.y.try_into().unwrap();
let w: usize = sync_rect.width.try_into().unwrap();
let h: usize = sync_rect.height.try_into().unwrap();
let start_x: usize = sync_rect.x.try_into().unwrap();
let start_y: usize = sync_rect.y.try_into().unwrap();
let w: usize = sync_rect.width.try_into().unwrap();
let h: usize = sync_rect.height.try_into().unwrap();
let offscreen_ptr = self.ptr.as_ptr() as *mut u32;
let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
let offscreen_ptr = self.ptr.as_ptr() as *mut u32;
let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
for row in start_y..start_y + h {
unsafe {
ptr::copy(
offscreen_ptr.add(row * self.width + start_x),
onscreen_ptr.add(row * framebuffer.stride + start_x),
w,
);
}
for row in start_y..start_y + h {
unsafe {
ptr::copy(
offscreen_ptr.add(row * self.width + start_x),
onscreen_ptr.add(row * framebuffer.stride + start_x),
w,
);
}
}
}
+7 -14
View File
@@ -170,12 +170,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
framebuffer.sgl.as_ptr()
}
fn update_plane(
&mut self,
display_id: usize,
framebuffer: &Self::Framebuffer,
damage: &[Damage],
) {
fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) {
futures::executor::block_on(async {
let req = Dma::new(XferToHost2d::new(
framebuffer.id,
@@ -204,14 +199,12 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
self.displays[display_id].active_resource = Some(framebuffer.id);
}
for damage in damage {
let flush = ResourceFlush::new(
framebuffer.id,
damage.clip(framebuffer.width, framebuffer.height).into(),
);
let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap();
assert_eq!(header.ty, CommandTy::RespOkNodata);
}
let flush = ResourceFlush::new(
framebuffer.id,
damage.clip(framebuffer.width, framebuffer.height).into(),
);
let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap();
assert_eq!(header.ty, CommandTy::RespOkNodata);
});
}
}