Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 72 additions & 10 deletions src/backends/orbital.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ impl BufferInterface for BufferImpl<'_> {
}
}

fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
match self.pixels {
Pixels::Mapping(mapping) => {
drop(mapping);
syscall::fsync(self.window_fd).expect("failed to sync orbital window");
*self.presented = true;
}
Pixels::Buffer(buffer) => {
set_buffer(self.window_fd, &buffer, self.width, self.height);
set_buffer(self.window_fd, &buffer, self.width, self.height, damage);
}
}

Expand Down Expand Up @@ -226,7 +226,13 @@ fn window_size(window_fd: usize) -> (usize, usize) {
(window_width, window_height)
}

fn set_buffer(window_fd: usize, buffer: &[Pixel], width_u32: u32, height_u32: u32) {
fn set_buffer(
window_fd: usize,
buffer: &[Pixel],
width_u32: u32,
height_u32: u32,
damage: &[Rect],
) {
// Read the current width and size
let (window_width, window_height) = window_size(window_fd);

Expand All @@ -243,13 +249,63 @@ fn set_buffer(window_fd: usize, buffer: &[Pixel], width_u32: u32, height_u32: u3
// Copy each line, cropping to fit
let width = width_u32 as usize;
let height = height_u32 as usize;
let min_width = cmp::min(width, window_width);
let min_height = cmp::min(height, window_height);
for y in 0..min_height {
let offset_buffer = y * width;
let offset_data = y * window_width;
window_data[offset_data..offset_data + min_width]
.copy_from_slice(&buffer[offset_buffer..offset_buffer + min_width]);
// let min_width = cmp::min(width, window_width);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove commented out code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

// let min_height = cmp::min(height, window_height);

// if width == window_width {
// let pixels = width * min_height;
// window_data[..pixels].copy_from_slice(&buffer[..pixels]);
// } else {
// for y in 0..min_height {
// let offset_buffer = y * width;
// let offset_data = y * window_width;
// window_data[offset_data..offset_data + min_width]
// .copy_from_slice(&buffer[offset_buffer..offset_buffer + min_width]);
// }
// }

// If window size hasn't changed (memory size is same) and we update everything,
// or if at least one damage rect covers the full window, copy everything at once.
if width == window_width && (damage.is_empty() || is_full_damage(damage, width, height)) {
let total_pixels = width * height;
window_data[..total_pixels].copy_from_slice(&buffer[..total_pixels]);
} else {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not that interested in a bunch of extra code for a code path that's ideally gonna never be taken (Pixels::Mapping is the way to go). Especially if the perf wins aren't even really there.

If you really want damage tracking here, maybe you could use util::union_rect instead, and then just copy the resulting rect? That'd be a simpler implementation, and probably just as fast.

Copy link
Copy Markdown
Contributor Author

@yagizgil yagizgil Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did as you said and short the code.
I couldn't find "union_rect" I used "union_damage"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant as an alternative to is_full_damage etc., something similar to what Web did before #321

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did i do it right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, thanks!

// Even if width is same, damaged areas can be anywhere inside the window.
// If they don't cover the full width, we must jump over pixels to copy.
for rect in damage {
let start_y = rect.y as usize;
let rect_height = rect.height.get() as usize;
let end_y = cmp::min(start_y + rect_height, window_height);

let rect_x = rect.x as usize;
let rect_width = rect.width.get() as usize;
let copy_width = cmp::min(rect_width, window_width.saturating_sub(rect_x));

// If the rect is exactly the window width and our width hasn't changed,
// we can copy the rect block without jumping over pixels.
if copy_width == width && width == window_width {
let start_index = start_y * width + rect_x;
let total_len = (end_y - start_y) * width;
window_data[start_index..start_index + total_len]
.copy_from_slice(&buffer[start_index..start_index + total_len]);
continue;
}

let mut current_buffer_offset = start_y * width + rect_x;
let mut current_data_offset = start_y * window_width + rect_x;

// We visit each row of the rect one by one and copy only the specific column range.
for _ in start_y..end_y {
let src = &buffer[current_buffer_offset..current_buffer_offset + copy_width];
let dst =
&mut window_data[current_data_offset..current_data_offset + copy_width];

dst.copy_from_slice(src);

current_buffer_offset += width;
current_data_offset += window_width;
}
}
}

// Window buffer map is dropped here
Expand All @@ -258,3 +314,9 @@ fn set_buffer(window_fd: usize, buffer: &[Pixel], width_u32: u32, height_u32: u3
// Tell orbital to show the latest window data
syscall::fsync(window_fd).expect("failed to sync orbital window");
}

fn is_full_damage(damage: &[Rect], width: usize, height: usize) -> bool {
damage.iter().any(|r| {
r.x == 0 && r.y == 0 && r.width.get() as usize >= width && r.height.get() as usize >= height
})
}