From 7f95385f72b117b74bf90fae0e49c99ff5033e50 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sat, 27 Jan 2024 14:55:33 -0800 Subject: [PATCH 1/5] Use traits to define common backend interface This still uses enums to dispatch to the backends, but has the `*Dispatch` types implement the same traits. Nothing about the behavior or performance should change. If we require backends to implement the same methods, it seems good to use traits for that. Any documentation on the interface implemented by backends can be in one place. The traits can provide default implementations where appropriate. Hopefully this will help with more refactoring and features. --- src/backend_dispatch.rs | 162 +++++++++++++++++++++++++++++++++++++++ src/backend_interface.rs | 31 ++++++++ src/cg.rs | 29 ++++--- src/kms.rs | 36 ++++----- src/lib.rs | 156 +------------------------------------ src/orbital.rs | 79 ++++++++++--------- src/wayland/mod.rs | 133 ++++++++++++++++---------------- src/web.rs | 73 +++++++++--------- src/win32.rs | 74 +++++++++--------- src/x11.rs | 35 ++++----- 10 files changed, 426 insertions(+), 382 deletions(-) create mode 100644 src/backend_dispatch.rs create mode 100644 src/backend_interface.rs diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs new file mode 100644 index 00000000..825d08ef --- /dev/null +++ b/src/backend_dispatch.rs @@ -0,0 +1,162 @@ +//! Implements `buffer_interface::*` traits for enums dispatching to backends + +use crate::{backend_interface::*, Rect, SoftBufferError}; + +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use std::num::NonZeroU32; +#[cfg(any(wayland_platform, x11_platform, kms_platform))] +use std::rc::Rc; + +/// A macro for creating the enum used to statically dispatch to the platform-specific implementation. +macro_rules! make_dispatch { + ( + <$dgen: ident, $wgen: ident> => + $( + $(#[$attr:meta])* + $name: ident + ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty), + )* + ) => { + pub(crate) enum ContextDispatch<$dgen> { + $( + $(#[$attr])* + $name($context_inner), + )* + } + + impl ContextDispatch { + pub fn variant_name(&self) -> &'static str { + match self { + $( + $(#[$attr])* + Self::$name(_) => stringify!($name), + )* + } + } + } + + #[allow(clippy::large_enum_variant)] // it's boxed anyways + pub(crate) enum SurfaceDispatch<$dgen, $wgen> { + $( + $(#[$attr])* + $name($surface_inner), + )* + } + + impl SurfaceInterface for SurfaceDispatch { + type Buffer<'a> = BufferDispatch<'a, D, W> where Self: 'a; + + fn window(&self) -> &W { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.window(), + )* + } + } + + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.resize(width, height), + )* + } + } + + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + match self { + $( + $(#[$attr])* + Self::$name(inner) => Ok(BufferDispatch::$name(inner.buffer_mut()?)), + )* + } + } + + fn fetch(&mut self) -> Result, SoftBufferError> { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.fetch(), + )* + } + } + } + + pub(crate) enum BufferDispatch<'a, $dgen, $wgen> { + $( + $(#[$attr])* + $name($buffer_inner), + )* + } + + impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> { + #[inline] + fn pixels(&self) -> &[u32] { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.pixels(), + )* + } + } + + #[inline] + fn pixels_mut(&mut self) -> &mut [u32] { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.pixels_mut(), + )* + } + } + + fn age(&self) -> u8 { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.age(), + )* + } + } + + fn present(self) -> Result<(), SoftBufferError> { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.present(), + )* + } + } + + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { + match self { + $( + $(#[$attr])* + Self::$name(inner) => inner.present_with_damage(damage), + )* + } + } + } + }; +} + +// XXX empty enum with generic bound is invalid? + +make_dispatch! { + => + #[cfg(x11_platform)] + X11(Rc>, crate::x11::X11Impl, crate::x11::BufferImpl<'a, D, W>), + #[cfg(wayland_platform)] + Wayland(Rc>, crate::wayland::WaylandImpl, crate::wayland::BufferImpl<'a, D, W>), + #[cfg(kms_platform)] + Kms(Rc>, crate::kms::KmsImpl, crate::kms::BufferImpl<'a, D, W>), + #[cfg(target_os = "windows")] + Win32(D, crate::win32::Win32Impl, crate::win32::BufferImpl<'a, D, W>), + #[cfg(target_os = "macos")] + CG(D, crate::cg::CGImpl, crate::cg::BufferImpl<'a, D, W>), + #[cfg(target_arch = "wasm32")] + Web(crate::web::WebDisplayImpl, crate::web::WebImpl, crate::web::BufferImpl<'a, D, W>), + #[cfg(target_os = "redox")] + Orbital(D, crate::orbital::OrbitalImpl, crate::orbital::BufferImpl<'a, D, W>), +} diff --git a/src/backend_interface.rs b/src/backend_interface.rs new file mode 100644 index 00000000..8f16de2f --- /dev/null +++ b/src/backend_interface.rs @@ -0,0 +1,31 @@ +//! Interface implemented by backends + +use crate::{Rect, SoftBufferError}; + +use raw_window_handle::HasWindowHandle; +use std::num::NonZeroU32; + +pub(crate) trait SurfaceInterface { + type Buffer<'a>: BufferInterface + where + Self: 'a; + + /// Get the inner window handle. + fn window(&self) -> &W; + /// Resize the internal buffer to the given width and height. + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError>; + /// Get a mutable reference to the buffer. + fn buffer_mut(&mut self) -> Result, SoftBufferError>; + /// Fetch the buffer from the window. + fn fetch(&mut self) -> Result, SoftBufferError> { + Err(SoftBufferError::Unimplemented) + } +} + +pub(crate) trait BufferInterface { + fn pixels(&self) -> &[u32]; + fn pixels_mut(&mut self) -> &mut [u32]; + fn age(&self) -> u8; + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError>; + fn present(self) -> Result<(), SoftBufferError>; +} diff --git a/src/cg.rs b/src/cg.rs index ef96fb9a..9ad62e64 100644 --- a/src/cg.rs +++ b/src/cg.rs @@ -1,3 +1,4 @@ +use crate::backend_interface::*; use crate::error::InitError; use crate::{Rect, SoftBufferError}; use core_graphics::base::{ @@ -65,19 +66,22 @@ impl CGImpl { window_handle: window_src, }) } +} + +impl SurfaceInterface for CGImpl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; - /// Get the inner window handle. #[inline] - pub fn window(&self) -> &W { + fn window(&self) -> &W { &self.window_handle } - pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { self.size = Some((width, height)); Ok(()) } - pub 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()`"); @@ -87,11 +91,6 @@ impl CGImpl { imp: self, }) } - - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { - Err(SoftBufferError::Unimplemented) - } } pub struct BufferImpl<'a, D, W> { @@ -99,22 +98,22 @@ pub struct BufferImpl<'a, D, W> { buffer: Vec, } -impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { &self.buffer } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { &mut self.buffer } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { 0 } - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let data_provider = CGDataProvider::from_buffer(Arc::new(Buffer(self.buffer))); let (width, height) = self.imp.size.unwrap(); let image = CGImage::new( @@ -148,7 +147,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { Ok(()) } - pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> { self.present() } } diff --git a/src/kms.rs b/src/kms.rs index 2761843d..a5239769 100644 --- a/src/kms.rs +++ b/src/kms.rs @@ -17,6 +17,7 @@ use std::num::NonZeroU32; use std::os::unix::io::{AsFd, BorrowedFd}; use std::rc::Rc; +use crate::backend_interface::*; use crate::error::{InitError, SoftBufferError, SwResultExt}; #[derive(Debug)] @@ -203,19 +204,17 @@ impl KmsImpl { window_handle: window, }) } +} + +impl SurfaceInterface for KmsImpl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; - /// Get the inner window handle. #[inline] - pub fn window(&self) -> &W { + fn window(&self) -> &W { &self.window_handle } - /// Resize the internal buffer to the given size. - pub(crate) fn resize( - &mut self, - width: NonZeroU32, - height: NonZeroU32, - ) -> Result<(), SoftBufferError> { + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { // Don't resize if we don't have to. if let Some(buffer) = &self.buffer { let (buffer_width, buffer_height) = buffer.size(); @@ -237,14 +236,13 @@ impl KmsImpl { Ok(()) } - /// Fetch the buffer from the window. - pub(crate) fn fetch(&mut self) -> Result, SoftBufferError> { + /* + fn fetch(&mut self) -> Result, SoftBufferError> { // TODO: Implement this! - Err(SoftBufferError::Unimplemented) } + */ - /// Get a mutable reference to the buffer. - pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { // Map the dumb buffer. let set = self .buffer @@ -299,26 +297,26 @@ impl Drop for KmsImpl { } } -impl BufferImpl<'_, D, W> { +impl BufferInterface for BufferImpl<'_, D, W> { #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { // drm-rs doesn't let us have the immutable reference... so just use a bunch of zeroes. // TODO: There has to be a better way of doing this! self.zeroes } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { bytemuck::cast_slice_mut(self.mapping.as_mut()) } #[inline] - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { *self.front_age } #[inline] - pub fn present_with_damage(self, damage: &[crate::Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, damage: &[crate::Rect]) -> Result<(), SoftBufferError> { let rectangles = damage .iter() .map(|&rect| { @@ -374,7 +372,7 @@ impl BufferImpl<'_, D, W> { } #[inline] - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let (width, height) = self.size; self.present_with_damage(&[crate::Rect { x: 0, diff --git a/src/lib.rs b/src/lib.rs index 14191ca5..f23b5cec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,10 @@ mod win32; #[cfg(x11_platform)] mod x11; +mod backend_dispatch; +use backend_dispatch::*; +mod backend_interface; +use backend_interface::*; mod error; mod util; @@ -49,158 +53,6 @@ pub struct Context { context_impl: ContextDispatch, } -/// A macro for creating the enum used to statically dispatch to the platform-specific implementation. -macro_rules! make_dispatch { - ( - <$dgen: ident, $wgen: ident> => - $( - $(#[$attr:meta])* - $name: ident - ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty), - )* - ) => { - enum ContextDispatch<$dgen> { - $( - $(#[$attr])* - $name($context_inner), - )* - } - - impl ContextDispatch { - fn variant_name(&self) -> &'static str { - match self { - $( - $(#[$attr])* - Self::$name(_) => stringify!($name), - )* - } - } - } - - #[allow(clippy::large_enum_variant)] // it's boxed anyways - enum SurfaceDispatch<$dgen, $wgen> { - $( - $(#[$attr])* - $name($surface_inner), - )* - } - - impl SurfaceDispatch { - fn window(&self) -> &W { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.window(), - )* - } - } - - pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.resize(width, height), - )* - } - } - - pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { - match self { - $( - $(#[$attr])* - Self::$name(inner) => Ok(BufferDispatch::$name(inner.buffer_mut()?)), - )* - } - } - - pub fn fetch(&mut self) -> Result, SoftBufferError> { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.fetch(), - )* - } - } - } - - enum BufferDispatch<'a, $dgen, $wgen> { - $( - $(#[$attr])* - $name($buffer_inner), - )* - } - - impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferDispatch<'a, D, W> { - #[inline] - pub fn pixels(&self) -> &[u32] { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.pixels(), - )* - } - } - - #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.pixels_mut(), - )* - } - } - - pub fn age(&self) -> u8 { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.age(), - )* - } - } - - pub fn present(self) -> Result<(), SoftBufferError> { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.present(), - )* - } - } - - pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { - match self { - $( - $(#[$attr])* - Self::$name(inner) => inner.present_with_damage(damage), - )* - } - } - } - }; -} - -// XXX empty enum with generic bound is invalid? - -make_dispatch! { - => - #[cfg(x11_platform)] - X11(Rc>, x11::X11Impl, x11::BufferImpl<'a, D, W>), - #[cfg(wayland_platform)] - Wayland(Rc>, wayland::WaylandImpl, wayland::BufferImpl<'a, D, W>), - #[cfg(kms_platform)] - Kms(Rc>, kms::KmsImpl, kms::BufferImpl<'a, D, W>), - #[cfg(target_os = "windows")] - Win32(D, win32::Win32Impl, win32::BufferImpl<'a, D, W>), - #[cfg(target_os = "macos")] - CG(D, cg::CGImpl, cg::BufferImpl<'a, D, W>), - #[cfg(target_arch = "wasm32")] - Web(web::WebDisplayImpl, web::WebImpl, web::BufferImpl<'a, D, W>), - #[cfg(target_os = "redox")] - Orbital(D, orbital::OrbitalImpl, orbital::BufferImpl<'a, D, W>), -} - impl Context { /// Creates a new instance of this struct, using the provided display. pub fn new(mut dpy: D) -> Result { diff --git a/src/orbital.rs b/src/orbital.rs index 50c80d46..dae5d9e8 100644 --- a/src/orbital.rs +++ b/src/orbital.rs @@ -2,6 +2,7 @@ use crate::error::InitError; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle}; use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str}; +use crate::backend_interface::*; use crate::{Rect, SoftBufferError}; struct OrbitalMap { @@ -81,23 +82,6 @@ impl OrbitalImpl { }) } - /// Get the inner window handle. - #[inline] - pub fn window(&self) -> &W { - &self.window_handle - } - - pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { - let width = width.get(); - let height = height.get(); - if width != self.width || height != self.height { - self.presented = false; - self.width = width; - self.height = height; - } - Ok(()) - } - fn window_fd(&self) -> usize { self.handle.window.as_ptr() as usize } @@ -122,20 +106,6 @@ impl OrbitalImpl { (window_width, window_height) } - pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { - let (window_width, window_height) = self.window_size(); - let pixels = if self.width as usize == window_width && self.height as usize == window_height - { - Pixels::Mapping( - unsafe { OrbitalMap::new(self.window_fd(), window_width * window_height * 4) } - .expect("failed to map orbital window"), - ) - } else { - Pixels::Buffer(vec![0; self.width as usize * self.height as usize]) - }; - Ok(BufferImpl { imp: self, pixels }) - } - 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(); @@ -167,10 +137,39 @@ impl OrbitalImpl { // Tell orbital to show the latest window data syscall::fsync(self.window_fd()).expect("failed to sync orbital window"); } +} + +impl SurfaceInterface for OrbitalImpl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { - Err(SoftBufferError::Unimplemented) + #[inline] + fn window(&self) -> &W { + &self.window_handle + } + + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + let width = width.get(); + let height = height.get(); + if width != self.width || height != self.height { + self.presented = false; + self.width = width; + self.height = height; + } + Ok(()) + } + + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + let (window_width, window_height) = self.window_size(); + let pixels = if self.width as usize == window_width && self.height as usize == window_height + { + Pixels::Mapping( + unsafe { OrbitalMap::new(self.window_fd(), window_width * window_height * 4) } + .expect("failed to map orbital window"), + ) + } else { + Pixels::Buffer(vec![0; self.width as usize * self.height as usize]) + }; + Ok(BufferImpl { imp: self, pixels }) } } @@ -184,9 +183,9 @@ pub struct BufferImpl<'a, D, W> { pixels: Pixels, } -impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { match &self.pixels { Pixels::Mapping(mapping) => unsafe { mapping.data() }, Pixels::Buffer(buffer) => buffer, @@ -194,21 +193,21 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { match &mut self.pixels { Pixels::Mapping(mapping) => unsafe { mapping.data_mut() }, Pixels::Buffer(buffer) => buffer, } } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { match self.pixels { Pixels::Mapping(_) if self.imp.presented => 1, _ => 0, } } - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { match self.pixels { Pixels::Mapping(mapping) => { drop(mapping); @@ -224,7 +223,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { Ok(()) } - pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> { self.present() } } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index d61a5f16..bf956877 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -1,4 +1,5 @@ use crate::{ + backend_interface::*, error::{InitError, SwResultExt}, util, Rect, SoftBufferError, }; @@ -113,13 +114,67 @@ impl WaylandImpl { }) } - /// Get the inner window handle. + 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 + .borrow_mut() + .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.borrow_mut().flush(); + + Ok(()) + } +} + +impl SurfaceInterface for WaylandImpl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + #[inline] - pub fn window(&self) -> &W { + fn window(&self) -> &W { &self.window_handle } - pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { self.size = Some( (|| { let width = NonZeroI32::try_from(width).ok()?; @@ -131,7 +186,7 @@ impl WaylandImpl { Ok(()) } - pub 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()`"); @@ -178,62 +233,6 @@ impl WaylandImpl { age, }) } - - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { - Err(SoftBufferError::Unimplemented) - } - - fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { - let _ = self - .display - .event_queue - .borrow_mut() - .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.borrow_mut().flush(); - - Ok(()) - } - - fn surface(&self) -> &wl_surface::WlSurface { - self.surface.as_ref().unwrap() - } } impl Drop for WaylandImpl { @@ -248,26 +247,28 @@ pub struct BufferImpl<'a, D: ?Sized, W> { age: u8, } -impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> { +impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferInterface + for BufferImpl<'a, D, W> +{ #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { self.stack.member() } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { self.stack.member_mut() } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { self.age } - pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { self.stack.into_container().present_with_damage(damage) } - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let imp = self.stack.into_container(); let (width, height) = imp .size diff --git a/src/web.rs b/src/web.rs index 595073d4..66fc18c0 100644 --- a/src/web.rs +++ b/src/web.rs @@ -9,6 +9,7 @@ use web_sys::ImageData; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d}; +use crate::backend_interface::*; use crate::error::{InitError, SwResultExt}; use crate::{util, NoDisplayHandle, NoWindowHandle, Rect, SoftBufferError}; use std::convert::TryInto; @@ -135,13 +136,6 @@ impl WebImpl { }) } - /// Get the inner window handle. - #[inline] - pub fn window(&self) -> &W { - &self.window_handle - } - - /// De-duplicates the error handling between `HtmlCanvasElement` and `OffscreenCanvas`. fn resolve_ctx( result: Option>, name: &str, @@ -157,28 +151,6 @@ impl WebImpl { Ok(ctx) } - /// Resize the canvas to the given dimensions. - pub(crate) fn resize( - &mut self, - width: NonZeroU32, - height: NonZeroU32, - ) -> Result<(), SoftBufferError> { - if self.size != Some((width, height)) { - self.buffer_presented = false; - self.buffer.resize(total_len(width.get(), height.get()), 0); - self.canvas.set_width(width.get()); - self.canvas.set_height(height.get()); - self.size = Some((width, height)); - } - - Ok(()) - } - - /// Get a pointer to the mutable buffer. - pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { - Ok(BufferImpl { imp: self }) - } - fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { let (buffer_width, _buffer_height) = self .size @@ -260,9 +232,36 @@ impl WebImpl { Ok(()) } +} + +impl SurfaceInterface for WebImpl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + + /// Get the inner window handle. + #[inline] + fn window(&self) -> &W { + &self.window_handle + } + + /// De-duplicates the error handling between `HtmlCanvasElement` and `OffscreenCanvas`. + /// Resize the canvas to the given dimensions. + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + if self.size != Some((width, height)) { + self.buffer_presented = false; + self.buffer.resize(total_len(width.get(), height.get()), 0); + self.canvas.set_width(width.get()); + self.canvas.set_height(height.get()); + self.size = Some((width, height)); + } + + Ok(()) + } + + fn buffer_mut(&mut self) -> Result, SoftBufferError> { + Ok(BufferImpl { imp: self }) + } - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { + fn fetch(&mut self) -> Result, SoftBufferError> { let (width, height) = self .size .expect("Must set size of surface before calling `fetch()`"); @@ -374,16 +373,16 @@ pub struct BufferImpl<'a, D, W> { imp: &'a mut WebImpl, } -impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { - pub fn pixels(&self) -> &[u32] { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { + fn pixels(&self) -> &[u32] { &self.imp.buffer } - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { &mut self.imp.buffer } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { if self.imp.buffer_presented { 1 } else { @@ -392,7 +391,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { } /// Push the buffer to the canvas. - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let (width, height) = self .imp .size @@ -405,7 +404,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { }]) } - pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { self.imp.present_with_damage(damage) } } diff --git a/src/win32.rs b/src/win32.rs index 7055b443..a4d98274 100644 --- a/src/win32.rs +++ b/src/win32.rs @@ -2,6 +2,7 @@ //! //! This module converts the input buffer into a bitmap and then stretches it to the window. +use crate::backend_interface::*; use crate::{Rect, SoftBufferError}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; @@ -189,13 +190,40 @@ impl Win32Impl { }) } - /// Get the inner window handle. + 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, x, y, width, height, buffer.dc, x, y, Gdi::SRCCOPY); + } + + // Validate the window. + Gdi::ValidateRect(self.window, ptr::null_mut()); + } + buffer.presented = true; + + Ok(()) + } +} + +impl SurfaceInterface for Win32Impl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + #[inline] - pub fn window(&self) -> &W { + fn window(&self) -> &W { &self.handle } - pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { let (width, height) = (|| { let width = NonZeroI32::new(i32::try_from(width.get()).ok()?)?; let height = NonZeroI32::new(i32::try_from(height.get()).ok()?)?; @@ -214,7 +242,7 @@ impl Win32Impl { Ok(()) } - pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { if self.buffer.is_none() { panic!("Must set size of surface before calling `buffer_mut()`"); } @@ -222,57 +250,33 @@ impl Win32Impl { Ok(BufferImpl(self)) } - 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, x, y, width, height, buffer.dc, x, y, Gdi::SRCCOPY); - } - - // Validate the window. - Gdi::ValidateRect(self.window, ptr::null_mut()); - } - buffer.presented = true; - - Ok(()) - } - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { + fn fetch(&mut self) -> Result, SoftBufferError> { Err(SoftBufferError::Unimplemented) } } pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl); -impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> { #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { self.0.buffer.as_ref().unwrap().pixels() } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + fn pixels_mut(&mut self) -> &mut [u32] { self.0.buffer.as_mut().unwrap().pixels_mut() } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { match self.0.buffer.as_ref() { Some(buffer) if buffer.presented => 1, _ => 0, } } - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let imp = self.0; let buffer = imp.buffer.as_ref().unwrap(); imp.present_with_damage(&[Rect { @@ -284,7 +288,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { }]) } - pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { let imp = self.0; imp.present_with_damage(damage) } diff --git a/src/x11.rs b/src/x11.rs index 31b2325a..ed214863 100644 --- a/src/x11.rs +++ b/src/x11.rs @@ -5,6 +5,7 @@ #![allow(clippy::uninlined_format_args)] +use crate::backend_interface::*; use crate::error::{InitError, SwResultExt}; use crate::{Rect, SoftBufferError}; use raw_window_handle::{ @@ -295,19 +296,17 @@ impl X11Impl { window_handle: window_src, }) } +} + +impl SurfaceInterface for X11Impl { + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; - /// Get the inner window handle. #[inline] - pub fn window(&self) -> &W { + fn window(&self) -> &W { &self.window_handle } - /// Resize the internal buffer to the given width and height. - pub(crate) fn resize( - &mut self, - width: NonZeroU32, - height: NonZeroU32, - ) -> Result<(), SoftBufferError> { + fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { log::trace!( "resize: window={:X}, size={}x{}", self.window, @@ -337,8 +336,7 @@ impl X11Impl { Ok(()) } - /// Get a mutable reference to the buffer. - pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { + fn buffer_mut(&mut self) -> Result, SoftBufferError> { log::trace!("buffer_mut: window={:X}", self.window); // Finish waiting on the previous `shm::PutImage` request, if any. @@ -348,8 +346,7 @@ impl X11Impl { Ok(BufferImpl(self)) } - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { + fn fetch(&mut self) -> Result, SoftBufferError> { log::trace!("fetch: window={:X}", self.window); let (width, height) = self @@ -388,20 +385,22 @@ impl X11Impl { pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl); -impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<'a, D, W> { +impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferInterface + for BufferImpl<'a, D, W> +{ #[inline] - pub fn pixels(&self) -> &[u32] { + fn pixels(&self) -> &[u32] { // SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`. unsafe { self.0.buffer.buffer() } } #[inline] - pub fn pixels_mut(&mut self) -> &mut [u32] { + 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() } } - pub fn age(&self) -> u8 { + fn age(&self) -> u8 { if self.0.buffer_presented { 1 } else { @@ -410,7 +409,7 @@ impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<' } /// Push the buffer to the window. - pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { + fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { let imp = self.0; let (surface_width, surface_height) = imp @@ -500,7 +499,7 @@ impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<' Ok(()) } - pub fn present(self) -> Result<(), SoftBufferError> { + fn present(self) -> Result<(), SoftBufferError> { let (width, height) = self .0 .size From 8286a5bda5853ab6fbe1f89b58b695b833adc759 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 13 Feb 2024 10:29:10 -0800 Subject: [PATCH 2/5] ci: Downgrade dep for 1.65.0 build --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26811d6b..af55c9cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,7 +93,7 @@ jobs: - name: Pin versions of dev-deps if: matrix.rust_version == '1.65.0' - run: cargo update -p half --precise 2.2.1 + run: cargo update -p exr --precise 1.71.0 && cargo update -p ahash --precise 0.8.7 - name: Build tests shell: bash From 878d51c81e57c6f80f68649fb730977d67512808 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 13 Feb 2024 10:29:10 -0800 Subject: [PATCH 3/5] Add `#[allow(dead_code)]` to `SwResultExt` Fixes build warnings on some platforms. --- src/error.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/error.rs b/src/error.rs index c2994a7c..eaec8563 100644 --- a/src/error.rs +++ b/src/error.rs @@ -181,6 +181,7 @@ impl From for InitError { } /// Convenient wrapper to cast errors into SoftBufferError. +#[allow(dead_code)] pub(crate) trait SwResultExt { fn swbuf_err(self, msg: impl Into) -> Result; } From c0ff669c6d824edfc6cc973a5b7cc500f8478afd Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 13 Feb 2024 10:29:10 -0800 Subject: [PATCH 4/5] Move backends into a `backends` module --- src/backend_dispatch.rs | 16 +++++----- src/{ => backends}/cg.rs | 0 src/{ => backends}/kms.rs | 0 src/backends/mod.rs | 14 ++++++++ src/{ => backends}/orbital.rs | 0 src/{ => backends}/wayland/buffer.rs | 0 src/{ => backends}/wayland/mod.rs | 0 src/{ => backends}/web.rs | 2 +- src/{ => backends}/win32.rs | 0 src/{ => backends}/x11.rs | 0 src/lib.rs | 48 ++++++++++------------------ 11 files changed, 40 insertions(+), 40 deletions(-) rename src/{ => backends}/cg.rs (100%) rename src/{ => backends}/kms.rs (100%) create mode 100644 src/backends/mod.rs rename src/{ => backends}/orbital.rs (100%) rename src/{ => backends}/wayland/buffer.rs (100%) rename src/{ => backends}/wayland/mod.rs (100%) rename src/{ => backends}/web.rs (99%) rename src/{ => backends}/win32.rs (100%) rename src/{ => backends}/x11.rs (100%) diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index 825d08ef..01c25c1b 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -1,6 +1,6 @@ //! Implements `buffer_interface::*` traits for enums dispatching to backends -use crate::{backend_interface::*, Rect, SoftBufferError}; +use crate::{backend_interface::*, backends, Rect, SoftBufferError}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::num::NonZeroU32; @@ -146,17 +146,17 @@ macro_rules! make_dispatch { make_dispatch! { => #[cfg(x11_platform)] - X11(Rc>, crate::x11::X11Impl, crate::x11::BufferImpl<'a, D, W>), + X11(Rc>, backends::x11::X11Impl, backends::x11::BufferImpl<'a, D, W>), #[cfg(wayland_platform)] - Wayland(Rc>, crate::wayland::WaylandImpl, crate::wayland::BufferImpl<'a, D, W>), + Wayland(Rc>, backends::wayland::WaylandImpl, backends::wayland::BufferImpl<'a, D, W>), #[cfg(kms_platform)] - Kms(Rc>, crate::kms::KmsImpl, crate::kms::BufferImpl<'a, D, W>), + Kms(Rc>, backends::kms::KmsImpl, backends::kms::BufferImpl<'a, D, W>), #[cfg(target_os = "windows")] - Win32(D, crate::win32::Win32Impl, crate::win32::BufferImpl<'a, D, W>), + Win32(D, backends::win32::Win32Impl, backends::win32::BufferImpl<'a, D, W>), #[cfg(target_os = "macos")] - CG(D, crate::cg::CGImpl, crate::cg::BufferImpl<'a, D, W>), + CG(D, backends::cg::CGImpl, backends::cg::BufferImpl<'a, D, W>), #[cfg(target_arch = "wasm32")] - Web(crate::web::WebDisplayImpl, crate::web::WebImpl, crate::web::BufferImpl<'a, D, W>), + Web(backends::web::WebDisplayImpl, backends::web::WebImpl, backends::web::BufferImpl<'a, D, W>), #[cfg(target_os = "redox")] - Orbital(D, crate::orbital::OrbitalImpl, crate::orbital::BufferImpl<'a, D, W>), + Orbital(D, backends::orbital::OrbitalImpl, backends::orbital::BufferImpl<'a, D, W>), } diff --git a/src/cg.rs b/src/backends/cg.rs similarity index 100% rename from src/cg.rs rename to src/backends/cg.rs diff --git a/src/kms.rs b/src/backends/kms.rs similarity index 100% rename from src/kms.rs rename to src/backends/kms.rs diff --git a/src/backends/mod.rs b/src/backends/mod.rs new file mode 100644 index 00000000..35bc66ef --- /dev/null +++ b/src/backends/mod.rs @@ -0,0 +1,14 @@ +#[cfg(target_os = "macos")] +pub(crate) mod cg; +#[cfg(kms_platform)] +pub(crate) mod kms; +#[cfg(target_os = "redox")] +pub(crate) mod orbital; +#[cfg(wayland_platform)] +pub(crate) mod wayland; +#[cfg(target_arch = "wasm32")] +pub(crate) mod web; +#[cfg(target_os = "windows")] +pub(crate) mod win32; +#[cfg(x11_platform)] +pub(crate) mod x11; diff --git a/src/orbital.rs b/src/backends/orbital.rs similarity index 100% rename from src/orbital.rs rename to src/backends/orbital.rs diff --git a/src/wayland/buffer.rs b/src/backends/wayland/buffer.rs similarity index 100% rename from src/wayland/buffer.rs rename to src/backends/wayland/buffer.rs diff --git a/src/wayland/mod.rs b/src/backends/wayland/mod.rs similarity index 100% rename from src/wayland/mod.rs rename to src/backends/wayland/mod.rs diff --git a/src/web.rs b/src/backends/web.rs similarity index 99% rename from src/web.rs rename to src/backends/web.rs index 66fc18c0..5b631a80 100644 --- a/src/web.rs +++ b/src/backends/web.rs @@ -25,7 +25,7 @@ pub struct WebDisplayImpl { } impl WebDisplayImpl { - pub(super) fn new(display: D) -> Result> { + pub(crate) fn new(display: D) -> Result> { let raw = display.display_handle()?.as_raw(); match raw { RawDisplayHandle::Web(..) => {} diff --git a/src/win32.rs b/src/backends/win32.rs similarity index 100% rename from src/win32.rs rename to src/backends/win32.rs diff --git a/src/x11.rs b/src/backends/x11.rs similarity index 100% rename from src/x11.rs rename to src/backends/x11.rs diff --git a/src/lib.rs b/src/lib.rs index f23b5cec..ec298538 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,25 +8,11 @@ extern crate objc; extern crate core; -#[cfg(target_os = "macos")] -mod cg; -#[cfg(kms_platform)] -mod kms; -#[cfg(target_os = "redox")] -mod orbital; -#[cfg(wayland_platform)] -mod wayland; -#[cfg(target_arch = "wasm32")] -mod web; -#[cfg(target_os = "windows")] -mod win32; -#[cfg(x11_platform)] -mod x11; - mod backend_dispatch; use backend_dispatch::*; mod backend_interface; use backend_interface::*; +mod backends; mod error; mod util; @@ -42,7 +28,7 @@ pub use error::SoftBufferError; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; #[cfg(target_arch = "wasm32")] -pub use self::web::SurfaceExtWeb; +pub use backends::web::SurfaceExtWeb; /// An instance of this struct contains the platform-specific data that must be managed in order to /// write to a window on that platform. @@ -73,17 +59,17 @@ impl Context { } #[cfg(x11_platform)] - try_init!(X11, display => x11::X11DisplayImpl::new(display).map(Rc::new)); + try_init!(X11, display => backends::x11::X11DisplayImpl::new(display).map(Rc::new)); #[cfg(wayland_platform)] - try_init!(Wayland, display => wayland::WaylandDisplayImpl::new(display).map(Rc::new)); + try_init!(Wayland, display => backends::wayland::WaylandDisplayImpl::new(display).map(Rc::new)); #[cfg(kms_platform)] - try_init!(Kms, display => kms::KmsDisplayImpl::new(display).map(Rc::new)); + try_init!(Kms, display => backends::kms::KmsDisplayImpl::new(display).map(Rc::new)); #[cfg(target_os = "windows")] try_init!(Win32, display => Ok(display)); #[cfg(target_os = "macos")] try_init!(CG, display => Ok(display)); #[cfg(target_arch = "wasm32")] - try_init!(Web, display => web::WebDisplayImpl::new(display)); + try_init!(Web, display => backends::web::WebDisplayImpl::new(display)); #[cfg(target_os = "redox")] try_init!(Orbital, display => Ok(display)); @@ -139,30 +125,30 @@ impl Surface { let imple = match &context.context_impl { #[cfg(x11_platform)] - ContextDispatch::X11(xcb_display_handle) => { - SurfaceDispatch::X11(leap!(x11::X11Impl::new(window, xcb_display_handle.clone()))) - } + ContextDispatch::X11(xcb_display_handle) => SurfaceDispatch::X11(leap!( + backends::x11::X11Impl::new(window, xcb_display_handle.clone()) + )), #[cfg(wayland_platform)] ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!( - wayland::WaylandImpl::new(window, wayland_display_impl.clone()) + backends::wayland::WaylandImpl::new(window, wayland_display_impl.clone()) )), #[cfg(kms_platform)] - ContextDispatch::Kms(kms_display_impl) => { - SurfaceDispatch::Kms(leap!(kms::KmsImpl::new(window, kms_display_impl.clone()))) - } + ContextDispatch::Kms(kms_display_impl) => SurfaceDispatch::Kms(leap!( + backends::kms::KmsImpl::new(window, kms_display_impl.clone()) + )), #[cfg(target_os = "windows")] ContextDispatch::Win32(_) => { - SurfaceDispatch::Win32(leap!(win32::Win32Impl::new(window))) + SurfaceDispatch::Win32(leap!(backends::win32::Win32Impl::new(window))) } #[cfg(target_os = "macos")] - ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(cg::CGImpl::new(window))), + ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(backends::cg::CGImpl::new(window))), #[cfg(target_arch = "wasm32")] ContextDispatch::Web(web_display_impl) => { - SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window))) + SurfaceDispatch::Web(leap!(backends::web::WebImpl::new(web_display_impl, window))) } #[cfg(target_os = "redox")] ContextDispatch::Orbital(_) => { - SurfaceDispatch::Orbital(leap!(orbital::OrbitalImpl::new(window))) + SurfaceDispatch::Orbital(leap!(backends::orbital::OrbitalImpl::new(window))) } }; From d7b32faf8dedd17ba28925ca130e5861595d27d8 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 13 Feb 2024 10:29:10 -0800 Subject: [PATCH 5/5] Move `new()` methods into traits Now `lib.rs` doesn't need conditional code and macros for dispatching `new`. It can be handled by `make_dispatch!`. --- src/backend_dispatch.rs | 37 +++++++++++- src/backend_interface.rs | 18 +++++- src/backends/cg.rs | 11 ++-- src/backends/kms.rs | 24 ++++---- src/backends/mod.rs | 9 +++ src/backends/orbital.rs | 37 ++++++------ src/backends/wayland/mod.rs | 73 +++++++++++----------- src/backends/web.rs | 65 ++++++++++---------- src/backends/win32.rs | 59 +++++++++--------- src/backends/x11.rs | 21 +++---- src/lib.rs | 117 +++++++++--------------------------- 11 files changed, 236 insertions(+), 235 deletions(-) diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs index 01c25c1b..e23a0c27 100644 --- a/src/backend_dispatch.rs +++ b/src/backend_dispatch.rs @@ -1,6 +1,6 @@ //! Implements `buffer_interface::*` traits for enums dispatching to backends -use crate::{backend_interface::*, backends, Rect, SoftBufferError}; +use crate::{backend_interface::*, backends, InitError, Rect, SoftBufferError}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::num::NonZeroU32; @@ -35,6 +35,26 @@ macro_rules! make_dispatch { } } + impl ContextInterface for ContextDispatch { + fn new(mut display: D) -> Result> + where + D: Sized, + { + $( + $(#[$attr])* + match <$context_inner as ContextInterface>::new(display) { + Ok(x) => { + return Ok(Self::$name(x)); + } + Err(InitError::Unsupported(d)) => display = d, + Err(InitError::Failure(f)) => return Err(InitError::Failure(f)), + } + )* + + Err(InitError::Unsupported(display)) + } + } + #[allow(clippy::large_enum_variant)] // it's boxed anyways pub(crate) enum SurfaceDispatch<$dgen, $wgen> { $( @@ -43,9 +63,22 @@ macro_rules! make_dispatch { )* } - impl SurfaceInterface for SurfaceDispatch { + impl SurfaceInterface for SurfaceDispatch { + type Context = ContextDispatch; type Buffer<'a> = BufferDispatch<'a, D, W> where Self: 'a; + fn new(window: W, display: &Self::Context) -> Result> + where + W: Sized, + Self: Sized { + match display { + $( + $(#[$attr])* + ContextDispatch::$name(inner) => Ok(Self::$name(<$surface_inner>::new(window, inner)?)), + )* + } + } + fn window(&self) -> &W { match self { $( diff --git a/src/backend_interface.rs b/src/backend_interface.rs index 8f16de2f..13e3555c 100644 --- a/src/backend_interface.rs +++ b/src/backend_interface.rs @@ -1,15 +1,27 @@ //! Interface implemented by backends -use crate::{Rect, SoftBufferError}; +use crate::{InitError, Rect, SoftBufferError}; -use raw_window_handle::HasWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::num::NonZeroU32; -pub(crate) trait SurfaceInterface { +pub(crate) trait ContextInterface { + fn new(display: D) -> Result> + where + D: Sized, + Self: Sized; +} + +pub(crate) trait SurfaceInterface { + type Context: ContextInterface; type Buffer<'a>: BufferInterface where Self: 'a; + fn new(window: W, context: &Self::Context) -> Result> + where + W: Sized, + Self: Sized; /// Get the inner window handle. fn window(&self) -> &W; /// Resize the internal buffer to the given width and height. diff --git a/src/backends/cg.rs b/src/backends/cg.rs index 9ad62e64..3757880f 100644 --- a/src/backends/cg.rs +++ b/src/backends/cg.rs @@ -35,8 +35,11 @@ pub struct CGImpl { _display: PhantomData, } -impl CGImpl { - pub(crate) fn new(window_src: W) -> Result> { +impl SurfaceInterface for CGImpl { + type Context = D; + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + + fn new(window_src: W, _display: &D) -> Result> { let raw = window_src.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::AppKit(handle) => handle, @@ -66,10 +69,6 @@ impl CGImpl { window_handle: window_src, }) } -} - -impl SurfaceInterface for CGImpl { - type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; #[inline] fn window(&self) -> &W { diff --git a/src/backends/kms.rs b/src/backends/kms.rs index a5239769..13c040b5 100644 --- a/src/backends/kms.rs +++ b/src/backends/kms.rs @@ -38,8 +38,11 @@ impl AsFd for KmsDisplayImpl { impl Device for KmsDisplayImpl {} impl CtrlDevice for KmsDisplayImpl {} -impl KmsDisplayImpl { - pub(crate) fn new(display: D) -> Result> { +impl ContextInterface for Rc> { + fn new(display: D) -> Result> + where + D: Sized, + { let fd = match display.display_handle()?.as_raw() { RawDisplayHandle::Drm(drm) => drm.fd, _ => return Err(InitError::Unsupported(display)), @@ -51,10 +54,10 @@ impl KmsDisplayImpl { // SAFETY: Invariants guaranteed by the user. let fd = unsafe { BorrowedFd::borrow_raw(fd) }; - Ok(KmsDisplayImpl { + Ok(Rc::new(KmsDisplayImpl { fd, _display: display, - }) + })) } } @@ -135,9 +138,12 @@ struct SharedBuffer { age: u8, } -impl KmsImpl { +impl SurfaceInterface for KmsImpl { + type Context = Rc>; + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + /// Create a new KMS backend. - pub(crate) fn new(window: W, display: Rc>) -> Result> { + fn new(window: W, display: &Rc>) -> Result> { // Make sure that the window handle is valid. let plane_handle = match window.window_handle()?.as_raw() { RawWindowHandle::Drm(drm) => match NonZeroU32::new(drm.plane) { @@ -199,15 +205,11 @@ impl KmsImpl { Ok(Self { crtc, connectors, - display, + display: display.clone(), buffer: None, window_handle: window, }) } -} - -impl SurfaceInterface for KmsImpl { - type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; #[inline] fn window(&self) -> &W { diff --git a/src/backends/mod.rs b/src/backends/mod.rs index 35bc66ef..8402b441 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -1,3 +1,6 @@ +use crate::{ContextInterface, InitError}; +use raw_window_handle::HasDisplayHandle; + #[cfg(target_os = "macos")] pub(crate) mod cg; #[cfg(kms_platform)] @@ -12,3 +15,9 @@ pub(crate) mod web; pub(crate) mod win32; #[cfg(x11_platform)] pub(crate) mod x11; + +impl ContextInterface for D { + fn new(display: D) -> Result> { + Ok(display) + } +} diff --git a/src/backends/orbital.rs b/src/backends/orbital.rs index dae5d9e8..7fb5c164 100644 --- a/src/backends/orbital.rs +++ b/src/backends/orbital.rs @@ -65,23 +65,6 @@ pub struct OrbitalImpl { } impl OrbitalImpl { - pub(crate) fn new(window: W) -> Result> { - let raw = window.window_handle()?.as_raw(); - let handle = match raw { - RawWindowHandle::Orbital(handle) => handle, - _ => return Err(InitError::Unsupported(window)), - }; - - Ok(Self { - handle, - width: 0, - height: 0, - presented: false, - window_handle: window, - _display: PhantomData, - }) - } - fn window_fd(&self) -> usize { self.handle.window.as_ptr() as usize } @@ -139,9 +122,27 @@ impl OrbitalImpl { } } -impl SurfaceInterface for OrbitalImpl { +impl SurfaceInterface for OrbitalImpl { + type Context = D; type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + fn new(window: W, _display: &D) -> Result> { + let raw = window.window_handle()?.as_raw(); + let handle = match raw { + RawWindowHandle::Orbital(handle) => handle, + _ => return Err(InitError::Unsupported(window)), + }; + + Ok(Self { + handle, + width: 0, + height: 0, + presented: false, + window_handle: window, + _display: PhantomData, + }) + } + #[inline] fn window(&self) -> &W { &self.window_handle diff --git a/src/backends/wayland/mod.rs b/src/backends/wayland/mod.rs index bf956877..32be3d46 100644 --- a/src/backends/wayland/mod.rs +++ b/src/backends/wayland/mod.rs @@ -35,7 +35,13 @@ pub struct WaylandDisplayImpl { } impl WaylandDisplayImpl { - pub(crate) fn new(display: D) -> Result> + fn conn(&self) -> &Connection { + self.conn.as_ref().unwrap() + } +} + +impl ContextInterface for Rc> { + fn new(display: D) -> Result> where D: Sized, { @@ -53,17 +59,13 @@ impl WaylandDisplayImpl { let shm: wl_shm::WlShm = globals .bind(&qh, 1..=1, ()) .swbuf_err("Failed to instantiate Wayland Shm")?; - Ok(Self { + Ok(Rc::new(WaylandDisplayImpl { conn: Some(conn), event_queue: RefCell::new(event_queue), qh, shm, _display: display, - }) - } - - fn conn(&self) -> &Connection { - self.conn.as_ref().unwrap() + })) } } @@ -88,32 +90,6 @@ pub struct WaylandImpl { } impl WaylandImpl { - pub(crate) fn new(window: W, display: Rc>) -> Result> { - // Get the raw Wayland window. - let raw = window.window_handle()?.as_raw(); - let wayland_handle = match raw { - RawWindowHandle::Wayland(w) => w.surface, - _ => return Err(InitError::Unsupported(window)), - }; - - let surface_id = unsafe { - ObjectId::from_ptr( - wl_surface::WlSurface::interface(), - wayland_handle.as_ptr().cast(), - ) - } - .swbuf_err("Failed to create proxy for surface ID.")?; - let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id) - .swbuf_err("Failed to create proxy for surface ID.")?; - Ok(Self { - display, - surface: Some(surface), - buffers: Default::default(), - size: None, - window_handle: window, - }) - } - fn surface(&self) -> &wl_surface::WlSurface { self.surface.as_ref().unwrap() } @@ -166,9 +142,38 @@ impl WaylandImpl { } } -impl SurfaceInterface for WaylandImpl { +impl SurfaceInterface + for WaylandImpl +{ + type Context = Rc>; type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + fn new(window: W, display: &Rc>) -> Result> { + // Get the raw Wayland window. + let raw = window.window_handle()?.as_raw(); + let wayland_handle = match raw { + RawWindowHandle::Wayland(w) => w.surface, + _ => return Err(InitError::Unsupported(window)), + }; + + let surface_id = unsafe { + ObjectId::from_ptr( + wl_surface::WlSurface::interface(), + wayland_handle.as_ptr().cast(), + ) + } + .swbuf_err("Failed to create proxy for surface ID.")?; + let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id) + .swbuf_err("Failed to create proxy for surface ID.")?; + Ok(Self { + display: display.clone(), + surface: Some(surface), + buffers: Default::default(), + size: None, + window_handle: window, + }) + } + #[inline] fn window(&self) -> &W { &self.window_handle diff --git a/src/backends/web.rs b/src/backends/web.rs index 5b631a80..2b8e9b5b 100644 --- a/src/backends/web.rs +++ b/src/backends/web.rs @@ -24,8 +24,8 @@ pub struct WebDisplayImpl { _display: D, } -impl WebDisplayImpl { - pub(crate) fn new(display: D) -> Result> { +impl ContextInterface for WebDisplayImpl { + fn new(display: D) -> Result> { let raw = display.display_handle()?.as_raw(); match raw { RawDisplayHandle::Web(..) => {} @@ -78,35 +78,6 @@ enum Canvas { } impl WebImpl { - pub(crate) fn new(display: &WebDisplayImpl, window: W) -> Result> { - let raw = window.window_handle()?.as_raw(); - let canvas: HtmlCanvasElement = match raw { - RawWindowHandle::Web(handle) => { - display - .document - .query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id)) - // `querySelector` only throws an error if the selector is invalid. - .unwrap() - .swbuf_err("No canvas found with the given id")? - // We already made sure this was a canvas in `querySelector`. - .unchecked_into() - } - RawWindowHandle::WebCanvas(handle) => { - let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; - value.clone().unchecked_into() - } - RawWindowHandle::WebOffscreenCanvas(handle) => { - let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; - let canvas: OffscreenCanvas = value.clone().unchecked_into(); - - return Self::from_offscreen_canvas(canvas, window).map_err(InitError::Failure); - } - _ => return Err(InitError::Unsupported(window)), - }; - - Self::from_canvas(canvas, window).map_err(InitError::Failure) - } - fn from_canvas(canvas: HtmlCanvasElement, window: W) -> Result { let ctx = Self::resolve_ctx(canvas.get_context("2d").ok(), "CanvasRenderingContext2d")?; @@ -234,9 +205,39 @@ impl WebImpl { } } -impl SurfaceInterface for WebImpl { +impl SurfaceInterface for WebImpl { + type Context = WebDisplayImpl; type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + fn new(window: W, display: &WebDisplayImpl) -> Result> { + let raw = window.window_handle()?.as_raw(); + let canvas: HtmlCanvasElement = match raw { + RawWindowHandle::Web(handle) => { + display + .document + .query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id)) + // `querySelector` only throws an error if the selector is invalid. + .unwrap() + .swbuf_err("No canvas found with the given id")? + // We already made sure this was a canvas in `querySelector`. + .unchecked_into() + } + RawWindowHandle::WebCanvas(handle) => { + let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; + value.clone().unchecked_into() + } + RawWindowHandle::WebOffscreenCanvas(handle) => { + let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; + let canvas: OffscreenCanvas = value.clone().unchecked_into(); + + return Self::from_offscreen_canvas(canvas, window).map_err(InitError::Failure); + } + _ => return Err(InitError::Unsupported(window)), + }; + + Self::from_canvas(canvas, window).map_err(InitError::Failure) + } + /// Get the inner window handle. #[inline] fn window(&self) -> &W { diff --git a/src/backends/win32.rs b/src/backends/win32.rs index a4d98274..120b55aa 100644 --- a/src/backends/win32.rs +++ b/src/backends/win32.rs @@ -159,8 +159,37 @@ struct BitmapInfo { } 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, x, y, width, height, buffer.dc, x, y, Gdi::SRCCOPY); + } + + // Validate the window. + Gdi::ValidateRect(self.window, ptr::null_mut()); + } + buffer.presented = true; + + Ok(()) + } +} + +impl SurfaceInterface for Win32Impl { + type Context = D; + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + /// Create a new `Win32Impl` from a `Win32WindowHandle`. - pub(crate) fn new(window: W) -> Result> { + fn new(window: W, _display: &D) -> Result> { let raw = window.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::Win32(handle) => handle, @@ -190,34 +219,6 @@ 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, x, y, width, height, buffer.dc, x, y, Gdi::SRCCOPY); - } - - // Validate the window. - Gdi::ValidateRect(self.window, ptr::null_mut()); - } - buffer.presented = true; - - Ok(()) - } -} - -impl SurfaceInterface for Win32Impl { - type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; - #[inline] fn window(&self) -> &W { &self.handle diff --git a/src/backends/x11.rs b/src/backends/x11.rs index ed214863..16bdab4a 100644 --- a/src/backends/x11.rs +++ b/src/backends/x11.rs @@ -54,9 +54,9 @@ pub struct X11DisplayImpl { _display: D, } -impl X11DisplayImpl { +impl ContextInterface for Rc> { /// Create a new `X11DisplayImpl`. - pub(crate) fn new(display: D) -> Result> + fn new(display: D) -> Result> where D: Sized, { @@ -107,12 +107,12 @@ impl X11DisplayImpl { let supported_visuals = supported_visuals(&connection); - Ok(Self { + Ok(Rc::new(X11DisplayImpl { connection: Some(connection), is_shm_available, supported_visuals, _display: display, - }) + })) } } @@ -182,9 +182,12 @@ struct ShmBuffer { done_processing: Option, } -impl X11Impl { +impl SurfaceInterface for X11Impl { + type Context = Rc>; + type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; + /// Create a new `X11Impl` from a `HasWindowHandle`. - pub(crate) fn new(window_src: W, display: Rc>) -> Result> { + fn new(window_src: W, display: &Rc>) -> Result> { // Get the underlying raw window handle. let raw = window_src.window_handle()?.as_raw(); let window_handle = match raw { @@ -285,7 +288,7 @@ impl X11Impl { }; Ok(Self { - display, + display: display.clone(), window, gc, depth: geometry_reply.depth, @@ -296,10 +299,6 @@ impl X11Impl { window_handle: window_src, }) } -} - -impl SurfaceInterface for X11Impl { - type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; #[inline] fn window(&self) -> &W { diff --git a/src/lib.rs b/src/lib.rs index ec298538..13e97baf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,8 +19,6 @@ mod util; use std::marker::PhantomData; use std::num::NonZeroU32; use std::ops; -#[cfg(any(wayland_platform, x11_platform, kms_platform))] -use std::rc::Rc; use error::InitError; pub use error::SoftBufferError; @@ -41,43 +39,21 @@ pub struct Context { impl Context { /// Creates a new instance of this struct, using the provided display. - pub fn new(mut dpy: D) -> Result { - macro_rules! try_init { - ($imp:ident, $x:ident => $make_it:expr) => {{ - let $x = dpy; - match { $make_it } { - Ok(x) => { - return Ok(Self { - context_impl: ContextDispatch::$imp(x), - _marker: PhantomData, - }) - } - Err(InitError::Unsupported(d)) => dpy = d, - Err(InitError::Failure(f)) => return Err(f), - } - }}; + pub fn new(display: D) -> Result { + match ContextDispatch::new(display) { + Ok(context_impl) => Ok(Self { + context_impl, + _marker: PhantomData, + }), + Err(InitError::Unsupported(display)) => { + let raw = display.display_handle()?.as_raw(); + Err(SoftBufferError::UnsupportedDisplayPlatform { + human_readable_display_platform_name: display_handle_type_name(&raw), + display_handle: raw, + }) + } + Err(InitError::Failure(f)) => Err(f), } - - #[cfg(x11_platform)] - try_init!(X11, display => backends::x11::X11DisplayImpl::new(display).map(Rc::new)); - #[cfg(wayland_platform)] - try_init!(Wayland, display => backends::wayland::WaylandDisplayImpl::new(display).map(Rc::new)); - #[cfg(kms_platform)] - try_init!(Kms, display => backends::kms::KmsDisplayImpl::new(display).map(Rc::new)); - #[cfg(target_os = "windows")] - try_init!(Win32, display => Ok(display)); - #[cfg(target_os = "macos")] - try_init!(CG, display => Ok(display)); - #[cfg(target_arch = "wasm32")] - try_init!(Web, display => backends::web::WebDisplayImpl::new(display)); - #[cfg(target_os = "redox")] - try_init!(Orbital, display => Ok(display)); - - let raw = dpy.display_handle()?.as_raw(); - Err(SoftBufferError::UnsupportedDisplayPlatform { - human_readable_display_platform_name: display_handle_type_name(&raw), - display_handle: raw, - }) } } @@ -104,58 +80,21 @@ pub struct Surface { impl Surface { /// Creates a new surface for the context for the provided window. pub fn new(context: &Context, window: W) -> Result { - macro_rules! leap { - ($e:expr) => {{ - match ($e) { - Ok(x) => x, - Err(InitError::Unsupported(window)) => { - let raw = window.window_handle()?.as_raw(); - return Err(SoftBufferError::UnsupportedWindowPlatform { - human_readable_window_platform_name: window_handle_type_name(&raw), - human_readable_display_platform_name: context - .context_impl - .variant_name(), - window_handle: raw, - }); - } - Err(InitError::Failure(f)) => return Err(f), - } - }}; - } - - let imple = match &context.context_impl { - #[cfg(x11_platform)] - ContextDispatch::X11(xcb_display_handle) => SurfaceDispatch::X11(leap!( - backends::x11::X11Impl::new(window, xcb_display_handle.clone()) - )), - #[cfg(wayland_platform)] - ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!( - backends::wayland::WaylandImpl::new(window, wayland_display_impl.clone()) - )), - #[cfg(kms_platform)] - ContextDispatch::Kms(kms_display_impl) => SurfaceDispatch::Kms(leap!( - backends::kms::KmsImpl::new(window, kms_display_impl.clone()) - )), - #[cfg(target_os = "windows")] - ContextDispatch::Win32(_) => { - SurfaceDispatch::Win32(leap!(backends::win32::Win32Impl::new(window))) + match SurfaceDispatch::new(window, &context.context_impl) { + Ok(surface_dispatch) => Ok(Self { + surface_impl: Box::new(surface_dispatch), + _marker: PhantomData, + }), + Err(InitError::Unsupported(window)) => { + let raw = window.window_handle()?.as_raw(); + Err(SoftBufferError::UnsupportedWindowPlatform { + human_readable_window_platform_name: window_handle_type_name(&raw), + human_readable_display_platform_name: context.context_impl.variant_name(), + window_handle: raw, + }) } - #[cfg(target_os = "macos")] - ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(backends::cg::CGImpl::new(window))), - #[cfg(target_arch = "wasm32")] - ContextDispatch::Web(web_display_impl) => { - SurfaceDispatch::Web(leap!(backends::web::WebImpl::new(web_display_impl, window))) - } - #[cfg(target_os = "redox")] - ContextDispatch::Orbital(_) => { - SurfaceDispatch::Orbital(leap!(backends::orbital::OrbitalImpl::new(window))) - } - }; - - Ok(Self { - surface_impl: Box::new(imple), - _marker: PhantomData, - }) + Err(InitError::Failure(f)) => Err(f), + } } /// Get a reference to the underlying window handle.