diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e1b15..ec65322 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- **Breaking:** Remove generic type parameters `D` and `W` from `Buffer<'_>` struct. + # 0.4.7 - Fix documentation building on `docs.rs`. diff --git a/benches/buffer_mut.rs b/benches/buffer_mut.rs index 5a0fd7e..a121a85 100644 --- a/benches/buffer_mut.rs +++ b/benches/buffer_mut.rs @@ -36,18 +36,39 @@ fn buffer_mut(c: &mut criterion::Criterion) { c.bench_function("buffer_mut()", |b| { b.iter(|| { - for _ in 0..500 { - black_box(surface.buffer_mut().unwrap()); - } + black_box(surface.buffer_mut().unwrap()); }); }); c.bench_function("pixels_mut()", |b| { let mut buffer = surface.buffer_mut().unwrap(); b.iter(|| { - for _ in 0..500 { - let x: &mut [u32] = &mut buffer; - black_box(x); + let pixels: &mut [u32] = &mut buffer; + black_box(pixels); + }); + }); + + c.bench_function("fill", |b| { + let mut buffer = surface.buffer_mut().unwrap(); + b.iter(|| { + let buffer = black_box(&mut buffer); + buffer.fill(0x00000000); + }); + }); + + c.bench_function("render", |b| { + let mut buffer = surface.buffer_mut().unwrap(); + b.iter(|| { + let buffer = black_box(&mut buffer); + let width = buffer.width().get(); + for y in 0..buffer.height().get() { + for x in 0..buffer.width().get() { + let red = (x & 0xff) ^ (y & 0xff); + let green = (x & 0x7f) ^ (y & 0x7f); + let blue = (x & 0x3f) ^ (y & 0x3f); + let value = blue | (green << 8) | (red << 16); + buffer[(y * width + x) as usize] = value; + } } }); }); diff --git a/examples/raytracing/game.rs b/examples/raytracing/game.rs index 5b7abd9..6629c26 100644 --- a/examples/raytracing/game.rs +++ b/examples/raytracing/game.rs @@ -2,7 +2,6 @@ use std::time::{Duration, Instant}; use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; -use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use softbuffer::Buffer; use crate::camera::Camera; @@ -44,21 +43,13 @@ impl Game { } } - pub fn draw( - &self, - buffer: &mut Buffer<'_, impl HasDisplayHandle, impl HasWindowHandle>, - scale_factor: f32, - ) { + pub fn draw(&self, buffer: &mut Buffer<'_>, scale_factor: f32) { self.draw_scene(buffer, scale_factor); self.draw_ui(buffer, scale_factor); } /// Draw the 3D scene. - fn draw_scene( - &self, - buffer: &mut Buffer<'_, impl HasDisplayHandle, impl HasWindowHandle>, - scale_factor: f32, - ) { + fn draw_scene(&self, buffer: &mut Buffer<'_>, scale_factor: f32) { // Raytracing is expensive, so we only do it once every 4x4 pixel. // // FIXME(madsmtm): Avoid the need for this once we can do hardware scaling. @@ -130,11 +121,7 @@ impl Game { } /// Draw a simple example UI on top of the scene. - fn draw_ui( - &self, - buffer: &mut Buffer<'_, impl HasDisplayHandle, impl HasWindowHandle>, - scale_factor: f32, - ) { + fn draw_ui(&self, buffer: &mut Buffer<'_>, scale_factor: f32) { struct Rect { left: f32, right: f32, diff --git a/examples/rectangle.rs b/examples/rectangle.rs index e7e5346..5fde1d5 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -1,4 +1,3 @@ -use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use softbuffer::Buffer; use std::num::NonZeroU32; use winit::event::{ElementState, KeyEvent, WindowEvent}; @@ -7,7 +6,7 @@ use winit::keyboard::{Key, NamedKey}; mod util; -fn redraw(buffer: &mut Buffer<'_, impl HasDisplayHandle, impl HasWindowHandle>, flag: bool) { +fn redraw(buffer: &mut Buffer<'_>, flag: bool) { let width = buffer.width().get(); let height = buffer.height().get(); for y in 0..height { diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index 3bfe94b..9eaf779 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -76,7 +76,7 @@ macro_rules! make_dispatch { impl SurfaceInterface for SurfaceDispatch { type Context = ContextDispatch; - type Buffer<'a> = BufferDispatch<'a, D, W> where Self: 'a; + type Buffer<'a> = BufferDispatch<'a> where Self: 'a; fn new(window: W, display: &Self::Context) -> Result> where @@ -108,7 +108,7 @@ macro_rules! make_dispatch { } } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { match self { $( $(#[$attr])* @@ -138,14 +138,14 @@ macro_rules! make_dispatch { } } - pub(crate) enum BufferDispatch<'a, $dgen, $wgen> { + pub(crate) enum BufferDispatch<'a> { $( $(#[$attr])* $name($buffer_inner), )* } - impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> { + impl BufferInterface for BufferDispatch<'_> { #[inline] fn width(&self) -> NonZeroU32 { match self { @@ -214,7 +214,7 @@ macro_rules! make_dispatch { } } - impl fmt::Debug for BufferDispatch<'_, D, W> { + impl fmt::Debug for BufferDispatch<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { $( @@ -232,7 +232,7 @@ macro_rules! make_dispatch { make_dispatch! { => #[cfg(target_os = "android")] - Android(D, backends::android::AndroidImpl, backends::android::BufferImpl<'a, D, W>), + Android(D, backends::android::AndroidImpl, backends::android::BufferImpl<'a>), #[cfg(all( feature = "x11", not(any( @@ -243,7 +243,7 @@ make_dispatch! { target_os = "windows" )) ))] - X11(std::sync::Arc>, backends::x11::X11Impl, backends::x11::BufferImpl<'a, D, W>), + X11(std::sync::Arc>, backends::x11::X11Impl, backends::x11::BufferImpl<'a>), #[cfg(all( feature = "wayland", not(any( @@ -254,7 +254,7 @@ make_dispatch! { target_os = "windows" )) ))] - Wayland(std::sync::Arc>, backends::wayland::WaylandImpl, backends::wayland::BufferImpl<'a, D, W>), + Wayland(std::sync::Arc>, backends::wayland::WaylandImpl, backends::wayland::BufferImpl<'a>), #[cfg(all( feature = "kms", not(any( @@ -265,13 +265,13 @@ make_dispatch! { target_os = "windows" )) ))] - Kms(std::sync::Arc>, backends::kms::KmsImpl, backends::kms::BufferImpl<'a, D, W>), + Kms(std::sync::Arc>, backends::kms::KmsImpl, backends::kms::BufferImpl<'a>), #[cfg(target_os = "windows")] - Win32(D, backends::win32::Win32Impl, backends::win32::BufferImpl<'a, D, W>), + Win32(D, backends::win32::Win32Impl, backends::win32::BufferImpl<'a>), #[cfg(target_vendor = "apple")] - CoreGraphics(D, backends::cg::CGImpl, backends::cg::BufferImpl<'a, D, W>), + CoreGraphics(D, backends::cg::CGImpl, backends::cg::BufferImpl<'a>), #[cfg(target_family = "wasm")] - Web(backends::web::WebDisplayImpl, backends::web::WebImpl, backends::web::BufferImpl<'a, D, W>), + Web(backends::web::WebDisplayImpl, backends::web::WebImpl, backends::web::BufferImpl<'a>), #[cfg(target_os = "redox")] - Orbital(D, backends::orbital::OrbitalImpl, backends::orbital::BufferImpl<'a, D, W>), + Orbital(D, backends::orbital::OrbitalImpl, backends::orbital::BufferImpl<'a>), } diff --git a/src/backends/android.rs b/src/backends/android.rs index 12d489b..54dcae0 100644 --- a/src/backends/android.rs +++ b/src/backends/android.rs @@ -25,7 +25,7 @@ pub struct AndroidImpl { impl SurfaceInterface for AndroidImpl { type Context = D; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -76,7 +76,7 @@ impl SurfaceInterface for Android }) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { let native_window_buffer = self.native_window.lock(None).map_err(|err| { SoftBufferError::PlatformError( Some("Failed to lock ANativeWindow".to_owned()), @@ -104,7 +104,6 @@ impl SurfaceInterface for Android Ok(BufferImpl { native_window_buffer, buffer: util::PixelBuffer(buffer), - marker: PhantomData, }) } @@ -115,16 +114,15 @@ impl SurfaceInterface for Android } #[derive(Debug)] -pub struct BufferImpl<'a, D: ?Sized, W> { +pub struct BufferImpl<'a> { native_window_buffer: NativeWindowBufferLockGuard<'a>, buffer: util::PixelBuffer, - marker: PhantomData<(&'a D, &'a W)>, } // TODO: Move to NativeWindowBufferLockGuard? -unsafe impl<'a, D, W> Send for BufferImpl<'a, D, W> {} +unsafe impl Send for BufferImpl<'_> {} -impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { NonZeroU32::new(self.native_window_buffer.width() as u32).unwrap() } diff --git a/src/backends/cg.rs b/src/backends/cg.rs index a5dc52a..2cc27a6 100644 --- a/src/backends/cg.rs +++ b/src/backends/cg.rs @@ -127,7 +127,7 @@ impl Drop for CGImpl { impl SurfaceInterface for CGImpl { type Context = D; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -258,27 +258,33 @@ impl SurfaceInterface for CGImpl< Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { Ok(BufferImpl { buffer: util::PixelBuffer(vec![0; self.width * self.height]), - imp: self, + width: self.width, + height: self.height, + color_space: &self.color_space, + layer: &mut self.layer, }) } } #[derive(Debug)] -pub struct BufferImpl<'a, D, W> { - imp: &'a mut CGImpl, +pub struct BufferImpl<'a> { + width: usize, + height: usize, + color_space: &'a CGColorSpace, buffer: util::PixelBuffer, + layer: &'a mut SendCALayer, } -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { - NonZeroU32::new(self.imp.width as u32).unwrap() + NonZeroU32::new(self.width as u32).unwrap() } fn height(&self) -> NonZeroU32 { - NonZeroU32::new(self.imp.height as u32).unwrap() + NonZeroU32::new(self.height as u32).unwrap() } #[inline] @@ -333,12 +339,12 @@ impl BufferInterface for BufferImpl<'_, let image = unsafe { CGImage::new( - self.imp.width, - self.imp.height, + self.width, + self.height, 8, 32, - self.imp.width * 4, - Some(&self.imp.color_space), + self.width * 4, + Some(self.color_space), bitmap_info, Some(&data_provider), ptr::null(), @@ -355,7 +361,7 @@ impl BufferInterface for BufferImpl<'_, CATransaction::setDisableActions(true); // SAFETY: The contents is `CGImage`, which is a valid class for `contents`. - unsafe { self.imp.layer.setContents(Some(image.as_ref())) }; + unsafe { self.layer.setContents(Some(image.as_ref())) }; CATransaction::commit(); Ok(()) diff --git a/src/backends/kms.rs b/src/backends/kms.rs index d18d633..4b18dbd 100644 --- a/src/backends/kms.rs +++ b/src/backends/kms.rs @@ -13,7 +13,6 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, Raw use std::collections::HashSet; use std::fmt; -use std::marker::PhantomData; use std::num::NonZeroU32; use std::os::unix::io::{AsFd, BorrowedFd}; use std::sync::Arc; @@ -21,23 +20,28 @@ use std::sync::Arc; use crate::backend_interface::*; use crate::error::{InitError, SoftBufferError, SwResultExt}; -#[derive(Debug)] -pub(crate) struct KmsDisplayImpl { - /// The underlying raw device file descriptor. - fd: BorrowedFd<'static>, - - /// Holds a reference to the display. - _display: D, +#[derive(Debug, Clone)] +struct DrmDevice<'a> { + /// The underlying raw display file descriptor. + fd: BorrowedFd<'a>, } -impl AsFd for KmsDisplayImpl { +impl AsFd for DrmDevice<'_> { fn as_fd(&self) -> BorrowedFd<'_> { self.fd } } -impl Device for KmsDisplayImpl {} -impl CtrlDevice for KmsDisplayImpl {} +impl Device for DrmDevice<'_> {} +impl CtrlDevice for DrmDevice<'_> {} + +#[derive(Debug)] +pub(crate) struct KmsDisplayImpl { + device: DrmDevice<'static>, + + /// Holds a reference to the display. + _display: D, +} impl ContextInterface for Arc> { fn new(display: D) -> Result> @@ -55,7 +59,7 @@ impl ContextInterface for Arc let fd = unsafe { BorrowedFd::borrow_raw(drm.fd) }; Ok(Arc::new(KmsDisplayImpl { - fd, + device: DrmDevice { fd }, _display: display, })) } @@ -90,7 +94,7 @@ struct Buffers { } /// The buffer implementation. -pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> { +pub(crate) struct BufferImpl<'a> { /// The mapping of the dump buffer. mapping: DumbMapping<'a>, @@ -106,20 +110,17 @@ pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> { /// The current size. size: (NonZeroU32, NonZeroU32), - /// The display implementation. - display: &'a KmsDisplayImpl, + /// The device file descriptor. + device: DrmDevice<'a>, /// Age of the front buffer. front_age: &'a mut u8, /// Age of the back buffer. back_age: &'a mut u8, - - /// Window reference. - _window: PhantomData<&'a mut W>, } -impl fmt::Debug for BufferImpl<'_, D, W> { +impl fmt::Debug for BufferImpl<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME: Derive instead once `DumbMapping` impls `Debug`. f.debug_struct("BufferImpl").finish_non_exhaustive() @@ -142,12 +143,14 @@ struct SharedBuffer { impl SurfaceInterface for KmsImpl { type Context = Arc>; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; /// Create a new KMS backend. fn new(window: W, display: &Arc>) -> Result> { + let device = &display.device; + // Make sure that the window handle is valid. let RawWindowHandle::Drm(drm) = window.window_handle()?.as_raw() else { return Err(InitError::Unsupported(window)); @@ -156,10 +159,10 @@ impl SurfaceInterface fo NonZeroU32::new(drm.plane).ok_or(SoftBufferError::IncompleteWindowHandle)?; let plane_handle = plane::Handle::from(plane_handle); - let plane_info = display + let plane_info = device .get_plane(plane_handle) .swbuf_err("failed to get plane info")?; - let handles = display + let handles = device .resource_handles() .swbuf_err("failed to get resource handles")?; @@ -178,7 +181,7 @@ impl SurfaceInterface fo }; // Get info about the CRTC. - display + device .get_crtc(handle) .swbuf_err("failed to get CRTC info")? }; @@ -187,7 +190,7 @@ impl SurfaceInterface fo let encoders = handles .encoders .iter() - .flat_map(|handle| display.get_encoder(*handle)) + .flat_map(|handle| device.get_encoder(*handle)) .filter(|encoder| encoder.crtc() == Some(crtc.handle())) .map(|encoder| encoder.handle()) .collect::>(); @@ -196,7 +199,7 @@ impl SurfaceInterface fo let connectors = handles .connectors .iter() - .flat_map(|handle| display.get_connector(*handle, false)) + .flat_map(|handle| device.get_connector(*handle, false)) .filter(|connector| { connector .current_encoder() @@ -246,7 +249,7 @@ impl SurfaceInterface fo } */ - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { // Map the dumb buffer. let set = self .buffer @@ -268,6 +271,7 @@ impl SurfaceInterface fo let mapping = self .display + .device .map_dumb_buffer(&mut front_buffer.db) .swbuf_err("failed to map dumb buffer")?; @@ -277,10 +281,9 @@ impl SurfaceInterface fo first_is_front: &mut set.first_is_front, front_fb, crtc_handle: self.crtc.handle(), - display: &self.display, + device: self.display.device.clone(), front_age, back_age, - _window: PhantomData, }) } } @@ -289,6 +292,7 @@ impl Drop for KmsImpl { fn drop(&mut self) { // Map the CRTC to the information that was there before. self.display + .device .set_crtc( self.crtc.handle(), self.crtc.framebuffer(), @@ -300,7 +304,7 @@ impl Drop for KmsImpl { } } -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { self.size.0 } @@ -351,7 +355,7 @@ impl BufferInterface for BufferImpl<'_, D, W> { // TODO: It would be nice to not have to heap-allocate the above rectangles if we know that // this is going to fail. Low hanging fruit PR: add a flag that's set to false if this // returns `ENOSYS` and check that before allocating the above and running this. - match self.display.dirty_framebuffer(self.front_fb, &rectangles) { + match self.device.dirty_framebuffer(self.front_fb, &rectangles) { Ok(()) => {} Err(e) if e.raw_os_error() == Some(rustix::io::Errno::NOSYS.raw_os_error()) => {} Err(e) => { @@ -364,7 +368,7 @@ impl BufferInterface for BufferImpl<'_, D, W> { // Swap the buffers. // TODO: Use atomic commits here! - self.display + self.device .page_flip(self.crtc_handle, self.front_fb, PageFlipFlags::EVENT, None) .swbuf_err("failed to page flip")?; @@ -400,9 +404,11 @@ impl SharedBuffer { height: NonZeroU32, ) -> Result { let db = display + .device .create_dumb_buffer((width.get(), height.get()), DrmFourcc::Xrgb8888, 32) .swbuf_err("failed to create dumb buffer")?; let fb = display + .device .add_framebuffer(&db, 24, 32) .swbuf_err("failed to add framebuffer")?; diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index 301baba..adcd3db 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -75,64 +75,12 @@ impl OrbitalImpl { fn window_fd(&self) -> usize { self.handle.0.window.as_ptr() as usize } - - // Read the current width and size - fn window_size(&self) -> (usize, usize) { - let mut window_width = 0; - let mut window_height = 0; - - let mut buf: [u8; 4096] = [0; 4096]; - let count = syscall::fpath(self.window_fd(), &mut buf).unwrap(); - let path = str::from_utf8(&buf[..count]).unwrap(); - // orbital:/x/y/w/h/t - let mut parts = path.split('/').skip(3); - if let Some(w) = parts.next() { - window_width = w.parse::().unwrap_or(0); - } - if let Some(h) = parts.next() { - window_height = h.parse::().unwrap_or(0); - } - - (window_width, window_height) - } - - fn set_buffer(&self, buffer: &[u32], width_u32: u32, height_u32: u32) { - // Read the current width and size - let (window_width, window_height) = self.window_size(); - - { - // Map window buffer - let mut window_map = - unsafe { OrbitalMap::new(self.window_fd(), window_width * window_height * 4) } - .expect("failed to map orbital window"); - - // Window buffer is u32 color data in 0xAABBGGRR format - 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; - 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]); - } - - // Window buffer map is dropped here - } - - // Tell orbital to show the latest window data - syscall::fsync(self.window_fd()).expect("failed to sync orbital window"); - } } impl SurfaceInterface for OrbitalImpl { type Context = D; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -168,8 +116,8 @@ impl SurfaceInterface for Orbital Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { - let (window_width, window_height) = self.window_size(); + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + let (window_width, window_height) = window_size(self.window_fd()); let pixels = if self.width as usize == window_width && self.height as usize == window_height { Pixels::Mapping( @@ -183,7 +131,13 @@ impl SurfaceInterface for Orbital * self.height as usize ])) }; - Ok(BufferImpl { imp: self, pixels }) + Ok(BufferImpl { + window_fd: self.window_fd(), + width: self.width, + height: self.height, + presented: &mut self.presented, + pixels, + }) } } @@ -194,18 +148,21 @@ enum Pixels { } #[derive(Debug)] -pub struct BufferImpl<'a, D, W> { - imp: &'a mut OrbitalImpl, +pub struct BufferImpl<'a> { + window_fd: usize, + width: u32, + height: u32, + presented: &'a mut bool, pixels: Pixels, } -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { - NonZeroU32::new(self.imp.width as u32).unwrap() + NonZeroU32::new(self.width as u32).unwrap() } fn height(&self) -> NonZeroU32 { - NonZeroU32::new(self.imp.height as u32).unwrap() + NonZeroU32::new(self.height as u32).unwrap() } #[inline] @@ -226,7 +183,7 @@ impl BufferInterface for BufferImpl<'_, fn age(&self) -> u8 { match self.pixels { - Pixels::Mapping(_) if self.imp.presented => 1, + Pixels::Mapping(_) if *self.presented => 1, _ => 0, } } @@ -235,12 +192,11 @@ impl BufferInterface for BufferImpl<'_, match self.pixels { Pixels::Mapping(mapping) => { drop(mapping); - syscall::fsync(self.imp.window_fd()).expect("failed to sync orbital window"); - self.imp.presented = true; + syscall::fsync(self.window_fd).expect("failed to sync orbital window"); + *self.presented = true; } Pixels::Buffer(buffer) => { - self.imp - .set_buffer(&buffer, self.imp.width, self.imp.height); + set_buffer(self.window_fd, &buffer, self.width, self.height); } } @@ -251,3 +207,55 @@ impl BufferInterface for BufferImpl<'_, self.present() } } + +// Read the current width and size +fn window_size(window_fd: usize) -> (usize, usize) { + let mut window_width = 0; + let mut window_height = 0; + + let mut buf: [u8; 4096] = [0; 4096]; + let count = syscall::fpath(window_fd, &mut buf).unwrap(); + let path = str::from_utf8(&buf[..count]).unwrap(); + // orbital:/x/y/w/h/t + let mut parts = path.split('/').skip(3); + if let Some(w) = parts.next() { + window_width = w.parse::().unwrap_or(0); + } + if let Some(h) = parts.next() { + window_height = h.parse::().unwrap_or(0); + } + + (window_width, window_height) +} + +fn set_buffer(window_fd: usize, buffer: &[u32], width_u32: u32, height_u32: u32) { + // Read the current width and size + let (window_width, window_height) = window_size(window_fd); + + { + // Map window buffer + let mut window_map = + unsafe { OrbitalMap::new(window_fd, window_width * window_height * 4) } + .expect("failed to map orbital window"); + + // Window buffer is u32 color data in 0xAABBGGRR format + 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; + 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]); + } + + // Window buffer map is dropped here + } + + // Tell orbital to show the latest window data + syscall::fsync(window_fd).expect("failed to sync orbital window"); +} diff --git a/src/backends/wayland/buffer.rs b/src/backends/wayland/buffer.rs index 49e641f..e28653a 100644 --- a/src/backends/wayland/buffer.rs +++ b/src/backends/wayland/buffer.rs @@ -161,7 +161,11 @@ impl WaylandBuffer { self.width as usize * self.height as usize } - pub unsafe fn mapped_mut(&mut self) -> &mut [u32] { + #[inline] + pub fn mapped_mut(&mut self) -> &mut [u32] { + debug_assert!(self.len() * 4 <= self.map.len()); + // SAFETY: We're casting a `&mut [u8]` to `&mut [u32]`, the alignment of the memory region + // is at least 4, and the size of the region is large enough. unsafe { slice::from_raw_parts_mut(self.map.as_mut_ptr() as *mut u32, self.len()) } } } diff --git a/src/backends/wayland/mod.rs b/src/backends/wayland/mod.rs index 2d37494..d55e963 100644 --- a/src/backends/wayland/mod.rs +++ b/src/backends/wayland/mod.rs @@ -1,7 +1,8 @@ use crate::{ backend_interface::*, error::{InitError, SwResultExt}, - util, Rect, SoftBufferError, + util::BorrowStack, + Rect, SoftBufferError, }; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use std::{ @@ -89,71 +90,12 @@ pub struct WaylandImpl { window_handle: W, } -impl WaylandImpl { - fn surface(&self) -> &wl_surface::WlSurface { - self.surface.as_ref().unwrap() - } - - fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let _ = self - .display - .event_queue - .lock() - .unwrap_or_else(|x| x.into_inner()) - .dispatch_pending(&mut State); - - if let Some((front, back)) = &mut self.buffers { - // Swap front and back buffer - std::mem::swap(front, back); - - front.age = 1; - if back.age != 0 { - back.age += 1; - } - - front.attach(self.surface.as_ref().unwrap()); - - // Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if - // the compositor doesn't support `damage_buffer`. - // https://bugs.freedesktop.org/show_bug.cgi?id=78190 - if self.surface().version() < 4 { - self.surface().damage(0, 0, i32::MAX, i32::MAX); - } else { - for rect in damage { - // Introduced in version 4, it is an error to use this request in version 3 or lower. - let (x, y, width, height) = (|| { - Some(( - i32::try_from(rect.x).ok()?, - i32::try_from(rect.y).ok()?, - i32::try_from(rect.width.get()).ok()?, - i32::try_from(rect.height.get()).ok()?, - )) - })() - .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; - self.surface().damage_buffer(x, y, width, height); - } - } - - self.surface().commit(); - } - - let _ = self - .display - .event_queue - .lock() - .unwrap_or_else(|x| x.into_inner()) - .flush(); - - Ok(()) - } -} - impl SurfaceInterface for WaylandImpl { type Context = Arc>; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -199,7 +141,7 @@ impl SurfaceInterface Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { let (width, height) = self .size .expect("Must set size of surface before calling `buffer_mut()`"); @@ -242,13 +184,16 @@ 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; + let (front, back) = self.buffers.as_mut().unwrap(); + + let width = back.width; + let height = back.height; + let age = back.age; Ok(BufferImpl { - stack: util::BorrowStack::new(self, |buffer| { - Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() }) - })?, + event_queue: &self.display.event_queue, + surface: self.surface.as_ref().unwrap(), + front, + back: BorrowStack::new(back, |buffer| buffer.mapped_mut()), width, height, age, @@ -264,14 +209,17 @@ impl Drop for WaylandImpl { } #[derive(Debug)] -pub struct BufferImpl<'a, D: ?Sized, W> { - stack: util::BorrowStack<'a, WaylandImpl, [u32]>, +pub struct BufferImpl<'a> { + event_queue: &'a Mutex>, + surface: &'a wl_surface::WlSurface, + front: &'a mut WaylandBuffer, + back: BorrowStack<'a, WaylandBuffer, [u32]>, width: i32, height: i32, age: u8, } -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { NonZeroU32::new(self.width as u32).unwrap() } @@ -282,12 +230,12 @@ impl BufferInterface for Buffe #[inline] fn pixels(&self) -> &[u32] { - self.stack.member() + self.back.member() } #[inline] fn pixels_mut(&mut self) -> &mut [u32] { - self.stack.member_mut() + self.back.member_mut() } fn age(&self) -> u8 { @@ -295,20 +243,64 @@ impl BufferInterface for Buffe } fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { - self.stack.into_container().present_with_damage(damage) + let _ = self + .event_queue + .lock() + .unwrap_or_else(|x| x.into_inner()) + .dispatch_pending(&mut State); + + let back = self.back.into_container(); + + // Swap front and back buffer + std::mem::swap(self.front, back); + + self.front.age = 1; + if back.age != 0 { + back.age += 1; + } + + self.front.attach(self.surface); + + // Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if + // the compositor doesn't support `damage_buffer`. + // https://bugs.freedesktop.org/show_bug.cgi?id=78190 + if self.surface.version() < 4 { + self.surface.damage(0, 0, i32::MAX, i32::MAX); + } else { + for rect in damage { + // Introduced in version 4, it is an error to use this request in version 3 or lower. + let (x, y, width, height) = (|| { + Some(( + i32::try_from(rect.x).ok()?, + i32::try_from(rect.y).ok()?, + i32::try_from(rect.width.get()).ok()?, + i32::try_from(rect.height.get()).ok()?, + )) + })() + .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; + self.surface.damage_buffer(x, y, width, height); + } + } + + self.surface.commit(); + + let _ = self + .event_queue + .lock() + .unwrap_or_else(|x| x.into_inner()) + .flush(); + + Ok(()) } fn present(self) -> Result<(), SoftBufferError> { - let imp = self.stack.into_container(); - let (width, height) = imp - .size - .expect("Must set size of surface before calling `present()`"); - imp.present_with_damage(&[Rect { + let (width, height) = (self.width, self.height); + self.present_with_damage(&[Rect { x: 0, y: 0, - // We know width/height will be non-negative - width: width.try_into().unwrap(), - height: height.try_into().unwrap(), + // We know width/height will be non-negative and non-zero. + width: (width as u32).try_into().unwrap(), + height: (height as u32).try_into().unwrap(), }]) } } diff --git a/src/backends/web.rs b/src/backends/web.rs index 358e934..488bab7 100644 --- a/src/backends/web.rs +++ b/src/backends/web.rs @@ -122,95 +122,12 @@ impl WebImpl { Ok(ctx) } - - fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let (buffer_width, _buffer_height) = self - .size - .expect("Must set size of surface before calling `present_with_damage()`"); - - let union_damage = if let Some(rect) = util::union_damage(damage) { - rect - } else { - return Ok(()); - }; - - // Create a bitmap from the buffer. - let bitmap: Vec<_> = self - .buffer - .chunks_exact(buffer_width.get() as usize) - .skip(union_damage.y as usize) - .take(union_damage.height.get() as usize) - .flat_map(|row| { - row.iter() - .skip(union_damage.x as usize) - .take(union_damage.width.get() as usize) - }) - .copied() - .flat_map(|pixel| [(pixel >> 16) as u8, (pixel >> 8) as u8, pixel as u8, 255]) - .collect(); - - debug_assert_eq!( - bitmap.len() as u32, - union_damage.width.get() * union_damage.height.get() * 4 - ); - - #[cfg(target_feature = "atomics")] - #[allow(non_local_definitions)] - let result = { - // When using atomics, the underlying memory becomes `SharedArrayBuffer`, - // which can't be shared with `ImageData`. - use js_sys::{Uint8Array, Uint8ClampedArray}; - use wasm_bindgen::prelude::wasm_bindgen; - - #[wasm_bindgen] - extern "C" { - #[wasm_bindgen(js_name = ImageData)] - type ImageDataExt; - - #[wasm_bindgen(catch, constructor, js_class = ImageData)] - fn new(array: Uint8ClampedArray, sw: u32) -> Result; - } - - let array = Uint8Array::new_with_length(bitmap.len() as u32); - array.copy_from(&bitmap); - let array = Uint8ClampedArray::new(&array); - ImageDataExt::new(array, union_damage.width.get()) - .map(JsValue::from) - .map(ImageData::unchecked_from_js) - }; - #[cfg(not(target_feature = "atomics"))] - let result = ImageData::new_with_u8_clamped_array( - wasm_bindgen::Clamped(&bitmap), - union_damage.width.get(), - ); - // This should only throw an error if the buffer we pass's size is incorrect. - let image_data = result.unwrap(); - - for rect in damage { - // This can only throw an error if `data` is detached, which is impossible. - self.canvas - .put_image_data( - &image_data, - union_damage.x.into(), - union_damage.y.into(), - (rect.x - union_damage.x).into(), - (rect.y - union_damage.y).into(), - rect.width.get().into(), - rect.height.get().into(), - ) - .unwrap(); - } - - self.buffer_presented = true; - - Ok(()) - } } impl SurfaceInterface for WebImpl { type Context = WebDisplayImpl; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -263,8 +180,13 @@ impl SurfaceInterface for WebImpl Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { - Ok(BufferImpl { imp: self }) + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + Ok(BufferImpl { + canvas: &self.canvas, + buffer: &mut self.buffer, + buffer_presented: &mut self.buffer_presented, + size: self.size, + }) } fn fetch(&mut self) -> Result, SoftBufferError> { @@ -376,35 +298,36 @@ impl Canvas { } #[derive(Debug)] -pub struct BufferImpl<'a, D, W> { - imp: &'a mut WebImpl, +pub struct BufferImpl<'a> { + canvas: &'a Canvas, + buffer: &'a mut util::PixelBuffer, + buffer_presented: &'a mut bool, + size: Option<(NonZeroU32, NonZeroU32)>, } -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { - self.imp - .size + self.size .expect("must set size of surface before calling `width()` on the buffer") .0 } fn height(&self) -> NonZeroU32 { - self.imp - .size + self.size .expect("must set size of surface before calling `height()` on the buffer") .1 } fn pixels(&self) -> &[u32] { - &self.imp.buffer + self.buffer } fn pixels_mut(&mut self) -> &mut [u32] { - &mut self.imp.buffer + self.buffer } fn age(&self) -> u8 { - if self.imp.buffer_presented { + if *self.buffer_presented { 1 } else { 0 @@ -414,10 +337,9 @@ impl BufferInterface for BufferImpl<'_, /// Push the buffer to the canvas. fn present(self) -> Result<(), SoftBufferError> { let (width, height) = self - .imp .size .expect("Must set size of surface before calling `present()`"); - self.imp.present_with_damage(&[Rect { + self.present_with_damage(&[Rect { x: 0, y: 0, width, @@ -426,7 +348,86 @@ impl BufferInterface for BufferImpl<'_, } fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { - self.imp.present_with_damage(damage) + let (buffer_width, _buffer_height) = self + .size + .expect("Must set size of surface before calling `present_with_damage()`"); + + let union_damage = if let Some(rect) = util::union_damage(damage) { + rect + } else { + return Ok(()); + }; + + // Create a bitmap from the buffer. + let bitmap: Vec<_> = self + .buffer + .chunks_exact(buffer_width.get() as usize) + .skip(union_damage.y as usize) + .take(union_damage.height.get() as usize) + .flat_map(|row| { + row.iter() + .skip(union_damage.x as usize) + .take(union_damage.width.get() as usize) + }) + .copied() + .flat_map(|pixel| [(pixel >> 16) as u8, (pixel >> 8) as u8, pixel as u8, 255]) + .collect(); + + debug_assert_eq!( + bitmap.len() as u32, + union_damage.width.get() * union_damage.height.get() * 4 + ); + + #[cfg(target_feature = "atomics")] + #[allow(non_local_definitions)] + let result = { + // When using atomics, the underlying memory becomes `SharedArrayBuffer`, + // which can't be shared with `ImageData`. + use js_sys::{Uint8Array, Uint8ClampedArray}; + use wasm_bindgen::prelude::wasm_bindgen; + + #[wasm_bindgen] + extern "C" { + #[wasm_bindgen(js_name = ImageData)] + type ImageDataExt; + + #[wasm_bindgen(catch, constructor, js_class = ImageData)] + fn new(array: Uint8ClampedArray, sw: u32) -> Result; + } + + let array = Uint8Array::new_with_length(bitmap.len() as u32); + array.copy_from(&bitmap); + let array = Uint8ClampedArray::new(&array); + ImageDataExt::new(array, union_damage.width.get()) + .map(JsValue::from) + .map(ImageData::unchecked_from_js) + }; + #[cfg(not(target_feature = "atomics"))] + let result = ImageData::new_with_u8_clamped_array( + wasm_bindgen::Clamped(&bitmap), + union_damage.width.get(), + ); + // This should only throw an error if the buffer we pass's size is incorrect. + let image_data = result.unwrap(); + + for rect in damage { + // This can only throw an error if `data` is detached, which is impossible. + self.canvas + .put_image_data( + &image_data, + union_damage.x.into(), + union_damage.y.into(), + (rect.x - union_damage.x).into(), + (rect.y - union_damage.y).into(), + rect.width.get().into(), + rect.height.get().into(), + ) + .unwrap(); + } + + *self.buffer_presented = true; + + Ok(()) } } diff --git a/src/backends/win32.rs b/src/backends/win32.rs index 75de23e..f20318e 100644 --- a/src/backends/win32.rs +++ b/src/backends/win32.rs @@ -172,46 +172,10 @@ struct BitmapInfo { bmi_colors: [Gdi::RGBQUAD; 3], } -impl Win32Impl { - fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let buffer = self.buffer.as_mut().unwrap(); - unsafe { - for rect in damage.iter().copied() { - let (x, y, width, height) = (|| { - Some(( - i32::try_from(rect.x).ok()?, - i32::try_from(rect.y).ok()?, - i32::try_from(rect.width.get()).ok()?, - i32::try_from(rect.height.get()).ok()?, - )) - })() - .ok_or(SoftBufferError::DamageOutOfRange { rect })?; - Gdi::BitBlt( - self.dc.0, - x, - y, - width, - height, - buffer.dc, - x, - y, - Gdi::SRCCOPY, - ); - } - - // Validate the window. - Gdi::ValidateRect(self.window.0, ptr::null_mut()); - } - buffer.presented = true; - - Ok(()) - } -} - impl SurfaceInterface for Win32Impl { type Context = D; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -269,12 +233,17 @@ impl SurfaceInterface for Win32Im Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { - if self.buffer.is_none() { - panic!("Must set size of surface before calling `buffer_mut()`"); - } + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + let buffer = self + .buffer + .as_mut() + .expect("Must set size of surface before calling `buffer_mut()`"); - Ok(BufferImpl(self)) + Ok(BufferImpl { + window: &self.window, + dc: &self.dc, + buffer, + }) } /// Fetch the buffer from the window. @@ -284,49 +253,81 @@ impl SurfaceInterface for Win32Im } #[derive(Debug)] -pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl); +pub struct BufferImpl<'a> { + window: &'a OnlyUsedFromOrigin, + dc: &'a OnlyUsedFromOrigin, + buffer: &'a mut Buffer, +} -impl BufferInterface for BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { - self.0.buffer.as_ref().unwrap().width.try_into().unwrap() + self.buffer.width.try_into().unwrap() } fn height(&self) -> NonZeroU32 { - self.0.buffer.as_ref().unwrap().height.try_into().unwrap() + self.buffer.height.try_into().unwrap() } #[inline] fn pixels(&self) -> &[u32] { - self.0.buffer.as_ref().unwrap().pixels() + self.buffer.pixels() } #[inline] fn pixels_mut(&mut self) -> &mut [u32] { - self.0.buffer.as_mut().unwrap().pixels_mut() + self.buffer.pixels_mut() } fn age(&self) -> u8 { - match self.0.buffer.as_ref() { - Some(buffer) if buffer.presented => 1, - _ => 0, + if self.buffer.presented { + 1 + } else { + 0 } } fn present(self) -> Result<(), SoftBufferError> { - let imp = self.0; - let buffer = imp.buffer.as_ref().unwrap(); - imp.present_with_damage(&[Rect { + let (width, height) = (self.buffer.width, self.buffer.height); + self.present_with_damage(&[Rect { x: 0, y: 0, // We know width/height will be non-negative - width: buffer.width.try_into().unwrap(), - height: buffer.height.try_into().unwrap(), + width: width.try_into().unwrap(), + height: height.try_into().unwrap(), }]) } fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let imp = self.0; - imp.present_with_damage(damage) + unsafe { + for rect in damage.iter().copied() { + let (x, y, width, height) = (|| { + Some(( + i32::try_from(rect.x).ok()?, + i32::try_from(rect.y).ok()?, + i32::try_from(rect.width.get()).ok()?, + i32::try_from(rect.height.get()).ok()?, + )) + })() + .ok_or(SoftBufferError::DamageOutOfRange { rect })?; + Gdi::BitBlt( + self.dc.0, + x, + y, + width, + height, + self.buffer.dc, + x, + y, + Gdi::SRCCOPY, + ); + } + + // Validate the window. + Gdi::ValidateRect(self.window.0, ptr::null_mut()); + } + self.buffer.presented = true; + + Ok(()) } } @@ -474,6 +475,7 @@ impl Command { #[derive(Debug)] struct OnlyUsedFromOrigin(T); unsafe impl Send for OnlyUsedFromOrigin {} +unsafe impl Sync for OnlyUsedFromOrigin {} impl From for OnlyUsedFromOrigin { fn from(t: T) -> Self { diff --git a/src/backends/x11.rs b/src/backends/x11.rs index 711b0b7..cc448c0 100644 --- a/src/backends/x11.rs +++ b/src/backends/x11.rs @@ -189,7 +189,7 @@ struct ShmBuffer { impl SurfaceInterface for X11Impl { type Context = Arc>; type Buffer<'a> - = BufferImpl<'a, D, W> + = BufferImpl<'a> where Self: 'a; @@ -340,14 +340,22 @@ impl SurfaceInterface fo Ok(()) } - fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { tracing::trace!("buffer_mut: window={:X}", self.window); // Finish waiting on the previous `shm::PutImage` request, if any. self.buffer.finish_wait(self.display.connection())?; // We can now safely call `buffer_mut` on the buffer. - Ok(BufferImpl(self)) + Ok(BufferImpl { + connection: self.display.connection(), + window: self.window, + gc: self.gc, + depth: self.depth, + buffer: &mut self.buffer, + buffer_presented: &mut self.buffer_presented, + size: self.size, + }) } fn fetch(&mut self) -> Result, SoftBufferError> { @@ -388,33 +396,40 @@ impl SurfaceInterface fo } #[derive(Debug)] -pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl); +pub struct BufferImpl<'a> { + // Various fields that reference data in `X11Impl`. + connection: &'a XCBConnection, + window: xproto::Window, + gc: xproto::Gcontext, + depth: u8, + buffer: &'a mut Buffer, + buffer_presented: &'a mut bool, + size: Option<(NonZeroU16, NonZeroU16)>, +} -impl BufferInterface - for BufferImpl<'_, D, W> -{ +impl BufferInterface for BufferImpl<'_> { fn width(&self) -> NonZeroU32 { - self.0.size.unwrap().0.into() + self.size.unwrap().0.into() } fn height(&self) -> NonZeroU32 { - self.0.size.unwrap().1.into() + self.size.unwrap().1.into() } #[inline] fn pixels(&self) -> &[u32] { // SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`. - unsafe { self.0.buffer.buffer() } + unsafe { self.buffer.buffer() } } #[inline] fn pixels_mut(&mut self) -> &mut [u32] { // SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer_mut`. - unsafe { self.0.buffer.buffer_mut() } + unsafe { self.buffer.buffer_mut() } } fn age(&self) -> u8 { - if self.0.buffer_presented { + if *self.buffer_presented { 1 } else { 0 @@ -423,31 +438,28 @@ impl BufferInterface /// Push the buffer to the window. fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let imp = self.0; - - let (surface_width, surface_height) = imp + let (surface_width, surface_height) = self .size .expect("Must set size of surface before calling `present_with_damage()`"); - tracing::trace!("present: window={:X}", imp.window); + tracing::trace!("present: window={:X}", self.window); - match imp.buffer { + match self.buffer { Buffer::Wire(ref wire) => { // This is a suboptimal strategy, raise a stink in the debug logs. tracing::debug!("Falling back to non-SHM method for window drawing."); - imp.display - .connection() + self.connection .put_image( xproto::ImageFormat::Z_PIXMAP, - imp.window, - imp.gc, + self.window, + self.gc, surface_width.get(), surface_height.get(), 0, 0, 0, - imp.depth, + self.depth, bytemuck::cast_slice(wire), ) .map(|c| c.ignore_error()) @@ -475,11 +487,10 @@ impl BufferInterface })( ) .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; - imp.display - .connection() + self.connection .shm_put_image( - imp.window, - imp.gc, + self.window, + self.gc, surface_width.get(), surface_height.get(), src_x, @@ -488,7 +499,7 @@ impl BufferInterface height, dst_x, dst_y, - imp.depth, + self.depth, xproto::ImageFormat::Z_PIXMAP.into(), false, segment_id, @@ -500,21 +511,20 @@ impl BufferInterface }) .and_then(|()| { // Send a short request to act as a notification for when the X server is done processing the image. - shm.begin_wait(imp.display.connection()) + shm.begin_wait(self.connection) .swbuf_err("Failed to draw image to window") })?; } } } - imp.buffer_presented = true; + *self.buffer_presented = true; Ok(()) } fn present(self) -> Result<(), SoftBufferError> { let (width, height) = self - .0 .size .expect("Must set size of surface before calling `present()`"); self.present_with_damage(&[Rect { diff --git a/src/lib.rs b/src/lib.rs index 7923c3e..82e0f9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,7 +136,7 @@ impl Surface { /// - On DRM/KMS, there is no reliable and sound way to wait for the page flip to happen from within /// `softbuffer`. Therefore it is the responsibility of the user to wait for the page flip before /// sending another frame. - pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { Ok(Buffer { buffer_impl: self.surface_impl.buffer_mut()?, _marker: PhantomData, @@ -202,12 +202,12 @@ impl HasWindowHandle for Surface /// Buffer copies an channel swizzling happen on: /// - Android #[derive(Debug)] -pub struct Buffer<'a, D, W> { - buffer_impl: BufferDispatch<'a, D, W>, - _marker: PhantomData<(Arc, Cell<()>)>, +pub struct Buffer<'a> { + buffer_impl: BufferDispatch<'a>, + _marker: PhantomData>, } -impl Buffer<'_, D, W> { +impl Buffer<'_> { /// The amount of pixels wide the buffer is. pub fn width(&self) -> NonZeroU32 { let width = self.buffer_impl.width(); @@ -272,7 +272,7 @@ impl Buffer<'_, D, W> { } } -impl ops::Deref for Buffer<'_, D, W> { +impl ops::Deref for Buffer<'_> { type Target = [u32]; #[inline] @@ -281,7 +281,7 @@ impl ops::Deref for Buffer<'_, D, W> { } } -impl ops::DerefMut for Buffer<'_, D, W> { +impl ops::DerefMut for Buffer<'_> { #[inline] fn deref_mut(&mut self) -> &mut [u32] { self.buffer_impl.pixels_mut() @@ -358,7 +358,7 @@ fn __assert_send() { is_send::>(); is_sync::>(); is_send::>(); - is_send::>(); + is_send::>(); /// ```compile_fail /// use softbuffer::Surface; @@ -371,7 +371,7 @@ fn __assert_send() { /// use softbuffer::Buffer; /// /// fn __is_sync() {} - /// __is_sync::>(); + /// __is_sync::>(); /// ``` fn __buffer_not_sync() {} } diff --git a/src/util.rs b/src/util.rs index 572de5e..f0f3ab4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,7 +7,6 @@ use std::num::NonZeroU32; use std::ops; use crate::Rect; -use crate::SoftBufferError; /// Takes a mutable reference to a container and a function deriving a /// reference into it, and stores both, making it possible to get back the @@ -24,17 +23,17 @@ pub struct BorrowStack<'a, T: 'a + ?Sized, U: 'a + ?Sized> { unsafe impl<'a, T: 'a + Send + ?Sized, U: 'a + Send + ?Sized> Send for BorrowStack<'a, T, U> {} impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> { - pub fn new(container: &'a mut T, f: F) -> Result + pub fn new(container: &'a mut T, f: F) -> Self where - F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>, + F: for<'b> FnOnce(&'b mut T) -> &'b mut U, { let container = container as *mut T; - let member = f(unsafe { &mut *container })? as *mut U; - Ok(Self { + let member = f(unsafe { &mut *container }) as *mut U; + Self { container, member, _phantom: std::marker::PhantomData, - }) + } } pub fn member(&self) -> &U { @@ -131,7 +130,7 @@ mod tests { } let mut v = vec![1, 2, 3, 4, 5]; - f(BorrowStack::new(v.as_mut(), |v: &mut [u32]| Ok(&mut v[2])).unwrap()); + f(BorrowStack::new(v.as_mut(), |v: &mut [u32]| &mut v[2])); assert_eq!(&v, &[1, 2, 42, 4, 5]); } }