diff --git a/CHANGELOG.md b/CHANGELOG.md index c93804ef..e806e037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Update to `objc2` 0.6.0. - Bump MSRV to Rust 1.71. - Make `Context` cloneable. +- Added `Buffer::width()` and `Buffer::height()` getters. # 0.4.6 diff --git a/README.md b/README.md index 421f4f13..85faaaee 100644 --- a/README.md +++ b/README.md @@ -101,21 +101,18 @@ 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; + for index in 0..(buffer.width().get() * buffer.height().get()) { + let y = index / buffer.width().get(); + let x = index % buffer.width().get(); let red = x % 255; let green = y % 255; let blue = (x * y) % 255; diff --git a/examples/animation.rs b/examples/animation.rs index 6b10902a..cfc41747 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -57,23 +57,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().get(), buffer.height().get()); + 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(); } WindowEvent::CloseRequested | WindowEvent::KeyboardInput { @@ -97,7 +94,7 @@ fn main() { winit_app::run_app(event_loop, app); } -fn pre_render_frames(width: usize, height: usize) -> Vec> { +fn pre_render_frames(width: u32, height: u32) -> Vec> { let render = |frame_id| { let elapsed = ((frame_id as f64) / (60.0)) * 2.0 * PI; diff --git a/examples/fruit.rs b/examples/fruit.rs index 0bd9fc42..f07fce2d 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -50,14 +50,14 @@ fn main() { }; let mut buffer = surface.buffer_mut().unwrap(); - let width = fruit.width() as usize; + let width = fruit.width(); for (x, y, pixel) in fruit.pixels() { let red = pixel.0[0] as u32; let green = pixel.0[1] as u32; let blue = pixel.0[2] as u32; let color = blue | (green << 8) | (red << 16); - buffer[y as usize * width + x as usize] = color; + buffer[(y * width + x) as usize] = color; } buffer.present().unwrap(); diff --git a/examples/rectangle.rs b/examples/rectangle.rs index 970c35d1..b6558666 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, 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().get(); + let height = buffer.height().get(); for y in 0..height { for x in 0..width { let value = if flag && x >= 100 && x < width - 100 && y >= 100 && y < height - 100 { @@ -15,9 +19,9 @@ fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { let red = (x & 0xff) ^ (y & 0xff); let green = (x & 0x7f) ^ (y & 0x7f); let blue = (x & 0x3f) ^ (y & 0x3f); - (blue | (green << 8) | (red << 16)) as u32 + blue | (green << 8) | (red << 16) }; - buffer[y * width + x] = value; + buffer[(y * width + x) as usize] = value; } } } @@ -66,21 +70,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(); } WindowEvent::CloseRequested diff --git a/examples/winit.rs b/examples/winit.rs index c27f3ef2..044ae391 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -43,23 +43,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().get() { + for x in 0..buffer.width().get() { + let red = x % 255; + let green = y % 255; + let blue = (x * y) % 255; + let index = y * buffer.width().get() + x; + buffer[index as usize] = blue | (green << 8) | (red << 16); + } } + + buffer.present().unwrap(); } WindowEvent::CloseRequested | WindowEvent::KeyboardInput { diff --git a/examples/winit_multithread.rs b/examples/winit_multithread.rs index d1ad0b7d..36ae2b2c 100644 --- a/examples/winit_multithread.rs +++ b/examples/winit_multithread.rs @@ -40,13 +40,13 @@ 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() { + for y in 0..buffer.height().get() { + for x in 0..buffer.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); + let index = y * buffer.width().get() + x; + buffer[index as usize] = blue | (green << 8) | (red << 16); } } diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index faee3ff3..ec74c652 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(); let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap(); @@ -19,10 +16,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 }, @@ -42,14 +36,15 @@ fn main() { }; 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 width = buffer.width().get(); + for y in 0..buffer.height().get() { + for x in 0..width { + let red = x % 255; + let green = y % 255; + let blue = (x * y) % 255; let color = blue | (green << 8) | (red << 16); - buffer[y * BUFFER_WIDTH + x] = color; + buffer[(y * width + x) as usize] = color; } } buffer.present().unwrap(); diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index 3b5d269c..5a34a7c5 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -125,6 +125,26 @@ macro_rules! make_dispatch { } impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> { + #[inline] + fn width(&self) -> NonZeroU32 { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.width(), + )* + } + } + + #[inline] + fn height(&self) -> NonZeroU32 { + 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 13e3555c..b6a56661 100644 --- a/src/backend_interface.rs +++ b/src/backend_interface.rs @@ -35,6 +35,8 @@ pub(crate) trait SurfaceInterface NonZeroU32; + fn height(&self) -> NonZeroU32; 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 a14aaefd..916cde85 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) -> NonZeroU32 { + NonZeroU32::new(self.native_window_buffer.width() as u32).unwrap() + } + + fn height(&self) -> NonZeroU32 { + NonZeroU32::new(self.native_window_buffer.height() as u32).unwrap() + } + #[inline] fn pixels(&self) -> &[u32] { &self.buffer diff --git a/src/backends/cg.rs b/src/backends/cg.rs index a7241289..6e8999d5 100644 --- a/src/backends/cg.rs +++ b/src/backends/cg.rs @@ -270,6 +270,14 @@ pub struct BufferImpl<'a, D, W> { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> NonZeroU32 { + NonZeroU32::new(self.imp.width as u32).unwrap() + } + + fn height(&self) -> NonZeroU32 { + NonZeroU32::new(self.imp.height as u32).unwrap() + } + #[inline] fn pixels(&self) -> &[u32] { &self.buffer diff --git a/src/backends/kms.rs b/src/backends/kms.rs index 35ed5b8f..3008e8c2 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) -> NonZeroU32 { + self.size.0 + } + + fn height(&self) -> NonZeroU32 { + self.size.1 + } + #[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 d54683f1..cea6feb0 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) -> NonZeroU32 { + NonZeroU32::new(self.imp.width as u32).unwrap() + } + + fn height(&self) -> NonZeroU32 { + NonZeroU32::new(self.imp.height as u32).unwrap() + } + #[inline] fn pixels(&self) -> &[u32] { match &self.pixels { diff --git a/src/backends/wayland/buffer.rs b/src/backends/wayland/buffer.rs index c4ebef0d..407dd742 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 000e553c..d497484a 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) -> NonZeroU32 { + NonZeroU32::new(self.width as u32).unwrap() + } + + fn height(&self) -> NonZeroU32 { + NonZeroU32::new(self.height as usize as u32).unwrap() + } + #[inline] fn pixels(&self) -> &[u32] { self.stack.member() diff --git a/src/backends/web.rs b/src/backends/web.rs index 6ebc70d3..3b8efa19 100644 --- a/src/backends/web.rs +++ b/src/backends/web.rs @@ -378,6 +378,20 @@ pub struct BufferImpl<'a, D, W> { } impl BufferInterface for BufferImpl<'_, D, W> { + fn width(&self) -> NonZeroU32 { + self.imp + .size + .expect("must set size of surface before calling `width()` on the buffer") + .0 + } + + fn height(&self) -> NonZeroU32 { + self.imp + .size + .expect("must set size of surface before calling `height()` on the buffer") + .1 + } + fn pixels(&self) -> &[u32] { &self.imp.buffer } diff --git a/src/backends/win32.rs b/src/backends/win32.rs index 72dc6d0f..3436f556 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) -> NonZeroU32 { + self.0.buffer.as_ref().unwrap().width.try_into().unwrap() + } + + fn height(&self) -> NonZeroU32 { + self.0.buffer.as_ref().unwrap().height.try_into().unwrap() + } + #[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 b4271f53..f1429711 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) -> NonZeroU32 { + self.0.size.unwrap().0.into() + } + + fn height(&self) -> NonZeroU32 { + self.0.size.unwrap().1.into() + } + #[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 ec3f1e9b..03246c04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,6 +206,28 @@ pub struct Buffer<'a, D, W> { } impl Buffer<'_, D, W> { + /// The amount of pixels wide the buffer is. + pub fn width(&self) -> NonZeroU32 { + let width = self.buffer_impl.width(); + debug_assert_eq!( + width.get() as usize * self.buffer_impl.height().get() as usize, + self.len(), + "buffer must be sized correctly" + ); + width + } + + /// The amount of pixels tall the buffer is. + pub fn height(&self) -> NonZeroU32 { + let height = self.buffer_impl.height(); + debug_assert_eq!( + height.get() as usize * self.buffer_impl.width().get() as usize, + 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