diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26811d6..af55c9c 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 diff --git a/src/backend_dispatch.rs b/src/backend_dispatch.rs new file mode 100644 index 0000000..e23a0c2 --- /dev/null +++ b/src/backend_dispatch.rs @@ -0,0 +1,195 @@ +//! Implements `buffer_interface::*` traits for enums dispatching to backends + +use crate::{backend_interface::*, backends, InitError, 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), + )* + } + } + } + + 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> { + $( + $(#[$attr])* + $name($surface_inner), + )* + } + + 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 { + $( + $(#[$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>, backends::x11::X11Impl, backends::x11::BufferImpl<'a, D, W>), + #[cfg(wayland_platform)] + Wayland(Rc>, backends::wayland::WaylandImpl, backends::wayland::BufferImpl<'a, D, W>), + #[cfg(kms_platform)] + Kms(Rc>, backends::kms::KmsImpl, backends::kms::BufferImpl<'a, D, W>), + #[cfg(target_os = "windows")] + Win32(D, backends::win32::Win32Impl, backends::win32::BufferImpl<'a, D, W>), + #[cfg(target_os = "macos")] + CG(D, backends::cg::CGImpl, backends::cg::BufferImpl<'a, D, W>), + #[cfg(target_arch = "wasm32")] + Web(backends::web::WebDisplayImpl, backends::web::WebImpl, backends::web::BufferImpl<'a, D, W>), + #[cfg(target_os = "redox")] + Orbital(D, backends::orbital::OrbitalImpl, backends::orbital::BufferImpl<'a, D, W>), +} diff --git a/src/backend_interface.rs b/src/backend_interface.rs new file mode 100644 index 0000000..13e3555 --- /dev/null +++ b/src/backend_interface.rs @@ -0,0 +1,43 @@ +//! Interface implemented by backends + +use crate::{InitError, Rect, SoftBufferError}; + +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use std::num::NonZeroU32; + +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. + 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/backends/cg.rs similarity index 82% rename from src/cg.rs rename to src/backends/cg.rs index ef96fb9..3757880 100644 --- a/src/cg.rs +++ b/src/backends/cg.rs @@ -1,3 +1,4 @@ +use crate::backend_interface::*; use crate::error::InitError; use crate::{Rect, SoftBufferError}; use core_graphics::base::{ @@ -34,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,18 +70,17 @@ impl CGImpl { }) } - /// 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 +90,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 +97,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 +146,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/backends/kms.rs similarity index 90% rename from src/kms.rs rename to src/backends/kms.rs index 2761843..13c040b 100644 --- a/src/kms.rs +++ b/src/backends/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)] @@ -37,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)), @@ -50,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, - }) + })) } } @@ -134,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) { @@ -198,24 +205,18 @@ impl KmsImpl { Ok(Self { crtc, connectors, - display, + display: display.clone(), buffer: None, window_handle: window, }) } - /// 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 +238,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 +299,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 +374,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/backends/mod.rs b/src/backends/mod.rs new file mode 100644 index 0000000..8402b44 --- /dev/null +++ b/src/backends/mod.rs @@ -0,0 +1,23 @@ +use crate::{ContextInterface, InitError}; +use raw_window_handle::HasDisplayHandle; + +#[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; + +impl ContextInterface for D { + fn new(display: D) -> Result> { + Ok(display) + } +} diff --git a/src/orbital.rs b/src/backends/orbital.rs similarity index 88% rename from src/orbital.rs rename to src/backends/orbital.rs index 50c80d4..7fb5c16 100644 --- a/src/orbital.rs +++ b/src/backends/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 { @@ -64,40 +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, - }) - } - - /// 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 +89,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 +120,57 @@ 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 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 + } - /// Fetch the buffer from the window. - pub fn fetch(&mut self) -> Result, SoftBufferError> { - Err(SoftBufferError::Unimplemented) + 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 +184,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 +194,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 +224,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/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 89% rename from src/wayland/mod.rs rename to src/backends/wayland/mod.rs index d61a5f1..32be3d4 100644 --- a/src/wayland/mod.rs +++ b/src/backends/wayland/mod.rs @@ -1,4 +1,5 @@ use crate::{ + backend_interface::*, error::{InitError, SwResultExt}, util, Rect, SoftBufferError, }; @@ -34,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, { @@ -52,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() + })) } } @@ -87,7 +90,65 @@ pub struct WaylandImpl { } impl WaylandImpl { - pub(crate) fn new(window: W, display: Rc>) -> Result> { + 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 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 { @@ -105,7 +166,7 @@ impl WaylandImpl { let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id) .swbuf_err("Failed to create proxy for surface ID.")?; Ok(Self { - display, + display: display.clone(), surface: Some(surface), buffers: Default::default(), size: None, @@ -113,13 +174,12 @@ impl WaylandImpl { }) } - /// 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( (|| { let width = NonZeroI32::try_from(width).ok()?; @@ -131,7 +191,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 +238,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 +252,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/backends/web.rs similarity index 92% rename from src/web.rs rename to src/backends/web.rs index 595073d..2b8e9b5 100644 --- a/src/web.rs +++ b/src/backends/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; @@ -23,8 +24,8 @@ pub struct WebDisplayImpl { _display: D, } -impl WebDisplayImpl { - pub(super) 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(..) => {} @@ -77,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")?; @@ -135,13 +107,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 +122,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 +203,66 @@ impl WebImpl { Ok(()) } +} + +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 { + &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 +374,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 +392,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 +405,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/backends/win32.rs similarity index 89% rename from src/win32.rs rename to src/backends/win32.rs index 7055b44..120b55a 100644 --- a/src/win32.rs +++ b/src/backends/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}; @@ -158,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, @@ -189,13 +219,12 @@ impl Win32Impl { }) } - /// Get the inner window handle. #[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 +243,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 +251,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 +289,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/backends/x11.rs similarity index 96% rename from src/x11.rs rename to src/backends/x11.rs index 31b2325..16bdab4 100644 --- a/src/x11.rs +++ b/src/backends/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::{ @@ -53,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, { @@ -106,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, - }) + })) } } @@ -181,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 { @@ -284,7 +288,7 @@ impl X11Impl { }; Ok(Self { - display, + display: display.clone(), window, gc, depth: geometry_reply.depth, @@ -296,18 +300,12 @@ impl X11Impl { }) } - /// 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 +335,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 +345,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 +384,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 +408,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 +498,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 diff --git a/src/error.rs b/src/error.rs index c2994a7..eaec856 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; } diff --git a/src/lib.rs b/src/lib.rs index 14191ca..13e97ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,29 +8,17 @@ 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; 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; @@ -38,7 +26,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. @@ -49,197 +37,23 @@ 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 { - 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 => x11::X11DisplayImpl::new(display).map(Rc::new)); - #[cfg(wayland_platform)] - try_init!(Wayland, display => wayland::WaylandDisplayImpl::new(display).map(Rc::new)); - #[cfg(kms_platform)] - try_init!(Kms, display => 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)); - #[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, - }) } } @@ -266,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!(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()) - )), - #[cfg(kms_platform)] - ContextDispatch::Kms(kms_display_impl) => { - SurfaceDispatch::Kms(leap!(kms::KmsImpl::new(window, kms_display_impl.clone()))) - } - #[cfg(target_os = "windows")] - ContextDispatch::Win32(_) => { - SurfaceDispatch::Win32(leap!(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!(cg::CGImpl::new(window))), - #[cfg(target_arch = "wasm32")] - ContextDispatch::Web(web_display_impl) => { - SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window))) - } - #[cfg(target_os = "redox")] - ContextDispatch::Orbital(_) => { - SurfaceDispatch::Orbital(leap!(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.