From b2fbf2338a033d605ec90f8a274902b2c87df5e6 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sun, 9 Jul 2023 19:56:17 -0700 Subject: [PATCH 1/6] Implement rwh v0.6 for softbuffer Signed-off-by: John Nunley Co-Authored-By: dAxpeDDa --- CHANGELOG.md | 4 + Cargo.toml | 8 +- README.md | 7 +- benches/buffer_mut.rs | 2 +- examples/animation.rs | 41 ++--- examples/fruit.rs | 17 +- examples/libxcb.rs | 17 +- examples/rectangle.rs | 56 +++--- examples/winit.rs | 46 +++-- examples/winit_wrong_sized_buffer.rs | 9 +- src/cg.rs | 32 ++-- src/error.rs | 45 ++++- src/lib.rs | 258 +++++++++++++-------------- src/orbital.rs | 31 +++- src/util.rs | 4 +- src/wayland/mod.rs | 116 ++++++++---- src/web.rs | 74 +++++--- src/win32.rs | 42 +++-- src/x11.rs | 188 ++++++++++--------- tests/present_and_fetch.rs | 9 +- 20 files changed, 598 insertions(+), 408 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ff0ab..d132f25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased + +* **Breaking:** Port to use `raw-window-handle` v0.6. + # 0.3.2 * Document that `present_with_damage` is supported on web platforms. (#152) diff --git a/Cargo.toml b/Cargo.toml index 66cee28..b0ad381 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ x11-dlopen = ["tiny-xlib/dlopen", "x11rb/dl-libxcb"] [dependencies] log = "0.4.17" -raw-window-handle = "0.5.0" +raw_window_handle = { package = "raw-window-handle", version = "0.6", features = ["std"] } [target.'cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))'.dependencies] as-raw-xcb-connection = { version = "1.0.0", optional = true } @@ -79,7 +79,7 @@ cfg_aliases = "0.1.1" colorous = "1.0.12" criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } instant = "0.1.12" -winit = "0.28.1" +winit = "0.29.0-beta.0" winit-test = "0.1.0" [dev-dependencies.image] @@ -119,3 +119,7 @@ targets = [ "x86_64-unknown-linux-gnu", "wasm32-unknown-unknown", ] + +[patch.crates-io] +raw_window_handle = { package = "raw-window-handle", git = "https://github.com/rust-windowing/raw-window-handle.git", branch = "notgull/next" } +winit = { git = "https://github.com/forkgull/winit.git", branch = "rwh-0.6" } diff --git a/README.md b/README.md index baa3ade..3bd2722 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,16 @@ Example == ```rust,no_run use std::num::NonZeroU32; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&event_loop).unwrap(); - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/benches/buffer_mut.rs b/benches/buffer_mut.rs index 810a10c..0c1772b 100644 --- a/benches/buffer_mut.rs +++ b/benches/buffer_mut.rs @@ -26,7 +26,7 @@ fn buffer_mut(c: &mut Criterion) { if let winit::event::Event::RedrawEventsCleared = ev { control_flow.set_exit(); - let mut surface = unsafe { + let mut surface = { let context = Context::new(elwt).unwrap(); Surface::new(&context, &window).unwrap() }; diff --git a/examples/animation.rs b/examples/animation.rs index 933f332..3a0a1d5 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -3,13 +3,14 @@ use instant::Instant; use rayon::prelude::*; use std::f64::consts::PI; use std::num::NonZeroU32; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&event_loop).unwrap(); + let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] { @@ -21,12 +22,12 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&window.canvas()) + .append_child(&window.canvas().unwrap()) .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); let mut old_size = (0, 0); let mut frames = pre_render_frames(0, 0); @@ -37,28 +38,24 @@ fn main() { match event { Event::RedrawRequested(window_id) if window_id == window.id() => { - let elapsed = start.elapsed().as_secs_f64() % 1.0; - let (width, height) = { + if let (Some(width), Some(height)) = { let size = window.inner_size(); - (size.width, size.height) - }; + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + let elapsed = start.elapsed().as_secs_f64() % 1.0; - if (width, height) != old_size { - old_size = (width, height); - frames = pre_render_frames(width as usize, height as usize); - }; + if (width.get(), height.get()) != old_size { + old_size = (width.get(), height.get()); + frames = pre_render_frames(width.get() as usize, height.get() as usize); + }; - let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; + let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; - surface - .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - buffer.copy_from_slice(frame); - buffer.present().unwrap(); + surface.resize(width, height).unwrap(); + let mut buffer = surface.buffer_mut().unwrap(); + buffer.copy_from_slice(frame); + buffer.present().unwrap(); + } } Event::MainEventsCleared => { window.request_redraw(); diff --git a/examples/fruit.rs b/examples/fruit.rs index 7e28e89..964c525 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -1,5 +1,6 @@ use image::GenericImageView; use std::num::NonZeroU32; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; @@ -9,10 +10,12 @@ fn main() { let fruit = image::load_from_memory(include_bytes!("fruit.jpg")).unwrap(); let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .with_inner_size(winit::dpi::PhysicalSize::new(fruit.width(), fruit.height())) - .build(&event_loop) - .unwrap(); + let window = Rc::new( + WindowBuilder::new() + .with_inner_size(winit::dpi::PhysicalSize::new(fruit.width(), fruit.height())) + .build(&event_loop) + .unwrap(), + ); #[cfg(target_arch = "wasm32")] { @@ -24,12 +27,12 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&window.canvas()) + .append_child(&window.canvas().unwrap()) .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/libxcb.rs b/examples/libxcb.rs index 4ea97b0..83dfeaa 100644 --- a/examples/libxcb.rs +++ b/examples/libxcb.rs @@ -2,7 +2,10 @@ #[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))] mod example { - use raw_window_handle::{RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, XcbWindowHandle}; + use raw_window_handle::{ + DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, XcbDisplayHandle, + XcbWindowHandle, + }; use std::num::NonZeroU32; use x11rb::{ connection::Connection, @@ -56,12 +59,12 @@ mod example { // Create a new softbuffer context. // SAFETY: The display and window handles outlive the context. - let context = - unsafe { softbuffer::Context::from_raw(RawDisplayHandle::Xcb(display_handle)) } - .unwrap(); - let mut surface = - unsafe { softbuffer::Surface::from_raw(&context, RawWindowHandle::Xcb(window_handle)) } - .unwrap(); + let display_handle = + unsafe { DisplayHandle::borrow_raw(RawDisplayHandle::Xcb(display_handle)) }; + let window_handle = + unsafe { WindowHandle::borrow_raw(RawWindowHandle::Xcb(window_handle)) }; + let context = softbuffer::Context::new(display_handle).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window_handle).unwrap(); // Register an atom for closing the window. let wm_protocols_atom = conn diff --git a/examples/rectangle.rs b/examples/rectangle.rs index 4940ed3..d69e5dd 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -1,6 +1,8 @@ use std::num::NonZeroU32; -use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use std::rc::Rc; +use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; +use winit::keyboard::KeyCode; use winit::window::WindowBuilder; fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { @@ -22,10 +24,12 @@ fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .with_title("Press space to show/hide a rectangle") - .build(&event_loop) - .unwrap(); + let window = Rc::new( + WindowBuilder::new() + .with_title("Press space to show/hide a rectangle") + .build(&event_loop) + .unwrap(), + ); #[cfg(target_arch = "wasm32")] { @@ -37,12 +41,12 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&window.canvas()) + .append_child(&window.canvas().unwrap()) .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); let mut flag = false; @@ -52,23 +56,23 @@ fn main() { match event { Event::RedrawRequested(window_id) if window_id == window.id() => { // Grab the window's client area dimensions - let (width, height) = { + if let (Some(width), Some(height)) = { let size = window.inner_size(); - (size.width, size.height) - }; + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + // Resize surface if needed + surface.resize(width, height).unwrap(); - // Resize surface if needed - surface - .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .unwrap(); - - // Draw something in the window - let mut buffer = surface.buffer_mut().unwrap(); - redraw(&mut buffer, width as usize, height as usize, flag); - buffer.present().unwrap(); + // Draw something in the window + let mut buffer = surface.buffer_mut().unwrap(); + redraw( + &mut buffer, + width.get() as usize, + height.get() as usize, + flag, + ); + buffer.present().unwrap(); + } } Event::WindowEvent { @@ -81,10 +85,10 @@ fn main() { Event::WindowEvent { event: WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { state: ElementState::Pressed, - virtual_keycode: Some(VirtualKeyCode::Space), + physical_key: KeyCode::Space, .. }, .. diff --git a/examples/winit.rs b/examples/winit.rs index fe5a82b..1c90191 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -1,11 +1,12 @@ use std::num::NonZeroU32; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&event_loop).unwrap(); + let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] { @@ -17,42 +18,37 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&window.canvas()) + .append_child(&window.canvas().unwrap()) .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; match event { Event::RedrawRequested(window_id) if window_id == window.id() => { - let (width, height) = { + if let (Some(width), Some(height)) = { let size = window.inner_size(); - (size.width, size.height) - }; - - surface - .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .unwrap(); - - let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..height { - for x in 0..width { - let red = x % 255; - let green = y % 255; - let blue = (x * y) % 255; - let index = y as usize * width as usize + x as usize; - buffer[index] = blue | (green << 8) | (red << 16); + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + surface.resize(width, height).unwrap(); + + let mut buffer = surface.buffer_mut().unwrap(); + for y in 0..height.get() { + for x in 0..width.get() { + let red = x % 255; + let green = y % 255; + let blue = (x * y) % 255; + let index = y as usize * width.get() as usize + x as usize; + buffer[index] = blue | (green << 8) | (red << 16); + } } - } - buffer.present().unwrap(); + buffer.present().unwrap(); + } } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 09aff57..21716d7 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -1,4 +1,5 @@ use std::num::NonZeroU32; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; @@ -8,7 +9,7 @@ const BUFFER_HEIGHT: usize = 128; fn main() { let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&event_loop).unwrap(); + let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] { @@ -20,12 +21,12 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&window.canvas()) + .append_child(&window.canvas().unwrap()) .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let context = softbuffer::Context::new(window.clone()).unwrap(); + let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/src/cg.rs b/src/cg.rs index 4ee40d6..4ebb458 100644 --- a/src/cg.rs +++ b/src/cg.rs @@ -1,3 +1,4 @@ +use crate::error::InitError; use crate::{Rect, SoftBufferError}; use core_graphics::base::{ kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault, @@ -5,13 +6,14 @@ use core_graphics::base::{ use core_graphics::color_space::CGColorSpace; use core_graphics::data_provider::CGDataProvider; use core_graphics::image::CGImage; -use raw_window_handle::AppKitWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawWindowHandle}; use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow}; use cocoa::base::{id, nil}; use cocoa::quartzcore::{transaction, CALayer, ContentsGravity}; use foreign_types::ForeignType; +use std::marker::PhantomData; use std::num::NonZeroU32; use std::sync::Arc; @@ -23,17 +25,24 @@ impl AsRef<[u8]> for Buffer { } } -pub struct CGImpl { +pub struct CGImpl { layer: CALayer, window: id, color_space: CGColorSpace, size: Option<(NonZeroU32, NonZeroU32)>, + _window_source: W, + _display: PhantomData, } -impl CGImpl { - pub unsafe fn new(handle: AppKitWindowHandle) -> Result { +impl CGImpl { + pub(crate) fn new(window_src: W) -> Result> { + let raw = window_src.window_handle()?.raw_window_handle()?; + let handle = match raw { + RawWindowHandle::AppKit(handle) => handle, + _ => return Err(InitError::Unsupported(window_src)), + }; let window = handle.ns_window as id; - let window: id = msg_send![window, retain]; + let window: id = unsafe { msg_send![window, retain] }; let view = handle.ns_view as id; let layer = CALayer::new(); unsafe { @@ -52,6 +61,8 @@ impl CGImpl { window, color_space, size: None, + _display: PhantomData, + _window_source: window_src, }) } @@ -60,10 +71,11 @@ impl CGImpl { Ok(()) } - pub fn buffer_mut(&mut self) -> Result { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { let (width, height) = self .size .expect("Must set size of surface before calling `buffer_mut()`"); + Ok(BufferImpl { buffer: vec![0; width.get() as usize * height.get() as usize], imp: self, @@ -76,12 +88,12 @@ impl CGImpl { } } -pub struct BufferImpl<'a> { - imp: &'a mut CGImpl, +pub struct BufferImpl<'a, D, W> { + imp: &'a mut CGImpl, buffer: Vec, } -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { &self.buffer @@ -135,7 +147,7 @@ impl<'a> BufferImpl<'a> { } } -impl Drop for CGImpl { +impl Drop for CGImpl { fn drop(&mut self) { unsafe { let _: () = msg_send![self.window, release]; diff --git a/src/error.rs b/src/error.rs index f9d6797..c2994a7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; +use raw_window_handle::{HandleError, RawDisplayHandle, RawWindowHandle}; use std::error::Error; use std::fmt; use std::num::NonZeroU32; @@ -7,6 +7,11 @@ use std::num::NonZeroU32; #[non_exhaustive] /// A sum type of all of the errors that can occur during the operation of this crate. pub enum SoftBufferError { + /// A [`raw-window-handle`] error occurred. + /// + /// [`raw-window-handle`]: raw_window_handle + RawWindowHandle(HandleError), + /// The [`RawDisplayHandle`] passed into [`Context::new`] is not supported by this crate. /// /// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle @@ -102,6 +107,7 @@ pub enum SoftBufferError { impl fmt::Display for SoftBufferError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + Self::RawWindowHandle(err) => fmt::Display::fmt(err, f), Self::UnsupportedDisplayPlatform { human_readable_display_platform_name, display_handle, @@ -137,7 +143,42 @@ impl fmt::Display for SoftBufferError { } } -impl std::error::Error for SoftBufferError {} +impl std::error::Error for SoftBufferError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + Self::RawWindowHandle(err) => Some(err), + Self::PlatformError(_, err) => err.as_deref(), + _ => None, + } + } +} + +impl From for SoftBufferError { + fn from(err: HandleError) -> Self { + Self::RawWindowHandle(err) + } +} + +/// Simple unit error type used to bubble up rejected platforms. +pub(crate) enum InitError { + /// Failed to initialize. + Failure(SoftBufferError), + + /// Cannot initialize this handle on this platform. + Unsupported(D), +} + +impl From for InitError { + fn from(err: SoftBufferError) -> Self { + Self::Failure(err) + } +} + +impl From for InitError { + fn from(err: HandleError) -> Self { + Self::Failure(err.into()) + } +} /// Convenient wrapper to cast errors into SoftBufferError. pub(crate) trait SwResultExt { diff --git a/src/lib.rs b/src/lib.rs index 801016b..152d41e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,10 +32,12 @@ use std::ops; #[cfg(any(wayland_platform, x11_platform, kms_platform))] use std::rc::Rc; +use error::InitError; pub use error::SoftBufferError; use raw_window_handle::{ - HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, + HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, + RawWindowHandle, }; #[cfg(target_arch = "wasm32")] @@ -43,28 +45,31 @@ pub use self::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. -pub struct Context { - /// The inner static dispatch object. - context_impl: ContextDispatch, +pub struct Context { _marker: PhantomData<*mut ()>, + + /// The inner static dispatch object. + 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), + $name: ident + ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty), )* ) => { - enum ContextDispatch { + enum ContextDispatch<$dgen> { $( $(#[$attr])* $name($context_inner), )* } - impl ContextDispatch { + impl ContextDispatch { fn variant_name(&self) -> &'static str { match self { $( @@ -76,14 +81,14 @@ macro_rules! make_dispatch { } #[allow(clippy::large_enum_variant)] // it's boxed anyways - enum SurfaceDispatch { + enum SurfaceDispatch<$dgen, $wgen> { $( $(#[$attr])* $name($surface_inner), )* } - impl SurfaceDispatch { + impl SurfaceDispatch { pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { match self { $( @@ -93,7 +98,7 @@ macro_rules! make_dispatch { } } - pub fn buffer_mut(&mut self) -> Result { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { match self { $( $(#[$attr])* @@ -112,14 +117,14 @@ macro_rules! make_dispatch { } } - enum BufferDispatch<'a> { + enum BufferDispatch<'a, $dgen, $wgen> { $( $(#[$attr])* $name($buffer_inner), )* } - impl<'a> BufferDispatch<'a> { + impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferDispatch<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { match self { @@ -173,30 +178,41 @@ macro_rules! make_dispatch { // XXX empty enum with generic bound is invalid? make_dispatch! { + => #[cfg(x11_platform)] - X11(Rc, x11::X11Impl, x11::BufferImpl<'a>), + X11(Rc>, x11::X11Impl, x11::BufferImpl<'a, D, W>), #[cfg(wayland_platform)] - Wayland(Rc, wayland::WaylandImpl, wayland::BufferImpl<'a>), + Wayland(Rc>, wayland::WaylandImpl, wayland::BufferImpl<'a, D, W>), #[cfg(kms_platform)] Kms(Rc, kms::KmsImpl, kms::BufferImpl<'a>), #[cfg(target_os = "windows")] - Win32((), win32::Win32Impl, win32::BufferImpl<'a>), + Win32(D, win32::Win32Impl, win32::BufferImpl<'a, D, W>), #[cfg(target_os = "macos")] - CG((), cg::CGImpl, cg::BufferImpl<'a>), + CG(D, cg::CGImpl, cg::BufferImpl<'a, D, W>), #[cfg(target_arch = "wasm32")] - Web(web::WebDisplayImpl, web::WebImpl, web::BufferImpl<'a>), + Web(web::WebDisplayImpl, web::WebImpl, web::BufferImpl<'a, D, W>), #[cfg(target_os = "redox")] - Orbital((), orbital::OrbitalImpl, orbital::BufferImpl<'a>), + Orbital(D, orbital::OrbitalImpl, orbital::BufferImpl<'a, D, W>), } -impl Context { +impl Context { /// Creates a new instance of this struct, using the provided display. - /// - /// # Safety - /// - /// - Ensure that the provided object is valid for the lifetime of the Context - pub unsafe fn new(display: &D) -> Result { - unsafe { Self::from_raw(display.raw_display_handle()) } + 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), + } + }}; + } } /// Creates a new instance of this struct, using the provided display handles @@ -205,44 +221,23 @@ impl Context { /// /// - Ensure that the provided handle is valid for the lifetime of the Context pub unsafe fn from_raw(raw_display_handle: RawDisplayHandle) -> Result { - let imple: ContextDispatch = match raw_display_handle { - #[cfg(x11_platform)] - RawDisplayHandle::Xlib(xlib_handle) => unsafe { - ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?)) - }, - #[cfg(x11_platform)] - RawDisplayHandle::Xcb(xcb_handle) => unsafe { - ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xcb(xcb_handle)?)) - }, - #[cfg(wayland_platform)] - RawDisplayHandle::Wayland(wayland_handle) => unsafe { - ContextDispatch::Wayland(Rc::new(wayland::WaylandDisplayImpl::new(wayland_handle)?)) - }, - #[cfg(kms_platform)] - RawDisplayHandle::Drm(drm_handle) => unsafe { - ContextDispatch::Kms(Rc::new(kms::KmsDisplayImpl::new(drm_handle)?)) - }, - #[cfg(target_os = "windows")] - RawDisplayHandle::Windows(_) => ContextDispatch::Win32(()), - #[cfg(target_os = "macos")] - RawDisplayHandle::AppKit(_) => ContextDispatch::CG(()), - #[cfg(target_arch = "wasm32")] - RawDisplayHandle::Web(_) => ContextDispatch::Web(web::WebDisplayImpl::new()?), - #[cfg(target_os = "redox")] - RawDisplayHandle::Orbital(_) => ContextDispatch::Orbital(()), - unimplemented_display_handle => { - return Err(SoftBufferError::UnsupportedDisplayPlatform { - human_readable_display_platform_name: display_handle_type_name( - &unimplemented_display_handle, - ), - display_handle: unimplemented_display_handle, - }) - } - }; - - Ok(Self { - context_impl: imple, - _marker: PhantomData, + #[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(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()?.raw_display_handle()?; + Err(SoftBufferError::UnsupportedDisplayPlatform { + human_readable_display_platform_name: display_handle_type_name(&raw), + display_handle: raw, }) } } @@ -261,87 +256,56 @@ pub struct Rect { } /// A surface for drawing to a window with software buffers. -pub struct Surface { +pub struct Surface { /// This is boxed so that `Surface` is the same size on every platform. - surface_impl: Box, + surface_impl: Box>, _marker: PhantomData<*mut ()>, } -impl Surface { +impl Surface { /// Creates a new surface for the context for the provided window. - /// - /// # Safety - /// - /// - Ensure that the provided objects are valid to draw a 2D buffer to, and are valid for the - /// lifetime of the Context - pub unsafe fn new( - context: &Context, - window: &W, - ) -> Result { - unsafe { Self::from_raw(context, window.raw_window_handle()) } - } + 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()?.raw_window_handle()?; + 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), + } + }}; + } - /// Creates a new surface for the context for the provided raw window handle. - /// - /// # Safety - /// - /// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the - /// lifetime of the Context - pub unsafe fn from_raw( - context: &Context, - raw_window_handle: RawWindowHandle, - ) -> Result { - let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle) { + let imple = match &context.context_impl { #[cfg(x11_platform)] - ( - ContextDispatch::X11(xcb_display_handle), - RawWindowHandle::Xlib(xlib_window_handle), - ) => SurfaceDispatch::X11(unsafe { - x11::X11Impl::from_xlib(xlib_window_handle, xcb_display_handle.clone())? - }), - #[cfg(x11_platform)] - (ContextDispatch::X11(xcb_display_handle), RawWindowHandle::Xcb(xcb_window_handle)) => { - SurfaceDispatch::X11(unsafe { - x11::X11Impl::from_xcb(xcb_window_handle, xcb_display_handle.clone())? - }) + ContextDispatch::X11(xcb_display_handle) => { + SurfaceDispatch::X11(leap!(x11::X11Impl::new(window, xcb_display_handle.clone()))) } #[cfg(wayland_platform)] - ( - ContextDispatch::Wayland(wayland_display_impl), - RawWindowHandle::Wayland(wayland_window_handle), - ) => SurfaceDispatch::Wayland(unsafe { - wayland::WaylandImpl::new(wayland_window_handle, wayland_display_impl.clone())? - }), - #[cfg(kms_platform)] - (ContextDispatch::Kms(kms_display_impl), RawWindowHandle::Drm(drm_window_handle)) => { - SurfaceDispatch::Kms(unsafe { - kms::KmsImpl::new(drm_window_handle, kms_display_impl.clone())? - }) - } + ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!( + wayland::WaylandImpl::new(window, wayland_display_impl.clone()) + )), #[cfg(target_os = "windows")] - (ContextDispatch::Win32(()), RawWindowHandle::Win32(win32_handle)) => { - SurfaceDispatch::Win32(unsafe { win32::Win32Impl::new(&win32_handle)? }) + ContextDispatch::Win32(_) => { + SurfaceDispatch::Win32(leap!(win32::Win32Impl::new(window))) } #[cfg(target_os = "macos")] - (ContextDispatch::CG(()), RawWindowHandle::AppKit(appkit_handle)) => { - SurfaceDispatch::CG(unsafe { cg::CGImpl::new(appkit_handle)? }) - } + ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(cg::CGImpl::new(window))), #[cfg(target_arch = "wasm32")] - (ContextDispatch::Web(context), RawWindowHandle::Web(web_handle)) => { - SurfaceDispatch::Web(web::WebImpl::new(context, web_handle)?) + ContextDispatch::Web(web_display_impl) => { + SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window))) } #[cfg(target_os = "redox")] - (ContextDispatch::Orbital(()), RawWindowHandle::Orbital(orbital_handle)) => { - SurfaceDispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?) - } - (unsupported_display_impl, unimplemented_window_handle) => { - return Err(SoftBufferError::UnsupportedWindowPlatform { - human_readable_window_platform_name: window_handle_type_name( - &unimplemented_window_handle, - ), - human_readable_display_platform_name: unsupported_display_impl.variant_name(), - window_handle: unimplemented_window_handle, - }) + ContextDispatch::Orbital(_) => { + SurfaceDispatch::Orbital(leap!(orbital::OrbitalImpl::new(window))) } }; @@ -382,7 +346,7 @@ impl Surface { /// - On DRM/KMS, there is no reliable and sound way to wait for the page flip to happen from within /// `softbuffer`. Therefore it is the responsibility of the user to wait for the page flip before /// sending another frame. - pub fn buffer_mut(&mut self) -> Result { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { Ok(Buffer { buffer_impl: self.surface_impl.buffer_mut()?, _marker: PhantomData, @@ -426,12 +390,12 @@ impl Surface { /// Currently [`Buffer::present`] must block copying image data on: /// - Web /// - macOS -pub struct Buffer<'a> { - buffer_impl: BufferDispatch<'a>, +pub struct Buffer<'a, D, W> { + buffer_impl: BufferDispatch<'a, D, W>, _marker: PhantomData<*mut ()>, } -impl<'a> Buffer<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> { /// Is age is the number of frames ago this buffer was last presented. So if the value is /// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame /// before that (for backends using double buffering). If the value is `0`, it is a new @@ -474,7 +438,7 @@ impl<'a> Buffer<'a> { } } -impl<'a> ops::Deref for Buffer<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::Deref for Buffer<'a, D, W> { type Target = [u32]; #[inline] @@ -483,13 +447,37 @@ impl<'a> ops::Deref for Buffer<'a> { } } -impl<'a> ops::DerefMut for Buffer<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::DerefMut for Buffer<'a, D, W> { #[inline] fn deref_mut(&mut self) -> &mut [u32] { self.buffer_impl.pixels_mut() } } +/// There is no display handle. +#[derive(Debug)] +pub struct NoDisplayHandle(core::convert::Infallible); + +impl HasDisplayHandle for NoDisplayHandle { + fn display_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + match self.0 {} + } +} + +/// There is no window handle. +#[derive(Debug)] +pub struct NoWindowHandle(()); + +impl HasWindowHandle for NoWindowHandle { + fn window_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + Err(raw_window_handle::HandleError::NotSupported) + } +} + fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str { match handle { RawWindowHandle::Xlib(_) => "Xlib", diff --git a/src/orbital.rs b/src/orbital.rs index eb686e9..f934889 100644 --- a/src/orbital.rs +++ b/src/orbital.rs @@ -1,5 +1,8 @@ -use raw_window_handle::OrbitalWindowHandle; -use std::{cmp, num::NonZeroU32, slice, str}; +use crate::error::InitError; +use raw_window_handle::{ + HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle, +}; +use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str}; use crate::{Rect, SoftBufferError}; @@ -53,20 +56,30 @@ impl Drop for OrbitalMap { } } -pub struct OrbitalImpl { +pub struct OrbitalImpl { handle: OrbitalWindowHandle, width: u32, height: u32, presented: bool, + _window_source: W, + _display: PhantomData, } -impl OrbitalImpl { - pub fn new(handle: OrbitalWindowHandle) -> Result { +impl OrbitalImpl { + pub(crate) fn new(window: W) -> Result> { + let raw = window.window_handle()?.raw_window_handle()?; + let handle = match raw { + RawWindowHandle::Orbital(handle) => handle, + _ => return Err(InitError::Unsupported(window)), + }; + Ok(Self { handle, width: 0, height: 0, presented: false, + _window_source: window, + _display: PhantomData, }) } @@ -105,7 +118,7 @@ impl OrbitalImpl { (window_width, window_height) } - pub fn buffer_mut(&mut self) -> Result { + 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 { @@ -162,12 +175,12 @@ enum Pixels { Buffer(Vec), } -pub struct BufferImpl<'a> { - imp: &'a mut OrbitalImpl, +pub struct BufferImpl<'a, D, W> { + imp: &'a mut OrbitalImpl, pixels: Pixels, } -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { match &self.pixels { diff --git a/src/util.rs b/src/util.rs index c31c575..b1219e1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -13,13 +13,13 @@ use crate::SoftBufferError; /// /// This should be consistent with stacked borrow rules, and miri seems to /// accept it at least in simple cases. -pub struct BorrowStack<'a, T: 'static + ?Sized, U: 'static + ?Sized> { +pub struct BorrowStack<'a, T: 'a + ?Sized, U: 'a + ?Sized> { container: *mut T, member: *mut U, _phantom: std::marker::PhantomData<&'a mut T>, } -impl<'a, T: 'static + ?Sized, U: 'static + ?Sized> BorrowStack<'a, T, U> { +impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> { pub fn new(container: &'a mut T, f: F) -> Result where F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>, diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 05b409f..855dc94 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -1,5 +1,11 @@ -use crate::{error::SwResultExt, util, Rect, SoftBufferError}; -use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; +use crate::{ + error::{InitError, SwResultExt}, + util, Rect, SoftBufferError, +}; +use raw_window_handle::{ + HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, + RawWindowHandle, +}; use std::{ cell::RefCell, num::{NonZeroI32, NonZeroU32}, @@ -17,17 +23,31 @@ use buffer::WaylandBuffer; struct State; -pub struct WaylandDisplayImpl { - conn: Connection, +pub struct WaylandDisplayImpl { + conn: Option, event_queue: RefCell>, qh: QueueHandle, shm: wl_shm::WlShm, + + /// The object that owns the display handle. + /// + /// This has to be dropped *after* the `conn` field, because the `conn` field implicitly borrows + /// this. + _display: D, } -impl WaylandDisplayImpl { - pub unsafe fn new(display_handle: WaylandDisplayHandle) -> Result { - // SAFETY: Ensured by user - let backend = unsafe { Backend::from_foreign_display(display_handle.display as *mut _) }; +impl WaylandDisplayImpl { + pub(crate) fn new(display: D) -> Result> + where + D: Sized, + { + let raw = display.display_handle()?.raw_display_handle()?; + let wayland_handle = match raw { + RawDisplayHandle::Wayland(w) => w.display, + _ => return Err(InitError::Unsupported(display)), + }; + + let backend = unsafe { Backend::from_foreign_display(wayland_handle.cast()) }; let conn = Connection::from_backend(backend); let (globals, event_queue) = registry_queue_init(&conn).swbuf_err("Failed to make round trip to server")?; @@ -36,41 +56,60 @@ impl WaylandDisplayImpl { .bind(&qh, 1..=1, ()) .swbuf_err("Failed to instantiate Wayland Shm")?; Ok(Self { - conn, + conn: Some(conn), event_queue: RefCell::new(event_queue), qh, shm, + _display: display, }) } + + fn conn(&self) -> &Connection { + self.conn.as_ref().unwrap() + } +} + +impl Drop for WaylandDisplayImpl { + fn drop(&mut self) { + // Make sure the connection is dropped first. + self.conn = None; + } } -pub struct WaylandImpl { - display: Rc, - surface: wl_surface::WlSurface, +pub struct WaylandImpl { + display: Rc>, + surface: Option, buffers: Option<(WaylandBuffer, WaylandBuffer)>, size: Option<(NonZeroI32, NonZeroI32)>, + + /// The pointer to the window object. + /// + /// This has to be dropped *after* the `surface` field, because the `surface` field implicitly + /// borrows this. + _window: W, } -impl WaylandImpl { - pub unsafe fn new( - window_handle: WaylandWindowHandle, - display: Rc, - ) -> Result { - // SAFETY: Ensured by user +impl WaylandImpl { + pub(crate) fn new(window: W, display: Rc>) -> Result> { + // Get the raw Wayland window. + let raw = window.window_handle()?.raw_window_handle()?; + 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(), - window_handle.surface as _, - ) + ObjectId::from_ptr(wl_surface::WlSurface::interface(), wayland_handle.cast()) } .swbuf_err("Failed to create proxy for surface ID.")?; - let surface = wl_surface::WlSurface::from_id(&display.conn, 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, + surface: Some(surface), buffers: Default::default(), size: None, + _window: window, }) } @@ -86,7 +125,7 @@ impl WaylandImpl { Ok(()) } - pub fn buffer_mut(&mut self) -> Result { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { let (width, height) = self .size .expect("Must set size of surface before calling `buffer_mut()`"); @@ -155,13 +194,13 @@ impl WaylandImpl { // Swap front and back buffer std::mem::swap(front, back); - front.attach(&self.surface); + 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); + 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. @@ -174,25 +213,36 @@ impl WaylandImpl { )) })() .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; - self.surface.damage_buffer(x, y, width, height); + self.surface().damage_buffer(x, y, width, height); } } - self.surface.commit(); + 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 { + fn drop(&mut self) { + // Make sure the surface is dropped first. + self.surface = None; + } } -pub struct BufferImpl<'a> { - stack: util::BorrowStack<'a, WaylandImpl, [u32]>, +pub struct BufferImpl<'a, D: ?Sized, W> { + stack: util::BorrowStack<'a, WaylandImpl, [u32]>, age: u8, } -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { self.stack.member() diff --git a/src/web.rs b/src/web.rs index eaf4da9..6ea71d8 100644 --- a/src/web.rs +++ b/src/web.rs @@ -7,34 +7,50 @@ use std::marker::PhantomData; use std::num::NonZeroU32; use js_sys::Object; -use raw_window_handle::WebWindowHandle; +use raw_window_handle::{ + HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, + RawWindowHandle, +}; use wasm_bindgen::{JsCast, JsValue}; use web_sys::ImageData; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d}; -use crate::error::SwResultExt; -use crate::{util, Rect, SoftBufferError}; +use crate::error::{InitError, SwResultExt}; +use crate::{util, NoDisplayHandle, NoWindowHandle, Rect, SoftBufferError}; +use std::convert::TryInto; +use std::marker::PhantomData; +use std::num::NonZeroU32; /// Display implementation for the web platform. /// /// This just caches the document to prevent having to query it every time. -pub struct WebDisplayImpl { +pub struct WebDisplayImpl { document: web_sys::Document, + _display: D, } -impl WebDisplayImpl { - pub(super) fn new() -> Result { +impl WebDisplayImpl { + pub(super) fn new(display: D) -> Result> { + let raw = display.display_handle()?.raw_display_handle()?; + match raw { + RawDisplayHandle::Web(..) => {} + _ => return Err(InitError::Unsupported(display)), + } + let document = web_sys::window() .swbuf_err("`Window` is not present in this runtime")? .document() .swbuf_err("`Document` is not present in this runtime")?; - Ok(Self { document }) + Ok(Self { + document, + _display: display, + }) } } -pub struct WebImpl { +pub struct WebImpl { /// The handle and context to the canvas that we're drawing to. canvas: Canvas, @@ -46,6 +62,12 @@ pub struct WebImpl { /// The current canvas width/height. size: Option<(NonZeroU32, NonZeroU32)>, + + /// The underlying window handle. + _window: W, + + /// The underlying display handle. + _display: PhantomData, } /// Holding canvas and context for [`HtmlCanvasElement`] or [`OffscreenCanvas`], @@ -61,8 +83,13 @@ enum Canvas { }, } -impl WebImpl { - pub fn new(display: &WebDisplayImpl, handle: WebWindowHandle) -> Result { +impl WebImpl { + pub(crate) fn new(display: &WebDisplayImpl, window: W) -> Result> { + let raw = window.window_handle()?.raw_window_handle()?; + let handle = match raw { + RawWindowHandle::Web(handle) => handle, + _ => return Err(InitError::Unsupported(window)), + }; let canvas: HtmlCanvasElement = display .document .query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id)) @@ -72,10 +99,10 @@ impl WebImpl { // We already made sure this was a canvas in `querySelector`. .unchecked_into(); - Self::from_canvas(canvas) + Self::from_canvas(canvas, window).map_err(InitError::Failure) } - fn from_canvas(canvas: HtmlCanvasElement) -> Result { + fn from_canvas(canvas: HtmlCanvasElement, window: W) -> Result { let ctx = Self::resolve_ctx(canvas.get_context("2d").ok(), "CanvasRenderingContext2d")?; Ok(Self { @@ -83,10 +110,12 @@ impl WebImpl { buffer: Vec::new(), buffer_presented: false, size: None, + _window: window, + _display: PhantomData, }) } - fn from_offscreen_canvas(canvas: OffscreenCanvas) -> Result { + fn from_offscreen_canvas(canvas: OffscreenCanvas, window: W) -> Result { let ctx = Self::resolve_ctx( canvas.get_context("2d").ok(), "OffscreenCanvasRenderingContext2d", @@ -97,6 +126,8 @@ impl WebImpl { buffer: Vec::new(), buffer_presented: false, size: None, + _window: window, + _display: PhantomData, }) } @@ -134,7 +165,7 @@ impl WebImpl { } /// Get a pointer to the mutable buffer. - pub(crate) fn buffer_mut(&mut self) -> Result { + pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { Ok(BufferImpl { imp: self }) } @@ -258,9 +289,9 @@ pub trait SurfaceExtWeb: Sized { fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result; } -impl SurfaceExtWeb for crate::Surface { +impl SurfaceExtWeb for crate::Surface { fn from_canvas(canvas: HtmlCanvasElement) -> Result { - let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas)?); + let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas, NoWindowHandle(()))?); Ok(Self { surface_impl: Box::new(imple), @@ -269,7 +300,10 @@ impl SurfaceExtWeb for crate::Surface { } fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result { - let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas(offscreen_canvas)?); + let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas( + offscreen_canvas, + NoWindowHandle(()), + )?); Ok(Self { surface_impl: Box::new(imple), @@ -326,11 +360,11 @@ impl Canvas { } } -pub struct BufferImpl<'a> { - imp: &'a mut WebImpl, +pub struct BufferImpl<'a, D, W> { + imp: &'a mut WebImpl, } -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { pub fn pixels(&self) -> &[u32] { &self.imp.buffer } diff --git a/src/win32.rs b/src/win32.rs index 6559e36..13b1e6e 100644 --- a/src/win32.rs +++ b/src/win32.rs @@ -3,9 +3,10 @@ //! This module converts the input buffer into a bitmap and then stretches it to the window. use crate::{Rect, SoftBufferError}; -use raw_window_handle::Win32WindowHandle; +use raw_window_handle::{HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawWindowHandle}; use std::io; +use std::marker::PhantomData; use std::mem; use std::num::{NonZeroI32, NonZeroU32}; use std::ptr::{self, NonNull}; @@ -128,7 +129,7 @@ impl Buffer { } /// The handle to a window for software buffering. -pub struct Win32Impl { +pub struct Win32Impl { /// The window handle. window: HWND, @@ -137,6 +138,16 @@ pub struct Win32Impl { /// The buffer used to hold the image. buffer: Option, + + /// The handle for the window. + /// + /// This should be kept alive in order to keep `window` valid. + _window: W, + + /// The display handle. + /// + /// We don't use this, but other code might. + _display: PhantomData, } /// The Win32-compatible bitmap information. @@ -146,16 +157,18 @@ struct BitmapInfo { bmi_colors: [Gdi::RGBQUAD; 3], } -impl Win32Impl { +impl Win32Impl { /// Create a new `Win32Impl` from a `Win32WindowHandle`. - /// - /// # Safety - /// - /// The `Win32WindowHandle` must be a valid window handle. - pub unsafe fn new(handle: &Win32WindowHandle) -> Result { + pub(crate) fn new(window: W) -> Result> { + let raw = window.window_handle()?.raw_window_handle()?; + let handle = match raw { + RawWindowHandle::Win32(handle) => handle, + _ => return Err(crate::InitError::Unsupported(window)), + }; + // It is valid for the window handle to be null here. Error out if it is. if handle.hwnd.is_null() { - return Err(SoftBufferError::IncompleteWindowHandle); + return Err(SoftBufferError::IncompleteWindowHandle.into()); } // Get the handle to the device context. @@ -168,13 +181,16 @@ impl Win32Impl { return Err(SoftBufferError::PlatformError( Some("Device Context is null".into()), Some(Box::new(io::Error::last_os_error())), - )); + ) + .into()); } Ok(Self { dc, window: hwnd, buffer: None, + _window: window, + _display: PhantomData, }) } @@ -197,7 +213,7 @@ impl Win32Impl { Ok(()) } - pub fn buffer_mut(&mut self) -> Result { + pub fn buffer_mut(&mut self) -> Result, SoftBufferError> { if self.buffer.is_none() { panic!("Must set size of surface before calling `buffer_mut()`"); } @@ -235,9 +251,9 @@ impl Win32Impl { } } -pub struct BufferImpl<'a>(&'a mut Win32Impl); +pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl); -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { self.0.buffer.as_ref().unwrap().pixels() diff --git a/src/x11.rs b/src/x11.rs index ef74758..0a6defb 100644 --- a/src/x11.rs +++ b/src/x11.rs @@ -5,10 +5,11 @@ #![allow(clippy::uninlined_format_args)] -use crate::error::SwResultExt; +use crate::error::{InitError, SwResultExt}; use crate::{Rect, SoftBufferError}; use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle}; use rustix::{fd, mm, shm as posix_shm}; + use std::{ fmt, fs::File, @@ -27,57 +28,63 @@ use x11rb::protocol::shm::{self, ConnectionExt as _}; use x11rb::protocol::xproto::{self, ConnectionExt as _}; use x11rb::xcb_ffi::XCBConnection; -pub struct X11DisplayImpl { +pub struct X11DisplayImpl { /// The handle to the XCB connection. - connection: XCBConnection, + connection: Option, /// SHM extension is available. is_shm_available: bool, + + /// The generic display where the `connection` field comes from. + /// + /// Without `&mut`, the underlying connection cannot be closed without other unsafe behavior. + /// With `&mut`, the connection can be dropped without us knowing about it. Therefore, we + /// cannot provide `&mut` access to this field. + _display: D, } -impl X11DisplayImpl { - pub(crate) unsafe fn from_xlib( - display_handle: XlibDisplayHandle, - ) -> Result { - // Validate the display handle to ensure we can use it. - if display_handle.display.is_null() { - return Err(SoftBufferError::IncompleteDisplayHandle); - } +impl X11DisplayImpl { + /// Create a new `X11DisplayImpl`. + pub(crate) fn new(display: D) -> Result> + where + D: Sized, + { + // Get the underlying libxcb handle. + let raw = display.display_handle()?.raw_display_handle()?; + let xcb_handle = match raw { + RawDisplayHandle::Xcb(xcb_handle) => xcb_handle, + RawDisplayHandle::Xlib(xlib) => { + // Convert to an XCB handle. + if xlib.display.is_null() { + return Err(SoftBufferError::IncompleteDisplayHandle.into()); + } - // Get the underlying XCB connection. - // SAFETY: The user has asserted that the display handle is valid. - let connection = unsafe { - let display = tiny_xlib::Display::from_ptr(display_handle.display); - display.as_raw_xcb_connection() + // Get the underlying XCB connection. + // SAFETY: The user has asserted that the display handle is valid. + let connection = unsafe { + let display = tiny_xlib::Display::from_ptr(xlib.display); + display.as_raw_xcb_connection() + }; + + // Construct the equivalent XCB display and window handles. + let mut xcb_display_handle = XcbDisplayHandle::empty(); + xcb_display_handle.connection = connection.cast(); + xcb_display_handle.screen = xlib.screen; + xcb_display_handle + } + _ => return Err(InitError::Unsupported(display)), }; - // Construct the equivalent XCB display and window handles. - let mut xcb_display_handle = XcbDisplayHandle::empty(); - xcb_display_handle.connection = connection.cast(); - xcb_display_handle.screen = display_handle.screen; - - // SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles. - unsafe { Self::from_xcb(xcb_display_handle) } - } - - /// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`. - /// - /// # Safety - /// - /// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid. - pub(crate) unsafe fn from_xcb( - display_handle: XcbDisplayHandle, - ) -> Result { - // Check that the handle is valid. - if display_handle.connection.is_null() { - return Err(SoftBufferError::IncompleteDisplayHandle); + // Validate the display handle to ensure we can use it. + if xcb_handle.connection.is_null() { + return Err(SoftBufferError::IncompleteDisplayHandle.into()); } // Wrap the display handle in an x11rb connection. // SAFETY: We don't own the connection, so don't drop it. We also assert that the connection is valid. let connection = { let result = - unsafe { XCBConnection::from_raw_xcb_connection(display_handle.connection, false) }; + unsafe { XCBConnection::from_raw_xcb_connection(xcb_handle.connection, false) }; result.swbuf_err("Failed to wrap XCB connection")? }; @@ -88,16 +95,25 @@ impl X11DisplayImpl { } Ok(Self { - connection, + connection: Some(connection), is_shm_available, + _display: display, }) } } +impl X11DisplayImpl { + fn connection(&self) -> &XCBConnection { + self.connection + .as_ref() + .expect("X11DisplayImpl::connection() called after X11DisplayImpl::drop()") + } +} + /// The handle to an X11 drawing context. -pub struct X11Impl { +pub struct X11Impl { /// X display this window belongs to. - display: Rc, + display: Rc>, /// The window to draw to. window: xproto::Window, @@ -119,6 +135,9 @@ pub struct X11Impl { /// The current buffer width/height. size: Option<(NonZeroU16, NonZeroU16)>, + + /// Keep the window alive. + _window_handle: W, } /// The buffer that is being drawn to. @@ -149,38 +168,29 @@ struct ShmBuffer { done_processing: Option, } -impl X11Impl { - /// Create a new `X11Impl` from a `XlibWindowHandle` and `XlibDisplayHandle`. - /// - /// # Safety - /// - /// The `XlibWindowHandle` and `XlibDisplayHandle` must be valid. - pub unsafe fn from_xlib( - window_handle: XlibWindowHandle, - display: Rc, - ) -> Result { - let mut xcb_window_handle = XcbWindowHandle::empty(); - xcb_window_handle.window = window_handle.window as _; - xcb_window_handle.visual_id = window_handle.visual_id as _; - - // SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles. - unsafe { Self::from_xcb(xcb_window_handle, display) } - } +impl X11Impl { + /// Create a new `X11Impl` from a `HasWindowHandle`. + pub(crate) fn new(window_src: W, display: Rc>) -> Result> { + // Get the underlying raw window handle. + let raw = window_src.window_handle()?.raw_window_handle()?; + let window_handle = match raw { + RawWindowHandle::Xcb(xcb) => xcb, + RawWindowHandle::Xlib(xlib) => { + let mut xcb_window_handle = XcbWindowHandle::empty(); + xcb_window_handle.window = xlib.window as _; + xcb_window_handle.visual_id = xlib.visual_id as _; + xcb_window_handle + } + _ => { + return Err(InitError::Unsupported(window_src)); + } + }; - /// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`. - /// - /// # Safety - /// - /// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid. - pub(crate) unsafe fn from_xcb( - window_handle: XcbWindowHandle, - display: Rc, - ) -> Result { - log::trace!("new: window_handle={:X}", window_handle.window,); + log::trace!("new: window_handle={:X}", window_handle.window); // Check that the handle is valid. if window_handle.window == 0 { - return Err(SoftBufferError::IncompleteWindowHandle); + return Err(SoftBufferError::IncompleteWindowHandle.into()); } let window = window_handle.window; @@ -189,13 +199,13 @@ impl X11Impl { let display2 = display.clone(); let tokens = { let geometry_token = display2 - .connection + .connection() .get_geometry(window) .swbuf_err("Failed to send geometry request")?; let window_attrs_token = if window_handle.visual_id == 0 { Some( display2 - .connection + .connection() .get_window_attributes(window) .swbuf_err("Failed to send window attributes request")?, ) @@ -208,11 +218,11 @@ impl X11Impl { // Create a new graphics context to draw to. let gc = display - .connection + .connection() .generate_id() .swbuf_err("Failed to generate GC ID")?; display - .connection + .connection() .create_gc( gc, window, @@ -262,6 +272,7 @@ impl X11Impl { buffer, buffer_presented: false, size: None, + _window_handle: window_src, }) } @@ -290,7 +301,7 @@ impl X11Impl { if self.size != Some((width, height)) { self.buffer_presented = false; self.buffer - .resize(&self.display.connection, width.get(), height.get()) + .resize(self.display.connection(), width.get(), height.get()) .swbuf_err("Failed to resize X11 buffer")?; // We successfully resized the buffer. @@ -301,11 +312,11 @@ impl X11Impl { } /// Get a mutable reference to the buffer. - pub(crate) fn buffer_mut(&mut self) -> Result { + pub(crate) 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. - self.buffer.finish_wait(&self.display.connection)?; + self.buffer.finish_wait(self.display.connection())?; // We can now safely call `buffer_mut` on the buffer. Ok(BufferImpl(self)) @@ -322,7 +333,7 @@ impl X11Impl { // TODO: Is it worth it to do SHM here? Probably not. let reply = self .display - .connection + .connection() .get_image( xproto::ImageFormat::Z_PIXMAP, self.window, @@ -349,9 +360,9 @@ impl X11Impl { } } -pub struct BufferImpl<'a>(&'a mut X11Impl); +pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl); -impl<'a> BufferImpl<'a> { +impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<'a, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { // SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`. @@ -388,7 +399,7 @@ impl<'a> BufferImpl<'a> { log::debug!("Falling back to non-SHM method for window drawing."); imp.display - .connection + .connection() .put_image( xproto::ImageFormat::Z_PIXMAP, imp.window, @@ -427,7 +438,7 @@ impl<'a> BufferImpl<'a> { ) .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; imp.display - .connection + .connection() .shm_put_image( imp.window, imp.gc, @@ -451,7 +462,7 @@ impl<'a> BufferImpl<'a> { }) .and_then(|()| { // Send a short request to act as a notification for when the X server is done processing the image. - shm.begin_wait(&imp.display.connection) + shm.begin_wait(imp.display.connection()) .swbuf_err("Failed to draw image to window") })?; } @@ -743,15 +754,22 @@ impl Drop for ShmSegment { } } -impl Drop for X11Impl { +impl Drop for X11DisplayImpl { + fn drop(&mut self) { + // Make sure that the x11rb connection is dropped before its source is. + self.connection = None; + } +} + +impl Drop for X11Impl { fn drop(&mut self) { // If we used SHM, make sure it's detached from the server. if let Buffer::Shm(mut shm) = mem::replace(&mut self.buffer, Buffer::Wire(Vec::new())) { // If we were in the middle of processing a buffer, wait for it to finish. - shm.finish_wait(&self.display.connection).ok(); + shm.finish_wait(self.display.connection()).ok(); if let Some((segment, seg_id)) = shm.seg.take() { - if let Ok(token) = self.display.connection.shm_detach(seg_id) { + if let Ok(token) = self.display.connection().shm_detach(seg_id) { token.ignore_error(); } @@ -761,7 +779,7 @@ impl Drop for X11Impl { } // Close the graphics context that we created. - if let Ok(token) = self.display.connection.free_gc(self.gc) { + if let Ok(token) = self.display.connection().free_gc(self.gc) { token.ignore_error(); } } diff --git a/tests/present_and_fetch.rs b/tests/present_and_fetch.rs index 2bf7ded..9e87c04 100644 --- a/tests/present_and_fetch.rs +++ b/tests/present_and_fetch.rs @@ -1,3 +1,5 @@ +// TODO: Once winit is updated again, restore this test. +/* use softbuffer::{Context, Surface}; use std::num::NonZeroU32; use winit::event_loop::EventLoopWindowTarget; @@ -26,8 +28,8 @@ fn all_red(elwt: &EventLoopWindowTarget<()>) { #[cfg(not(target_arch = "wasm32"))] std::thread::sleep(std::time::Duration::from_millis(1)); - let context = unsafe { Context::new(elwt) }.unwrap(); - let mut surface = unsafe { Surface::new(&context, &window) }.unwrap(); + let context = Context::new(elwt).unwrap(); + let mut surface = Surface::new(&context, &window).unwrap(); let size = window.inner_size(); // Set the size of the surface to the size of the window. @@ -54,3 +56,6 @@ fn all_red(elwt: &EventLoopWindowTarget<()>) { } winit_test::main!(all_red); +*/ + +fn main() {} From 1f44e3ab5ad7af2988b8aebc381e46d10de711b5 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sat, 21 Oct 2023 22:38:48 -0700 Subject: [PATCH 2/6] Update for newest changes Signed-off-by: John Nunley --- Cargo.toml | 3 -- src/cg.rs | 9 +++-- src/kms.rs | 87 +++++++++++++++++++++++++--------------------- src/lib.rs | 24 ++++++------- src/orbital.rs | 8 ++--- src/wayland/mod.rs | 16 ++++----- src/web.rs | 13 ++----- src/win32.rs | 11 ++---- src/x11.rs | 55 ++++++++++++++--------------- 9 files changed, 105 insertions(+), 121 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b0ad381..892dfd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,6 +120,3 @@ targets = [ "wasm32-unknown-unknown", ] -[patch.crates-io] -raw_window_handle = { package = "raw-window-handle", git = "https://github.com/rust-windowing/raw-window-handle.git", branch = "notgull/next" } -winit = { git = "https://github.com/forkgull/winit.git", branch = "rwh-0.6" } diff --git a/src/cg.rs b/src/cg.rs index 4ebb458..97cc913 100644 --- a/src/cg.rs +++ b/src/cg.rs @@ -6,7 +6,7 @@ use core_graphics::base::{ use core_graphics::color_space::CGColorSpace; use core_graphics::data_provider::CGDataProvider; use core_graphics::image::CGImage; -use raw_window_handle::{HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawWindowHandle}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow}; use cocoa::base::{id, nil}; @@ -36,14 +36,13 @@ pub struct CGImpl { impl CGImpl { pub(crate) fn new(window_src: W) -> Result> { - let raw = window_src.window_handle()?.raw_window_handle()?; + let raw = window_src.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::AppKit(handle) => handle, _ => return Err(InitError::Unsupported(window_src)), }; - let window = handle.ns_window as id; - let window: id = unsafe { msg_send![window, retain] }; - let view = handle.ns_view as id; + let view = handle.ns_view.as_ptr() as id; + let window = unsafe { msg_send![view, window] }; let layer = CALayer::new(); unsafe { let subview: id = NSView::alloc(nil).initWithFrame_(NSView::frame(view)); diff --git a/src/kms.rs b/src/kms.rs index aa7ebb5..bcbdfff 100644 --- a/src/kms.rs +++ b/src/kms.rs @@ -9,54 +9,59 @@ use drm::control::{ }; use drm::Device; -use raw_window_handle::{DrmDisplayHandle, DrmWindowHandle}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use std::collections::HashSet; +use std::marker::PhantomData; use std::num::NonZeroU32; use std::os::unix::io::{AsFd, BorrowedFd}; use std::rc::Rc; -use crate::error::{SoftBufferError, SwResultExt}; +use crate::error::{InitError, SoftBufferError, SwResultExt}; #[derive(Debug)] -pub(crate) struct KmsDisplayImpl { +pub(crate) struct KmsDisplayImpl { /// The underlying raw device file descriptor. - /// - /// Once rwh v0.6 support is merged, this an be made safe. Until then, - /// we use this hacky workaround, since this FD's validity is guaranteed by - /// the unsafe constructor. fd: BorrowedFd<'static>, + + /// Holds a reference to the display. + _display: D, } -impl AsFd for KmsDisplayImpl { +impl AsFd for KmsDisplayImpl { fn as_fd(&self) -> BorrowedFd<'_> { self.fd } } -impl Device for KmsDisplayImpl {} -impl CtrlDevice for KmsDisplayImpl {} +impl Device for KmsDisplayImpl {} +impl CtrlDevice for KmsDisplayImpl {} -impl KmsDisplayImpl { - /// SAFETY: The underlying fd must not outlive the display. - pub(crate) unsafe fn new(handle: DrmDisplayHandle) -> Result { - let fd = handle.fd; +impl KmsDisplayImpl { + pub(crate) fn new(display: D) -> Result> { + let fd = match display.display_handle()?.as_raw() { + RawDisplayHandle::Drm(drm) => drm.fd, + _ => return Err(InitError::Unsupported(display)), + }; if fd == -1 { - return Err(SoftBufferError::IncompleteDisplayHandle); + return Err(SoftBufferError::IncompleteDisplayHandle.into()); } // SAFETY: Invariants guaranteed by the user. let fd = unsafe { BorrowedFd::borrow_raw(fd) }; - Ok(KmsDisplayImpl { fd }) + Ok(KmsDisplayImpl { + fd, + _display: display, + }) } } /// All the necessary types for the Drm/Kms backend. #[derive(Debug)] -pub(crate) struct KmsImpl { +pub(crate) struct KmsImpl { /// The display implementation. - display: Rc, + display: Rc>, /// The connectors to use. connectors: Vec, @@ -66,6 +71,9 @@ pub(crate) struct KmsImpl { /// The dumb buffer we're using as a buffer. buffer: Option, + + /// Window handle that we are keeping around. + _window: W, } #[derive(Debug)] @@ -81,7 +89,7 @@ struct Buffers { } /// The buffer implementation. -pub(crate) struct BufferImpl<'a> { +pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> { /// The mapping of the dump buffer. mapping: DumbMapping<'a>, @@ -101,13 +109,16 @@ pub(crate) struct BufferImpl<'a> { size: (NonZeroU32, NonZeroU32), /// The display implementation. - display: &'a KmsDisplayImpl, + display: &'a KmsDisplayImpl, /// Age of the front buffer. front_age: &'a mut u8, /// Age of the back buffer. back_age: &'a mut u8, + + /// Window reference. + _window: PhantomData<&'a mut W>, } /// The combined frame buffer and dumb buffer. @@ -123,22 +134,16 @@ struct SharedBuffer { age: u8, } -impl KmsImpl { +impl KmsImpl { /// Create a new KMS backend. - /// - /// # Safety - /// - /// The plane must be valid for the lifetime of the backend. - pub(crate) unsafe fn new( - window_handle: DrmWindowHandle, - display: Rc, - ) -> Result { - log::trace!("new: window_handle={:X}", window_handle.plane); - + pub(crate) fn new(window: W, display: Rc>) -> Result> { // Make sure that the window handle is valid. - let plane_handle = match NonZeroU32::new(window_handle.plane) { - Some(handle) => plane::Handle::from(handle), - None => return Err(SoftBufferError::IncompleteWindowHandle), + let plane_handle = match window.window_handle()?.as_raw() { + RawWindowHandle::Drm(drm) => match NonZeroU32::new(drm.plane) { + Some(handle) => plane::Handle::from(handle), + None => return Err(SoftBufferError::IncompleteWindowHandle.into()), + }, + _ => return Err(InitError::Unsupported(window)), }; let plane_info = display @@ -195,6 +200,7 @@ impl KmsImpl { connectors, display, buffer: None, + _window: window, }) } @@ -232,7 +238,7 @@ impl KmsImpl { } /// Get a mutable reference to the buffer. - pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { + pub(crate) fn buffer_mut(&mut self) -> Result, SoftBufferError> { // Map the dumb buffer. let set = self .buffer @@ -267,11 +273,12 @@ impl KmsImpl { zeroes: &set.zeroes, front_age, back_age, + _window: PhantomData, }) } } -impl Drop for KmsImpl { +impl Drop for KmsImpl { fn drop(&mut self) { // Map the CRTC to the information that was there before. self.display @@ -286,7 +293,7 @@ impl Drop for KmsImpl { } } -impl BufferImpl<'_> { +impl BufferImpl<'_, D, W> { #[inline] pub fn pixels(&self) -> &[u32] { // drm-rs doesn't let us have the immutable reference... so just use a bunch of zeroes. @@ -310,7 +317,7 @@ impl BufferImpl<'_> { .iter() .map(|&rect| { let err = || SoftBufferError::DamageOutOfRange { rect }; - Ok(ClipRect::new( + Ok::<_, SoftBufferError>(ClipRect::new( rect.x.try_into().map_err(|_| err())?, rect.y.try_into().map_err(|_| err())?, rect.x @@ -375,8 +382,8 @@ impl BufferImpl<'_> { impl SharedBuffer { /// Create a new buffer set. - pub(crate) fn new( - display: &KmsDisplayImpl, + pub(crate) fn new( + display: &KmsDisplayImpl, width: NonZeroU32, height: NonZeroU32, ) -> Result { diff --git a/src/lib.rs b/src/lib.rs index 152d41e..798fa96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,10 +35,7 @@ use std::rc::Rc; use error::InitError; pub use error::SoftBufferError; -use raw_window_handle::{ - HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, - RawWindowHandle, -}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; #[cfg(target_arch = "wasm32")] pub use self::web::SurfaceExtWeb; @@ -184,7 +181,7 @@ make_dispatch! { #[cfg(wayland_platform)] Wayland(Rc>, wayland::WaylandImpl, wayland::BufferImpl<'a, D, W>), #[cfg(kms_platform)] - Kms(Rc, kms::KmsImpl, kms::BufferImpl<'a>), + 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")] @@ -213,18 +210,13 @@ impl Context { } }}; } - } - /// Creates a new instance of this struct, using the provided display handles - /// - /// # Safety - /// - /// - Ensure that the provided handle is valid for the lifetime of the Context - pub unsafe fn from_raw(raw_display_handle: RawDisplayHandle) -> Result { #[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")] @@ -234,7 +226,7 @@ impl Context { #[cfg(target_os = "redox")] try_init!(Orbital, display => Ok(display)); - let raw = dpy.display_handle()?.raw_display_handle()?; + let raw = dpy.display_handle()?.as_raw(); Err(SoftBufferError::UnsupportedDisplayPlatform { human_readable_display_platform_name: display_handle_type_name(&raw), display_handle: raw, @@ -270,7 +262,7 @@ impl Surface { match ($e) { Ok(x) => x, Err(InitError::Unsupported(window)) => { - let raw = window.window_handle()?.raw_window_handle()?; + 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 @@ -293,6 +285,10 @@ impl Surface { 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))) diff --git a/src/orbital.rs b/src/orbital.rs index f934889..3495b89 100644 --- a/src/orbital.rs +++ b/src/orbital.rs @@ -1,7 +1,5 @@ use crate::error::InitError; -use raw_window_handle::{ - HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle, -}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle}; use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str}; use crate::{Rect, SoftBufferError}; @@ -67,7 +65,7 @@ pub struct OrbitalImpl { impl OrbitalImpl { pub(crate) fn new(window: W) -> Result> { - let raw = window.window_handle()?.raw_window_handle()?; + let raw = window.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::Orbital(handle) => handle, _ => return Err(InitError::Unsupported(window)), @@ -95,7 +93,7 @@ impl OrbitalImpl { } fn window_fd(&self) -> usize { - self.handle.window as usize + self.handle.window.as_ptr() as usize } // Read the current width and size diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 855dc94..762202d 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -2,10 +2,7 @@ use crate::{ error::{InitError, SwResultExt}, util, Rect, SoftBufferError, }; -use raw_window_handle::{ - HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, - RawWindowHandle, -}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use std::{ cell::RefCell, num::{NonZeroI32, NonZeroU32}, @@ -41,13 +38,13 @@ impl WaylandDisplayImpl { where D: Sized, { - let raw = display.display_handle()?.raw_display_handle()?; + let raw = display.display_handle()?.as_raw(); let wayland_handle = match raw { RawDisplayHandle::Wayland(w) => w.display, _ => return Err(InitError::Unsupported(display)), }; - let backend = unsafe { Backend::from_foreign_display(wayland_handle.cast()) }; + let backend = unsafe { Backend::from_foreign_display(wayland_handle.as_ptr().cast()) }; let conn = Connection::from_backend(backend); let (globals, event_queue) = registry_queue_init(&conn).swbuf_err("Failed to make round trip to server")?; @@ -92,14 +89,17 @@ pub struct WaylandImpl { impl WaylandImpl { pub(crate) fn new(window: W, display: Rc>) -> Result> { // Get the raw Wayland window. - let raw = window.window_handle()?.raw_window_handle()?; + 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.cast()) + 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) diff --git a/src/web.rs b/src/web.rs index 6ea71d8..1caa71e 100644 --- a/src/web.rs +++ b/src/web.rs @@ -2,15 +2,8 @@ #![allow(clippy::uninlined_format_args)] -use std::convert::TryInto; -use std::marker::PhantomData; -use std::num::NonZeroU32; - use js_sys::Object; -use raw_window_handle::{ - HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, - RawWindowHandle, -}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use wasm_bindgen::{JsCast, JsValue}; use web_sys::ImageData; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; @@ -32,7 +25,7 @@ pub struct WebDisplayImpl { impl WebDisplayImpl { pub(super) fn new(display: D) -> Result> { - let raw = display.display_handle()?.raw_display_handle()?; + let raw = display.display_handle()?.as_raw(); match raw { RawDisplayHandle::Web(..) => {} _ => return Err(InitError::Unsupported(display)), @@ -85,7 +78,7 @@ enum Canvas { impl WebImpl { pub(crate) fn new(display: &WebDisplayImpl, window: W) -> Result> { - let raw = window.window_handle()?.raw_window_handle()?; + let raw = window.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::Web(handle) => handle, _ => return Err(InitError::Unsupported(window)), diff --git a/src/win32.rs b/src/win32.rs index 13b1e6e..a703aad 100644 --- a/src/win32.rs +++ b/src/win32.rs @@ -3,7 +3,7 @@ //! This module converts the input buffer into a bitmap and then stretches it to the window. use crate::{Rect, SoftBufferError}; -use raw_window_handle::{HasDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawWindowHandle}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use std::io; use std::marker::PhantomData; @@ -160,20 +160,15 @@ struct BitmapInfo { impl Win32Impl { /// Create a new `Win32Impl` from a `Win32WindowHandle`. pub(crate) fn new(window: W) -> Result> { - let raw = window.window_handle()?.raw_window_handle()?; + let raw = window.window_handle()?.as_raw(); let handle = match raw { RawWindowHandle::Win32(handle) => handle, _ => return Err(crate::InitError::Unsupported(window)), }; - // It is valid for the window handle to be null here. Error out if it is. - if handle.hwnd.is_null() { - return Err(SoftBufferError::IncompleteWindowHandle.into()); - } - // Get the handle to the device context. // SAFETY: We have confirmed that the window handle is valid. - let hwnd = handle.hwnd as HWND; + let hwnd = handle.hwnd.get() as HWND; let dc = unsafe { Gdi::GetDC(hwnd) }; // GetDC returns null if there is a platform error. diff --git a/src/x11.rs b/src/x11.rs index 0a6defb..7427e89 100644 --- a/src/x11.rs +++ b/src/x11.rs @@ -7,7 +7,10 @@ use crate::error::{InitError, SwResultExt}; use crate::{Rect, SoftBufferError}; -use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle}; +use raw_window_handle::{ + HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, + XcbWindowHandle, +}; use rustix::{fd, mm, shm as posix_shm}; use std::{ @@ -50,41 +53,40 @@ impl X11DisplayImpl { D: Sized, { // Get the underlying libxcb handle. - let raw = display.display_handle()?.raw_display_handle()?; + let raw = display.display_handle()?.as_raw(); let xcb_handle = match raw { RawDisplayHandle::Xcb(xcb_handle) => xcb_handle, RawDisplayHandle::Xlib(xlib) => { // Convert to an XCB handle. - if xlib.display.is_null() { - return Err(SoftBufferError::IncompleteDisplayHandle.into()); - } + let display = match xlib.display { + Some(display) => display, + None => return Err(SoftBufferError::IncompleteDisplayHandle.into()), + }; // Get the underlying XCB connection. // SAFETY: The user has asserted that the display handle is valid. let connection = unsafe { - let display = tiny_xlib::Display::from_ptr(xlib.display); - display.as_raw_xcb_connection() + let display = tiny_xlib::Display::from_ptr(display.as_ptr()); + NonNull::new_unchecked(display.as_raw_xcb_connection()) }; // Construct the equivalent XCB display and window handles. - let mut xcb_display_handle = XcbDisplayHandle::empty(); - xcb_display_handle.connection = connection.cast(); - xcb_display_handle.screen = xlib.screen; - xcb_display_handle + XcbDisplayHandle::new(Some(connection.cast()), xlib.screen) } _ => return Err(InitError::Unsupported(display)), }; // Validate the display handle to ensure we can use it. - if xcb_handle.connection.is_null() { - return Err(SoftBufferError::IncompleteDisplayHandle.into()); - } + let connection = match xcb_handle.connection { + Some(conn) => conn, + None => return Err(SoftBufferError::IncompleteDisplayHandle.into()), + }; // Wrap the display handle in an x11rb connection. // SAFETY: We don't own the connection, so don't drop it. We also assert that the connection is valid. let connection = { let result = - unsafe { XCBConnection::from_raw_xcb_connection(xcb_handle.connection, false) }; + unsafe { XCBConnection::from_raw_xcb_connection(connection.as_ptr(), false) }; result.swbuf_err("Failed to wrap XCB connection")? }; @@ -172,13 +174,16 @@ impl X11Impl { /// Create a new `X11Impl` from a `HasWindowHandle`. pub(crate) fn new(window_src: W, display: Rc>) -> Result> { // Get the underlying raw window handle. - let raw = window_src.window_handle()?.raw_window_handle()?; + let raw = window_src.window_handle()?.as_raw(); let window_handle = match raw { RawWindowHandle::Xcb(xcb) => xcb, RawWindowHandle::Xlib(xlib) => { - let mut xcb_window_handle = XcbWindowHandle::empty(); - xcb_window_handle.window = xlib.window as _; - xcb_window_handle.visual_id = xlib.visual_id as _; + let window = match NonZeroU32::new(xlib.window as u32) { + Some(window) => window, + None => return Err(SoftBufferError::IncompleteWindowHandle.into()), + }; + let mut xcb_window_handle = XcbWindowHandle::new(window); + xcb_window_handle.visual_id = NonZeroU32::new(xlib.visual_id as u32); xcb_window_handle } _ => { @@ -187,13 +192,7 @@ impl X11Impl { }; log::trace!("new: window_handle={:X}", window_handle.window); - - // Check that the handle is valid. - if window_handle.window == 0 { - return Err(SoftBufferError::IncompleteWindowHandle.into()); - } - - let window = window_handle.window; + let window = window_handle.window.get(); // Run in parallel: start getting the window depth and (if necessary) visual. let display2 = display.clone(); @@ -202,7 +201,7 @@ impl X11Impl { .connection() .get_geometry(window) .swbuf_err("Failed to send geometry request")?; - let window_attrs_token = if window_handle.visual_id == 0 { + let window_attrs_token = if window_handle.visual_id.is_none() { Some( display2 .connection() @@ -239,7 +238,7 @@ impl X11Impl { .reply() .swbuf_err("Failed to get geometry reply")?; let visual_id = match window_attrs_token { - None => window_handle.visual_id, + None => window_handle.visual_id.unwrap().get(), Some(window_attrs) => { window_attrs .reply() From 9974257f8df4641bebaf82075aa62d3a749752e2 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sat, 21 Oct 2023 22:41:03 -0700 Subject: [PATCH 3/6] Bump winit Signed-off-by: John Nunley --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 892dfd6..b7be7ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ cfg_aliases = "0.1.1" colorous = "1.0.12" criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } instant = "0.1.12" -winit = "0.29.0-beta.0" +winit = "0.29.2" winit-test = "0.1.0" [dev-dependencies.image] From dc25ddfa24a2edbefcffdc45acbc010447347b19 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sun, 22 Oct 2023 20:00:00 -0700 Subject: [PATCH 4/6] Fix examples Signed-off-by: John Nunley --- README.md | 14 +++++++------- examples/animation.rs | 17 ++++++++++------- examples/drm.rs | 21 +++++++++++---------- examples/fruit.rs | 15 +++++++++------ examples/libxcb.rs | 14 +++++++------- examples/rectangle.rs | 19 +++++++++++-------- examples/winit.rs | 15 +++++++++------ examples/winit_wrong_sized_buffer.rs | 15 +++++++++------ 8 files changed, 73 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 3bd2722..da9adb1 100644 --- a/README.md +++ b/README.md @@ -65,16 +65,16 @@ use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested } if window_id == window.id() => { let (width, height) = { let size = window.inner_size(); (size.width, size.height) @@ -97,17 +97,17 @@ fn main() { buffer[index as usize] = blue | (green << 8) | (red << 16); } - buffer.present().unwrap(); + buffer.present().unwrap(); } Event::WindowEvent { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } _ => {} } - }); + }).unwrap(); } ``` diff --git a/examples/animation.rs b/examples/animation.rs index 3a0a1d5..e798a03 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -9,7 +9,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] @@ -33,11 +33,14 @@ fn main() { let mut frames = pre_render_frames(0, 0); let start = Instant::now(); - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Poll); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { if let (Some(width), Some(height)) = { let size = window.inner_size(); (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) @@ -57,18 +60,18 @@ fn main() { buffer.present().unwrap(); } } - Event::MainEventsCleared => { + Event::AboutToWait => { window.request_redraw(); } Event::WindowEvent { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } _ => {} } - }); + }).unwrap(); } fn pre_render_frames(width: usize, height: usize) -> Vec> { diff --git a/examples/drm.rs b/examples/drm.rs index caf6d61..8e50125 100644 --- a/examples/drm.rs +++ b/examples/drm.rs @@ -5,7 +5,7 @@ mod imple { use drm::control::{connector, Device as CtrlDevice, Event, ModeTypeFlags, PlaneType}; use drm::Device; - use raw_window_handle::{DrmDisplayHandle, DrmWindowHandle}; + use raw_window_handle::{DisplayHandle, DrmDisplayHandle, DrmWindowHandle, WindowHandle}; use softbuffer::{Context, Surface}; use std::num::NonZeroU32; @@ -19,11 +19,10 @@ mod imple { // Create the softbuffer context. let context = unsafe { - Context::from_raw({ - let mut handle = DrmDisplayHandle::empty(); - handle.fd = device.as_fd().as_raw_fd(); + Context::new(DisplayHandle::borrow_raw({ + let handle = DrmDisplayHandle::new(device.as_fd().as_raw_fd()); handle.into() - }) + })) }?; // Get the DRM handles. @@ -93,11 +92,13 @@ mod imple { // Create the surface on top of this plane. // Note: This requires root on DRM/KMS. let mut surface = unsafe { - Surface::from_raw(&context, { - let mut handle = DrmWindowHandle::empty(); - handle.plane = (**plane).into(); - handle.into() - }) + Surface::new( + &context, + WindowHandle::borrow_raw({ + let handle = DrmWindowHandle::new((**plane).into()); + handle.into() + }), + ) }?; // Resize the surface. diff --git a/examples/fruit.rs b/examples/fruit.rs index 964c525..c190f02 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -9,7 +9,7 @@ fn main() { //see fruit.jpg.license for the license of fruit.jpg let fruit = image::load_from_memory(include_bytes!("fruit.jpg")).unwrap(); - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new( WindowBuilder::new() .with_inner_size(winit::dpi::PhysicalSize::new(fruit.width(), fruit.height())) @@ -34,11 +34,14 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + } if window_id == window.id() => { surface .resize( NonZeroU32::new(fruit.width()).unwrap(), @@ -63,9 +66,9 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } _ => {} } - }); + }).unwrap(); } diff --git a/examples/libxcb.rs b/examples/libxcb.rs index 83dfeaa..88ef5f2 100644 --- a/examples/libxcb.rs +++ b/examples/libxcb.rs @@ -6,7 +6,7 @@ mod example { DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, XcbDisplayHandle, XcbWindowHandle, }; - use std::num::NonZeroU32; + use std::{num::NonZeroU32, ptr::NonNull}; use x11rb::{ connection::Connection, protocol::{ @@ -23,9 +23,10 @@ mod example { let (conn, screen) = XCBConnection::connect(None).expect("Failed to connect to X server"); // x11rb doesn't use raw-window-handle yet, so just create our own. - let mut display_handle = XcbDisplayHandle::empty(); - display_handle.connection = conn.get_raw_xcb_connection() as *mut _; - display_handle.screen = screen as _; + let display_handle = XcbDisplayHandle::new( + NonNull::new(conn.get_raw_xcb_connection() as *mut _), + screen as _, + ); // Create a new window. let mut width = 640u16; @@ -53,9 +54,8 @@ mod example { .check() .unwrap(); - let mut window_handle = XcbWindowHandle::empty(); - window_handle.window = window as _; - window_handle.visual_id = root_visual as _; + let mut window_handle = XcbWindowHandle::new(NonZeroU32::new(window).unwrap()); + window_handle.visual_id = NonZeroU32::new(root_visual); // Create a new softbuffer context. // SAFETY: The display and window handles outlive the context. diff --git a/examples/rectangle.rs b/examples/rectangle.rs index d69e5dd..9af1656 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU32; use std::rc::Rc; use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; -use winit::keyboard::KeyCode; +use winit::keyboard::{PhysicalKey, KeyCode}; use winit::window::WindowBuilder; fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { @@ -22,7 +22,7 @@ fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { } fn main() { - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new( WindowBuilder::new() @@ -50,11 +50,14 @@ fn main() { let mut flag = false; - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { // Grab the window's client area dimensions if let (Some(width), Some(height)) = { let size = window.inner_size(); @@ -79,7 +82,7 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } Event::WindowEvent { @@ -88,7 +91,7 @@ fn main() { event: KeyEvent { state: ElementState::Pressed, - physical_key: KeyCode::Space, + physical_key: PhysicalKey::Code(KeyCode::Space), .. }, .. @@ -102,5 +105,5 @@ fn main() { _ => {} } - }); + }).unwrap(); } diff --git a/examples/winit.rs b/examples/winit.rs index 1c90191..3e49fa3 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -5,7 +5,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; fn main() { - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] @@ -25,11 +25,14 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { if let (Some(width), Some(height)) = { let size = window.inner_size(); (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) @@ -54,9 +57,9 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } _ => {} } - }); + }).unwrap(); } diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 21716d7..90930dc 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -8,7 +8,7 @@ const BUFFER_WIDTH: usize = 256; const BUFFER_HEIGHT: usize = 128; fn main() { - let event_loop = EventLoop::new(); + let event_loop = EventLoop::new().unwrap(); let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap()); #[cfg(target_arch = "wasm32")] @@ -28,11 +28,14 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; + event_loop.run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); match event { - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { surface .resize( NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(), @@ -57,9 +60,9 @@ fn main() { event: WindowEvent::CloseRequested, window_id, } if window_id == window.id() => { - *control_flow = ControlFlow::Exit; + elwt.exit(); } _ => {} } - }); + }).unwrap(); } From dffcb5bd48346374840091ee2d51a84dbe1c92fe Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sun, 22 Oct 2023 20:01:25 -0700 Subject: [PATCH 5/6] fmt Signed-off-by: John Nunley --- examples/animation.rs | 68 +++++++++--------- examples/fruit.rs | 66 ++++++++--------- examples/rectangle.rs | 104 ++++++++++++++------------- examples/winit.rs | 64 +++++++++-------- examples/winit_wrong_sized_buffer.rs | 64 +++++++++-------- 5 files changed, 188 insertions(+), 178 deletions(-) diff --git a/examples/animation.rs b/examples/animation.rs index e798a03..1e188f0 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -33,45 +33,47 @@ fn main() { let mut frames = pre_render_frames(0, 0); let start = Instant::now(); - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Poll); + event_loop + .run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Poll); - match event { - Event::WindowEvent { - window_id, - event: WindowEvent::RedrawRequested, - } if window_id == window.id() => { - if let (Some(width), Some(height)) = { - let size = window.inner_size(); - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - } { - let elapsed = start.elapsed().as_secs_f64() % 1.0; + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { + if let (Some(width), Some(height)) = { + let size = window.inner_size(); + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + let elapsed = start.elapsed().as_secs_f64() % 1.0; - if (width.get(), height.get()) != old_size { - old_size = (width.get(), height.get()); - frames = pre_render_frames(width.get() as usize, height.get() as usize); - }; + if (width.get(), height.get()) != old_size { + old_size = (width.get(), height.get()); + frames = pre_render_frames(width.get() as usize, height.get() as usize); + }; - let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; + let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; - surface.resize(width, height).unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - buffer.copy_from_slice(frame); - buffer.present().unwrap(); + surface.resize(width, height).unwrap(); + let mut buffer = surface.buffer_mut().unwrap(); + buffer.copy_from_slice(frame); + buffer.present().unwrap(); + } } + Event::AboutToWait => { + window.request_redraw(); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => { + elwt.exit(); + } + _ => {} } - Event::AboutToWait => { - window.request_redraw(); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => { - elwt.exit(); - } - _ => {} - } - }).unwrap(); + }) + .unwrap(); } fn pre_render_frames(width: usize, height: usize) -> Vec> { diff --git a/examples/fruit.rs b/examples/fruit.rs index c190f02..860d1bd 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -34,41 +34,43 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Wait); + event_loop + .run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); - match event { - Event::WindowEvent { - window_id, - event: WindowEvent::CloseRequested, - } if window_id == window.id() => { - surface - .resize( - NonZeroU32::new(fruit.width()).unwrap(), - NonZeroU32::new(fruit.height()).unwrap(), - ) - .unwrap(); + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + } if window_id == window.id() => { + surface + .resize( + NonZeroU32::new(fruit.width()).unwrap(), + NonZeroU32::new(fruit.height()).unwrap(), + ) + .unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - let width = fruit.width() as usize; - for (x, y, pixel) in fruit.pixels() { - let red = pixel.0[0] as u32; - let green = pixel.0[1] as u32; - let blue = pixel.0[2] as u32; + let mut buffer = surface.buffer_mut().unwrap(); + let width = fruit.width() as usize; + for (x, y, pixel) in fruit.pixels() { + let red = pixel.0[0] as u32; + let green = pixel.0[1] as u32; + let blue = pixel.0[2] as u32; - let color = blue | (green << 8) | (red << 16); - buffer[y as usize * width + x as usize] = color; - } + let color = blue | (green << 8) | (red << 16); + buffer[y as usize * width + x as usize] = color; + } - buffer.present().unwrap(); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => { - elwt.exit(); + buffer.present().unwrap(); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => { + elwt.exit(); + } + _ => {} } - _ => {} - } - }).unwrap(); + }) + .unwrap(); } diff --git a/examples/rectangle.rs b/examples/rectangle.rs index 9af1656..80e8ed4 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU32; use std::rc::Rc; use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; -use winit::keyboard::{PhysicalKey, KeyCode}; +use winit::keyboard::{KeyCode, PhysicalKey}; use winit::window::WindowBuilder; fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) { @@ -50,60 +50,62 @@ fn main() { let mut flag = false; - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Wait); + event_loop + .run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); - match event { - Event::WindowEvent { - window_id, - event: WindowEvent::RedrawRequested, - } if window_id == window.id() => { - // Grab the window's client area dimensions - if let (Some(width), Some(height)) = { - let size = window.inner_size(); - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - } { - // Resize surface if needed - surface.resize(width, height).unwrap(); + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { + // Grab the window's client area dimensions + if let (Some(width), Some(height)) = { + let size = window.inner_size(); + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + // Resize surface if needed + surface.resize(width, height).unwrap(); - // Draw something in the window - let mut buffer = surface.buffer_mut().unwrap(); - redraw( - &mut buffer, - width.get() as usize, - height.get() as usize, - flag, - ); - buffer.present().unwrap(); + // Draw something in the window + let mut buffer = surface.buffer_mut().unwrap(); + redraw( + &mut buffer, + width.get() as usize, + height.get() as usize, + flag, + ); + buffer.present().unwrap(); + } } - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => { - elwt.exit(); - } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => { + elwt.exit(); + } - Event::WindowEvent { - event: - WindowEvent::KeyboardInput { - event: - KeyEvent { - state: ElementState::Pressed, - physical_key: PhysicalKey::Code(KeyCode::Space), - .. - }, - .. - }, - window_id, - } if window_id == window.id() => { - // Flip the rectangle flag and request a redraw to show the changed image - flag = !flag; - window.request_redraw(); - } + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + event: + KeyEvent { + state: ElementState::Pressed, + physical_key: PhysicalKey::Code(KeyCode::Space), + .. + }, + .. + }, + window_id, + } if window_id == window.id() => { + // Flip the rectangle flag and request a redraw to show the changed image + flag = !flag; + window.request_redraw(); + } - _ => {} - } - }).unwrap(); + _ => {} + } + }) + .unwrap(); } diff --git a/examples/winit.rs b/examples/winit.rs index 3e49fa3..68b478f 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -25,41 +25,43 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Wait); + event_loop + .run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); - match event { - Event::WindowEvent { - window_id, - event: WindowEvent::RedrawRequested, - } if window_id == window.id() => { - if let (Some(width), Some(height)) = { - let size = window.inner_size(); - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - } { - surface.resize(width, height).unwrap(); + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { + if let (Some(width), Some(height)) = { + let size = window.inner_size(); + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + } { + surface.resize(width, height).unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..height.get() { - for x in 0..width.get() { - let red = x % 255; - let green = y % 255; - let blue = (x * y) % 255; - let index = y as usize * width.get() as usize + x as usize; - buffer[index] = blue | (green << 8) | (red << 16); + let mut buffer = surface.buffer_mut().unwrap(); + for y in 0..height.get() { + for x in 0..width.get() { + let red = x % 255; + let green = y % 255; + let blue = (x * y) % 255; + let index = y as usize * width.get() as usize + x as usize; + buffer[index] = blue | (green << 8) | (red << 16); + } } - } - buffer.present().unwrap(); + buffer.present().unwrap(); + } } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => { + elwt.exit(); + } + _ => {} } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => { - elwt.exit(); - } - _ => {} - } - }).unwrap(); + }) + .unwrap(); } diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 90930dc..3fe613e 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -28,41 +28,43 @@ fn main() { let context = softbuffer::Context::new(window.clone()).unwrap(); let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Wait); + event_loop + .run(move |event, elwt| { + elwt.set_control_flow(ControlFlow::Wait); - match event { - Event::WindowEvent { - window_id, - event: WindowEvent::RedrawRequested, - } if window_id == window.id() => { - surface - .resize( - NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(), - NonZeroU32::new(BUFFER_HEIGHT as u32).unwrap(), - ) - .unwrap(); + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + } if window_id == window.id() => { + surface + .resize( + NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(), + NonZeroU32::new(BUFFER_HEIGHT as u32).unwrap(), + ) + .unwrap(); - let mut buffer = surface.buffer_mut().unwrap(); - for y in 0..BUFFER_HEIGHT { - for x in 0..BUFFER_WIDTH { - let red = x as u32 % 255; - let green = y as u32 % 255; - let blue = (x as u32 * y as u32) % 255; + let mut buffer = surface.buffer_mut().unwrap(); + for y in 0..BUFFER_HEIGHT { + for x in 0..BUFFER_WIDTH { + let red = x as u32 % 255; + let green = y as u32 % 255; + let blue = (x as u32 * y as u32) % 255; - let color = blue | (green << 8) | (red << 16); - buffer[y * BUFFER_WIDTH + x] = color; + let color = blue | (green << 8) | (red << 16); + buffer[y * BUFFER_WIDTH + x] = color; + } } + buffer.present().unwrap(); } - buffer.present().unwrap(); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id, - } if window_id == window.id() => { - elwt.exit(); + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => { + elwt.exit(); + } + _ => {} } - _ => {} - } - }).unwrap(); + }) + .unwrap(); } From d803c2e026886886f3662659e69dbd6ae419c094 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Mon, 23 Oct 2023 12:10:35 -0700 Subject: [PATCH 6/6] Fix benchmark Signed-off-by: John Nunley --- benches/buffer_mut.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/benches/buffer_mut.rs b/benches/buffer_mut.rs index 0c1772b..b2a29cd 100644 --- a/benches/buffer_mut.rs +++ b/benches/buffer_mut.rs @@ -12,19 +12,20 @@ fn buffer_mut(c: &mut Criterion) { use criterion::black_box; use softbuffer::{Context, Surface}; use std::num::NonZeroU32; - use winit::platform::run_return::EventLoopExtRunReturn; + use winit::event_loop::ControlFlow; + use winit::platform::run_on_demand::EventLoopExtRunOnDemand; - let mut evl = winit::event_loop::EventLoop::new(); + let mut evl = winit::event_loop::EventLoop::new().unwrap(); let window = winit::window::WindowBuilder::new() .with_visible(false) .build(&evl) .unwrap(); - evl.run_return(move |ev, elwt, control_flow| { - control_flow.set_poll(); + evl.run_on_demand(move |ev, elwt| { + elwt.set_control_flow(ControlFlow::Poll); - if let winit::event::Event::RedrawEventsCleared = ev { - control_flow.set_exit(); + if let winit::event::Event::AboutToWait = ev { + elwt.exit(); let mut surface = { let context = Context::new(elwt).unwrap(); @@ -57,7 +58,8 @@ fn buffer_mut(c: &mut Criterion) { }); }); } - }); + }) + .unwrap(); } }