diff --git a/CHANGELOG.md b/CHANGELOG.md index 8669f2a..04bc710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Update to `objc2` 0.6.0. - Bump MSRV to Rust 1.71. +- Added `Buffer::width` and `Buffer::height`. # 0.4.6 diff --git a/README.md b/README.md index c17e01f..4b430a8 100644 --- a/README.md +++ b/README.md @@ -101,26 +101,23 @@ fn main() { eprintln!("RedrawRequested fired before Resumed or after Suspended"); return; }; - let (width, height) = { - let size = window.inner_size(); - (size.width, size.height) - }; + let size = window.inner_size(); surface .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), ) .unwrap(); let mut buffer = surface.buffer_mut().unwrap(); - for index in 0..(width * height) { - let y = index / width; - let x = index % width; - let red = x % 255; - let green = y % 255; - let blue = (x * y) % 255; - - buffer[index as usize] = blue | (green << 8) | (red << 16); + for index in 0..(buffer.width() * buffer.height()) { + let y = index / buffer.width(); + let x = index % buffer.width(); + let red = x as u32 % 255; + let green = y as u32 % 255; + let blue = (x as u32 * y as u32) % 255; + + buffer[index] = blue | (green << 8) | (red << 16); } buffer.present().unwrap(); diff --git a/examples/animation.rs b/examples/animation.rs index c075923..c6d503a 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -59,23 +59,20 @@ fn main() { return; }; - let size = window.inner_size(); - if let (Some(width), Some(height)) = - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - { - let elapsed = start.elapsed().as_secs_f64() % 1.0; + let elapsed = start.elapsed().as_secs_f64() % 1.0; - if (width.get(), height.get()) != *old_size { - *old_size = (width.get(), height.get()); - *frames = pre_render_frames(width.get() as usize, height.get() as usize); - }; + let mut buffer = surface.buffer_mut().unwrap(); - let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; - - let mut buffer = surface.buffer_mut().unwrap(); - buffer.copy_from_slice(frame); - buffer.present().unwrap(); + let size = (buffer.width(), buffer.height()); + if size != *old_size { + *old_size = size; + *frames = pre_render_frames(size.0, size.1); } + + let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; + + buffer.copy_from_slice(frame); + buffer.present().unwrap(); } Event::AboutToWait => { window.request_redraw(); diff --git a/examples/rectangle.rs b/examples/rectangle.rs index b92f30b..aba1a88 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -1,3 +1,5 @@ +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use softbuffer::Buffer; use std::num::NonZeroU32; use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; @@ -6,7 +8,9 @@ use winit::keyboard::{Key, NamedKey}; #[path = "utils/winit_app.rs"] mod winit_app; -fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { +fn redraw(buffer: &mut Buffer<'_, impl HasDisplayHandle, impl HasWindowHandle>, flag: bool) { + let width = buffer.width(); + let height = buffer.height(); for y in 0..height { for x in 0..width { let value = if flag && x >= 100 && x < width - 100 && y >= 100 && y < height - 100 { @@ -71,21 +75,10 @@ fn main() { eprintln!("RedrawRequested fired before Resumed or after Suspended"); return; }; - // Grab the window's client area dimensions, and ensure they're valid - let size = window.inner_size(); - if let (Some(width), Some(height)) = - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - { - // Draw something in the window - let mut buffer = surface.buffer_mut().unwrap(); - redraw( - &mut buffer, - width.get() as usize, - height.get() as usize, - *flag, - ); - buffer.present().unwrap(); - } + // Draw something in the window + let mut buffer = surface.buffer_mut().unwrap(); + redraw(&mut buffer, *flag); + buffer.present().unwrap(); } Event::WindowEvent { diff --git a/examples/winit.rs b/examples/winit.rs index 27a3cef..a18d601 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -49,23 +49,19 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { eprintln!("RedrawRequested fired before Resumed or after Suspended"); return; }; - let size = window.inner_size(); - if let (Some(width), Some(height)) = - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - { - let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..height.get() { - for x in 0..width.get() { - 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; - buffer[index] = blue | (green << 8) | (red << 16); - } - } - buffer.present().unwrap(); + let mut buffer = surface.buffer_mut().unwrap(); + for y in 0..buffer.height() { + for x in 0..buffer.width() { + let red = x as u32 % 255; + let green = y as u32 % 255; + let blue = (x as u32 * y as u32) % 255; + let index = y * buffer.width() + x; + buffer[index] = blue | (green << 8) | (red << 16); + } } + + buffer.present().unwrap(); } Event::WindowEvent { event: diff --git a/examples/winit_multithread.rs b/examples/winit_multithread.rs index 03afcc5..140b035 100644 --- a/examples/winit_multithread.rs +++ b/examples/winit_multithread.rs @@ -40,12 +40,12 @@ pub mod ex { surface.resize(width, height).unwrap(); let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..height.get() { - for x in 0..width.get() { - 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; + for y in 0..buffer.height() { + for x in 0..buffer.width() { + let red = x as u32 % 255; + let green = y as u32 % 255; + let blue = (x as u32 * y as u32) % 255; + let index = y * buffer.width() + x; buffer[index] = blue | (green << 8) | (red << 16); } } diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 0c58a11..febe7e0 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -6,9 +6,6 @@ use winit::keyboard::{Key, NamedKey}; #[path = "utils/winit_app.rs"] mod winit_app; -const BUFFER_WIDTH: usize = 256; -const BUFFER_HEIGHT: usize = 128; - fn main() { let event_loop = EventLoop::new().unwrap(); @@ -24,10 +21,7 @@ fn main() { let mut surface = softbuffer::Surface::new(context, window.clone()).unwrap(); // Intentionally set the size of the surface to something different than the size of the window. surface - .resize( - NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(), - NonZeroU32::new(BUFFER_HEIGHT as u32).unwrap(), - ) + .resize(NonZeroU32::new(256).unwrap(), NonZeroU32::new(128).unwrap()) .unwrap(); surface }, @@ -47,14 +41,15 @@ fn main() { }; let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..BUFFER_HEIGHT { - for x in 0..BUFFER_WIDTH { + let width = buffer.width(); + for y in 0..buffer.height() { + for x in 0..width { let red = x as u32 % 255; let green = y as u32 % 255; let blue = (x as u32 * y as u32) % 255; let color = blue | (green << 8) | (red << 16); - buffer[y * BUFFER_WIDTH + x] = color; + buffer[y * width + x] = color; } } buffer.present().unwrap(); diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index a86832e..bdb42db 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -124,6 +124,26 @@ macro_rules! make_dispatch { } impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> { + #[inline] + fn width(&self) -> usize { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.width(), + )* + } + } + + #[inline] + fn height(&self) -> usize { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.height(), + )* + } + } + #[inline] fn pixels(&self) -> &[u32] { match self { diff --git a/src/backend_interface.rs b/src/backend_interface.rs index 13e3555..4939dc9 100644 --- a/src/backend_interface.rs +++ b/src/backend_interface.rs @@ -35,6 +35,8 @@ pub(crate) trait SurfaceInterface usize; + fn height(&self) -> usize; fn pixels(&self) -> &[u32]; fn pixels_mut(&mut self) -> &mut [u32]; fn age(&self) -> u8; diff --git a/src/backends/android.rs b/src/backends/android.rs index a14aaef..a3ae752 100644 --- a/src/backends/android.rs +++ b/src/backends/android.rs @@ -123,6 +123,14 @@ pub struct BufferImpl<'a, D: ?Sized, W> { unsafe impl<'a, D, W> Send for BufferImpl<'a, D, W> {} impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { + fn width(&self) -> usize { + self.native_window_buffer.width() + } + + fn height(&self) -> usize { + self.native_window_buffer.height() + } + #[inline] fn pixels(&self) -> &[u32] { &self.buffer diff --git a/src/backends/cg.rs b/src/backends/cg.rs index ba6c17a..677634d 100644 --- a/src/backends/cg.rs +++ b/src/backends/cg.rs @@ -269,6 +269,14 @@ pub struct BufferImpl<'a, D, W> { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.imp.width + } + + fn height(&self) -> usize { + self.imp.height + } + #[inline] fn pixels(&self) -> &[u32] { &self.buffer diff --git a/src/backends/kms.rs b/src/backends/kms.rs index 35ed5b8..a2d6361 100644 --- a/src/backends/kms.rs +++ b/src/backends/kms.rs @@ -293,6 +293,14 @@ impl Drop for KmsImpl { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.size.0.get() as usize + } + + fn height(&self) -> usize { + self.size.1.get() as usize + } + #[inline] fn pixels(&self) -> &[u32] { bytemuck::cast_slice(self.mapping.as_ref()) diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index d54683f..c449e92 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -191,6 +191,14 @@ pub struct BufferImpl<'a, D, W> { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.imp.width as usize + } + + fn height(&self) -> usize { + self.imp.height as usize + } + #[inline] fn pixels(&self) -> &[u32] { match &self.pixels { diff --git a/src/backends/wayland/buffer.rs b/src/backends/wayland/buffer.rs index c4ebef0..407dd74 100644 --- a/src/backends/wayland/buffer.rs +++ b/src/backends/wayland/buffer.rs @@ -74,8 +74,8 @@ pub(super) struct WaylandBuffer { pool: wl_shm_pool::WlShmPool, pool_size: i32, buffer: wl_buffer::WlBuffer, - width: i32, - height: i32, + pub width: i32, + pub height: i32, released: Arc, pub age: u8, } diff --git a/src/backends/wayland/mod.rs b/src/backends/wayland/mod.rs index 000e553..eabc7ce 100644 --- a/src/backends/wayland/mod.rs +++ b/src/backends/wayland/mod.rs @@ -240,11 +240,15 @@ impl SurfaceInterface )); }; + let width = self.buffers.as_mut().unwrap().1.width; + let height = self.buffers.as_mut().unwrap().1.height; let age = self.buffers.as_mut().unwrap().1.age; Ok(BufferImpl { stack: util::BorrowStack::new(self, |buffer| { Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() }) })?, + width, + height, age, }) } @@ -259,10 +263,20 @@ impl Drop for WaylandImpl { pub struct BufferImpl<'a, D: ?Sized, W> { stack: util::BorrowStack<'a, WaylandImpl, [u32]>, + width: i32, + height: i32, age: u8, } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.width as usize + } + + fn height(&self) -> usize { + self.height as usize + } + #[inline] fn pixels(&self) -> &[u32] { self.stack.member() diff --git a/src/backends/web.rs b/src/backends/web.rs index 4eb8fe0..64e35e4 100644 --- a/src/backends/web.rs +++ b/src/backends/web.rs @@ -377,6 +377,22 @@ pub struct BufferImpl<'a, D, W> { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.imp + .size + .expect("must set size of surface before calling `width()` on the buffer") + .0 + .get() as usize + } + + fn height(&self) -> usize { + self.imp + .size + .expect("must set size of surface before calling `height()` on the buffer") + .1 + .get() as usize + } + fn pixels(&self) -> &[u32] { &self.imp.buffer } diff --git a/src/backends/win32.rs b/src/backends/win32.rs index 72dc6d0..eda528c 100644 --- a/src/backends/win32.rs +++ b/src/backends/win32.rs @@ -284,6 +284,14 @@ impl SurfaceInterface for Win32Im pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl); impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.0.buffer.as_ref().unwrap().width.get() as usize + } + + fn height(&self) -> usize { + self.0.buffer.as_ref().unwrap().height.get() as usize + } + #[inline] fn pixels(&self) -> &[u32] { self.0.buffer.as_ref().unwrap().pixels() diff --git a/src/backends/x11.rs b/src/backends/x11.rs index b4271f5..a141334 100644 --- a/src/backends/x11.rs +++ b/src/backends/x11.rs @@ -388,6 +388,14 @@ pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl); impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> usize { + self.0.size.unwrap().0.get() as usize + } + + fn height(&self) -> usize { + self.0.size.unwrap().1.get() as usize + } + #[inline] fn pixels(&self) -> &[u32] { // SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`. diff --git a/src/lib.rs b/src/lib.rs index 2e25967..ee085e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,6 +205,28 @@ pub struct Buffer<'a, D, W> { } impl Buffer<'_, D, W> { + /// The amount of pixels wide the buffer is. + pub fn width(&self) -> usize { + let width = self.buffer_impl.width(); + debug_assert_eq!( + width * self.buffer_impl.height(), + self.len(), + "buffer must be sized correctly" + ); + width + } + + /// The amount of pixels tall the buffer is. + pub fn height(&self) -> usize { + let height = self.buffer_impl.height(); + debug_assert_eq!( + height * self.buffer_impl.width(), + self.len(), + "buffer must be sized correctly" + ); + height + } + /// `age` is the number of frames ago this buffer was last presented. So if the value is /// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame /// before that (for backends using double buffering). If the value is `0`, it is a new