From e04a4bee4f91a3d810b3e06699cd26c9b0f0c757 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Fri, 13 Mar 2026 04:29:50 +0300 Subject: [PATCH 1/7] wip: add support for damage tracking on Redox --- src/backends/orbital.rs | 82 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 23f7b451..4acdbd82 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -190,7 +190,7 @@ 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); @@ -198,7 +198,7 @@ impl BufferInterface for BufferImpl<'_> { *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); } } @@ -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); @@ -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); + // 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 * min_height; + window_data[..total_pixels].copy_from_slice(&buffer[..total_pixels]); + } else { + // 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 @@ -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 + }) +} From b3d4a42898421aaef9ff3ba38c213cf0af845cf8 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Fri, 13 Mar 2026 05:01:04 +0300 Subject: [PATCH 2/7] Update orbital.rs --- src/backends/orbital.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 4acdbd82..dae4c98d 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -267,7 +267,7 @@ fn set_buffer( // 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 * min_height; + let total_pixels = width * height; window_data[..total_pixels].copy_from_slice(&buffer[..total_pixels]); } else { // Even if width is same, damaged areas can be anywhere inside the window. From 30a369894ba856dda361c3d5273d54eb63557794 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Sun, 15 Mar 2026 18:14:58 +0300 Subject: [PATCH 3/7] remove comments lines --- src/backends/orbital.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index dae4c98d..4ce137f7 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -249,20 +249,6 @@ fn set_buffer( // 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); - - // 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. From 2ba8030c3ab9073dd9d8eebfba8684cedc481fb1 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Sun, 15 Mar 2026 22:25:32 +0300 Subject: [PATCH 4/7] use union_damage as requested --- src/backends/orbital.rs | 45 ++++++++++++----------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 4ce137f7..89d2abbc 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -258,38 +258,19 @@ fn set_buffer( } else { // 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; + if let Some(urect) = util::union_damage(damage) { + let x = urect.x as usize; + let y = urect.y as usize; + let w = (urect.width.get() as usize).min(window_width.saturating_sub(x)); + let h = (urect.height.get() as usize).min(window_height.saturating_sub(y)); + + for (src_row, dst_row) in buffer + .chunks_exact(width) + .zip(window_data.chunks_exact_mut(window_width)) + .skip(y) + .take(h) + { + dst_row[x..x + w].copy_from_slice(&src_row[x..x + w]); } } } From b11359f9f40a4bb0af56abfa50086f1ec871cb49 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Sun, 15 Mar 2026 22:29:38 +0300 Subject: [PATCH 5/7] remove unused import --- src/backends/orbital.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 89d2abbc..85743821 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -1,6 +1,6 @@ use crate::error::InitError; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle}; -use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str}; +use std::{marker::PhantomData, num::NonZeroU32, slice, str}; use crate::backend_interface::*; use crate::{util, AlphaMode, Pixel, Rect, SoftBufferError}; From 9a84cdb1be5949a0c7e66b0fe0d41a380119c2a5 Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Sun, 15 Mar 2026 22:54:47 +0300 Subject: [PATCH 6/7] Update orbital.rs --- src/backends/orbital.rs | 48 ++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 85743821..35943da2 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -236,6 +236,11 @@ fn set_buffer( // Read the current width and size let (window_width, window_height) = window_size(window_fd); + let Some(urect) = util::union_damage(damage) else { + syscall::fsync(window_fd).expect("failed to sync orbital window"); + return; + }; + { // Map window buffer let mut window_map = @@ -246,32 +251,21 @@ fn set_buffer( // https://docs.rs/orbclient/0.3.48/src/orbclient/color.rs.html#25-29 let window_data = unsafe { window_map.data_mut() }; - // Copy each line, cropping to fit let width = width_u32 as usize; - let height = height_u32 as usize; - // 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 { - // 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. - if let Some(urect) = util::union_damage(damage) { - let x = urect.x as usize; - let y = urect.y as usize; - let w = (urect.width.get() as usize).min(window_width.saturating_sub(x)); - let h = (urect.height.get() as usize).min(window_height.saturating_sub(y)); - - for (src_row, dst_row) in buffer - .chunks_exact(width) - .zip(window_data.chunks_exact_mut(window_width)) - .skip(y) - .take(h) - { - dst_row[x..x + w].copy_from_slice(&src_row[x..x + w]); - } + let x = urect.x as usize; + let y = urect.y as usize; + let w = (urect.width.get() as usize).min(window_width.saturating_sub(x)); + let h = (urect.height.get() as usize).min(window_height.saturating_sub(y)); + + if let Some(urect) = util::union_damage(damage) { + for (src_row, dst_row) in buffer + .chunks_exact(width) + .zip(window_data.chunks_exact_mut(window_width)) + .skip(y) + .take(h) + { + dst_row[x..x + w].copy_from_slice(&src_row[x..x + w]); } } @@ -281,9 +275,3 @@ fn set_buffer( // 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 - }) -} From 45fe2c495561f733b2fca41aa6135956a1dc2a9a Mon Sep 17 00:00:00 2001 From: Ali Baydur <67105447+yagizgil@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:00:16 +0300 Subject: [PATCH 7/7] Update orbital.rs --- src/backends/orbital.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 35943da2..acfd2b10 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -230,7 +230,7 @@ fn set_buffer( window_fd: usize, buffer: &[Pixel], width_u32: u32, - height_u32: u32, + _height_u32: u32, damage: &[Rect], ) { // Read the current width and size @@ -258,15 +258,13 @@ fn set_buffer( let w = (urect.width.get() as usize).min(window_width.saturating_sub(x)); let h = (urect.height.get() as usize).min(window_height.saturating_sub(y)); - if let Some(urect) = util::union_damage(damage) { - for (src_row, dst_row) in buffer - .chunks_exact(width) - .zip(window_data.chunks_exact_mut(window_width)) - .skip(y) - .take(h) - { - dst_row[x..x + w].copy_from_slice(&src_row[x..x + w]); - } + for (src_row, dst_row) in buffer + .chunks_exact(width) + .zip(window_data.chunks_exact_mut(window_width)) + .skip(y) + .take(h) + { + dst_row[x..x + w].copy_from_slice(&src_row[x..x + w]); } // Window buffer map is dropped here