diff --git a/examples/winit.rs b/examples/winit.rs index 803dd9c..fbf4182 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -46,7 +46,7 @@ pub(crate) fn run(event_loop: EventLoop<()>) { let red = x % 255; let green = y % 255; let blue = (x * y) % 255; - let index = y as usize * width.get() as usize + x as usize; + let index = y as usize * buffer.stride() as usize + x as usize; buffer[index] = blue | (green << 8) | (red << 16); } } diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index e3b626f..d924235 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -153,6 +153,16 @@ macro_rules! make_dispatch { } } + #[inline] + fn stride(&self) -> u32 { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.stride(), + )* + } + } + fn present(self) -> Result<(), SoftBufferError> { match self { $( diff --git a/src/backend_interface.rs b/src/backend_interface.rs index 13e3555..95dd3e8 100644 --- a/src/backend_interface.rs +++ b/src/backend_interface.rs @@ -38,6 +38,7 @@ pub(crate) trait BufferInterface { fn pixels(&self) -> &[u32]; fn pixels_mut(&mut self) -> &mut [u32]; fn age(&self) -> u8; + fn stride(&self) -> u32; fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError>; fn present(self) -> Result<(), SoftBufferError>; } diff --git a/src/backends/android.rs b/src/backends/android.rs index 26cd055..206604c 100644 --- a/src/backends/android.rs +++ b/src/backends/android.rs @@ -139,6 +139,12 @@ impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> } } + /// The number of _pixels_ that a line in the buffer takes in memory. + #[inline] + pub fn stride(&self) -> u32 { + self.0.stride() as u32 + } + pub fn age(&self) -> u8 { todo!() } diff --git a/src/backends/kms.rs b/src/backends/kms.rs index da0369b..d6526ef 100644 --- a/src/backends/kms.rs +++ b/src/backends/kms.rs @@ -105,6 +105,9 @@ pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> { /// The current size. size: (NonZeroU32, NonZeroU32), + /// The current stride/pitch (length of a single row of pixels) in bytes. + stride: NonZeroU32, + /// The display implementation. display: &'a KmsDisplayImpl, @@ -243,6 +246,7 @@ impl SurfaceInterface fo .expect("Must set size of surface before calling `buffer_mut()`"); let size = set.size(); + let stride = set.pitch(); let [first_buffer, second_buffer] = &mut set.buffers; let (front_buffer, back_buffer) = if set.first_is_front { @@ -263,6 +267,7 @@ impl SurfaceInterface fo Ok(BufferImpl { mapping, size, + stride, first_is_front: &mut set.first_is_front, front_fb, crtc_handle: self.crtc.handle(), @@ -300,6 +305,19 @@ impl BufferInterface for BufferImpl<'_, D, W> { bytemuck::cast_slice_mut(self.mapping.as_mut()) } + /// The number of _pixels_ that a line in the buffer takes in memory. + #[inline] + pub fn stride(&self) -> u32 { + // TODO Return NonZeroU32? + let bpp: u32 = todo!(); + assert_eq!(self.stride.get() & bpp, 0); + // TODO: Since this may not always be a multiple of BPP, this API should return the size in + // bytes... And then the user is left to mess around with `fn pixels()`. We'll need a helper + // iterator accessor like: + // https://docs.rs/ndk/latest/ndk/native_window/struct.NativeWindowBufferLockGuard.html#method.lines + self.stride.get() / bpp + } + #[inline] fn age(&self) -> u8 { *self.front_age @@ -398,6 +416,10 @@ impl SharedBuffer { .and_then(|width| NonZeroU32::new(height).map(|height| (width, height))) .expect("buffer size is zero") } + + pub(crate) fn pitch(&self) -> NonZeroU32 { + NonZeroU32::new(self.db.pitch()).expect("Pitch (stride in bytes) is zero") + } } impl Buffers { @@ -405,4 +427,9 @@ impl Buffers { pub(crate) fn size(&self) -> (NonZeroU32, NonZeroU32) { self.buffers[0].size() } + + /// Get the pitch (stride) of this buffer. + pub(crate) fn pitch(&self) -> NonZeroU32 { + self.buffers[0].pitch() + } } diff --git a/src/backends/wayland/mod.rs b/src/backends/wayland/mod.rs index fe4cf36..0d747cd 100644 --- a/src/backends/wayland/mod.rs +++ b/src/backends/wayland/mod.rs @@ -243,6 +243,7 @@ impl SurfaceInterface Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() }) })?, age, + width: width.get() as u32, }) } } @@ -257,6 +258,7 @@ impl Drop for WaylandImpl { pub struct BufferImpl<'a, D: ?Sized, W> { stack: util::BorrowStack<'a, WaylandImpl, [u32]>, age: u8, + width: u32, } impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferInterface @@ -276,6 +278,11 @@ impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferInterface self.age } + #[inline] + fn stride(&self) -> u32 { + self.width + } + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { self.stack.into_container().present_with_damage(damage) } diff --git a/src/backends/x11.rs b/src/backends/x11.rs index bde94a7..f7fd39c 100644 --- a/src/backends/x11.rs +++ b/src/backends/x11.rs @@ -405,6 +405,16 @@ impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferInterf } } + #[inline] + pub fn stride(&self) -> u32 { + let (surface_width, _surface_height) = self + .0 + .size + .expect("Must set size of surface before calling `present_with_damage()`"); + + surface_width.get() as u32 + } + /// Push the buffer to the window. fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { let imp = self.0; diff --git a/src/lib.rs b/src/lib.rs index 1bd445b..a8aaa66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -211,6 +211,11 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> { self.buffer_impl.age() } + /// The number of _pixels_ that a line in the buffer takes in memory. + pub fn stride(&self) -> u32 { + self.buffer_impl.stride() + } + /// Presents buffer to the window. /// /// # Platform dependent behavior