From 0a453fef15a856079e968b0d831bfac7d3d826a1 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Sun, 19 Mar 2023 23:35:45 -0700 Subject: [PATCH 1/7] feat: Use the safer API for window handles --- Cargo.toml | 9 +- examples/animation.rs | 13 ++- examples/fruit.rs | 22 +++-- examples/rectangle.rs | 17 ++-- examples/winit.rs | 9 +- examples/winit_wrong_sized_buffer.rs | 9 +- src/error.rs | 3 + src/lib.rs | 131 ++++++++++++++++++--------- 8 files changed, 145 insertions(+), 68 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4479781..8e526f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ x11 = ["bytemuck", "nix", "x11rb", "x11-dl"] [dependencies] log = "0.4.17" -raw-window-handle = "0.5.0" +raw-window-handle = { version = "0.5.0", features = ["alloc"] } thiserror = "1.0.30" [target.'cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))'.dependencies] @@ -77,3 +77,10 @@ rayon = "1.5.1" members = [ "run-wasm", ] + +[patch.crates-io] +raw-window-handle = { git = "https://github.com/notgull/raw-window-handle.git", branch = "notgull/impl-more", version = "0.5.1" } +winit = { git = "https://github.com/bread-graphics/winit.git", branch = "window-handle", version = "0.28.3" } + +[patch.'https://github.com/rust-windowing/raw-window-handle'] +raw-window-handle = { git = "https://github.com/notgull/raw-window-handle.git", branch = "notgull/impl-more", version = "0.5.1" } diff --git a/examples/animation.rs b/examples/animation.rs index 7fcc740..7d051d4 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -2,13 +2,14 @@ use instant::Instant; #[cfg(not(target_arch = "wasm32"))] use rayon::prelude::*; use std::f64::consts::PI; +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")] { @@ -24,8 +25,12 @@ fn main() { .unwrap(); } - let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); - let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); + let (context, mut surface) = { + let context = softbuffer::Context::new(window.clone()).unwrap(); + let surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); + + (context, surface) + }; let mut old_size = (0, 0); let mut frames = pre_render_frames(0, 0); @@ -48,7 +53,7 @@ fn main() { }; let buffer = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; - surface.set_buffer(buffer.as_slice(), width as u16, height as u16); + surface.set_buffer(&context, buffer.as_slice(), width as u16, height as u16); } Event::MainEventsCleared => { window.request_redraw(); diff --git a/examples/fruit.rs b/examples/fruit.rs index b64ae47..6a76398 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -1,4 +1,5 @@ use image::GenericImageView; +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; @@ -18,10 +19,12 @@ fn main() { .collect::>(); 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")] { @@ -37,15 +40,20 @@ fn main() { .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() => { - surface.set_buffer(&buffer, fruit.width() as u16, fruit.height() as u16); + surface.set_buffer( + &context, + &buffer, + fruit.width() as u16, + fruit.height() as u16, + ); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/rectangle.rs b/examples/rectangle.rs index 17b8a20..d3e951d 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -1,3 +1,4 @@ +use std::rc::Rc; use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; @@ -21,10 +22,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")] { @@ -40,8 +43,8 @@ fn main() { .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 buffer = Vec::new(); let mut flag = false; @@ -66,7 +69,7 @@ fn main() { redraw(&mut buffer, width, height, flag); // Blit the offscreen buffer to the window's client area - surface.set_buffer(&buffer, width as u16, height as u16); + surface.set_buffer(&context, &buffer, width as u16, height as u16); } Event::WindowEvent { diff --git a/examples/winit.rs b/examples/winit.rs index db421a4..0cd4b15 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -1,10 +1,11 @@ +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")] { @@ -20,8 +21,8 @@ fn main() { .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; @@ -46,7 +47,7 @@ fn main() { }) .collect::>(); - surface.set_buffer(&buffer, width as u16, height as u16); + surface.set_buffer(&context, &buffer, width as u16, height as u16); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 120e5bc..143bbc1 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -1,3 +1,4 @@ +use std::rc::Rc; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; @@ -7,7 +8,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")] { @@ -23,8 +24,8 @@ fn main() { .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; @@ -45,7 +46,7 @@ fn main() { }) .collect::>(); - surface.set_buffer(&buffer, BUFFER_WIDTH as u16, BUFFER_HEIGHT as u16); + surface.set_buffer(&context, &buffer, BUFFER_WIDTH as u16, BUFFER_HEIGHT as u16); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/src/error.rs b/src/error.rs index 01ea102..786de35 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,6 +27,9 @@ pub enum SoftBufferError { #[error("The provided display handle is null.")] IncompleteDisplayHandle, + #[error("The provided display handle is not active.")] + Inactive, + #[error("Platform error")] PlatformError(Option, Option>), } diff --git a/src/lib.rs b/src/lib.rs index 6e424a3..a2940aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,14 +27,18 @@ use std::sync::Arc; pub use error::SoftBufferError; use raw_window_handle::{ - HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, + Active, DisplayHandle, HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, + HasWindowHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, }; /// 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 { +pub struct Context { /// The inner static dispatch object. context_impl: ContextDispatch, + + /// The reference to the event loop object. + display: D, } /// A macro for creating the enum used to statically dispatch to the platform-specific implementation. @@ -98,23 +102,18 @@ make_dispatch! { Orbital((), orbital::OrbitalImpl), } -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(display: D) -> Result + where + D: Sized, + { + let active = match display.active() { + Some(active) => active, + None => return Err(SoftBufferError::Inactive), + }; - /// 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 { - let imple: ContextDispatch = match raw_display_handle { + let imple: ContextDispatch = match display.display_handle(&active).raw_display_handle() { #[cfg(x11_platform)] RawDisplayHandle::Xlib(xlib_handle) => unsafe { ContextDispatch::X11(Arc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?)) @@ -149,39 +148,51 @@ impl Context { Ok(Self { context_impl: imple, + display, }) } } -pub struct Surface { +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 { + // SAFETY: This is safe because the lifetime of the display handle is static. + unsafe { + Self::new(DisplayHandle::borrow_raw( + raw_display_handle, + &Active::new_unchecked(), + )) + } + } +} + +pub struct Surface { /// This is boxed so that `Surface` is the same size on every platform. surface_impl: Box, + + /// The reference to the window object. + window: W, } -impl Surface { +impl Surface { /// Creates a new instance of this struct, using the provided window and display. - /// - /// # 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 + where + W: Sized, + { + let active = match context.display.active() { + Some(active) => active, + None => return Err(SoftBufferError::Inactive), + }; - /// Creates a new instance of this struct, using the provided raw window and display handles - /// - /// # 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 raw_window_handle = window.window_handle(&active).raw_window_handle(); let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle) { #[cfg(x11_platform)] ( @@ -232,6 +243,7 @@ impl Surface { Ok(Self { surface_impl: Box::new(imple), + window, }) } @@ -273,7 +285,23 @@ impl Surface { /// If the caller wishes to synchronize other surface/window changes, such requests must be sent to the /// Wayland compositor before calling this function. #[inline] - pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { + pub fn set_buffer( + &mut self, + context: &Context, + buffer: &[u32], + width: u16, + height: u16, + ) { + // Gain access to the window handle for the duration of this function. + let active = match context.display.active() { + Some(active) => active, + None => panic!("TODO: Handle not being active"), + }; + + let _ = self.window.window_handle(&active); + + // SAFETY: All of the below is safe because the window handle is valid for the lifetime of the + // context, and the context is valid for the lifetime of the surface. if (width as usize) * (height as usize) != buffer.len() { panic!("The size of the passed buffer is not the correct size. Its length must be exactly width*height."); } @@ -284,6 +312,27 @@ impl Surface { } } +impl Surface> { + /// Creates a new instance of this struct, using the provided raw window and display handles + /// + /// # 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 { + // SAFETY: This is safe because the lifetime of the window handle is static. + unsafe { + Self::new( + context, + WindowHandle::borrow_raw(raw_window_handle, &Active::new_unchecked()), + ) + } + } +} + fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str { match handle { RawWindowHandle::Xlib(_) => "Xlib", From d68110802683e2fcf2cc381ad90c301b29269093 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Mon, 20 Mar 2023 09:15:21 -0700 Subject: [PATCH 2/7] Avoid branch --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8e526f4..1632113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,8 +79,5 @@ members = [ ] [patch.crates-io] -raw-window-handle = { git = "https://github.com/notgull/raw-window-handle.git", branch = "notgull/impl-more", version = "0.5.1" } +raw-window-handle = { git = "https://github.com/rust-windowing/raw-window-handle.git", version = "0.5.1" } winit = { git = "https://github.com/bread-graphics/winit.git", branch = "window-handle", version = "0.28.3" } - -[patch.'https://github.com/rust-windowing/raw-window-handle'] -raw-window-handle = { git = "https://github.com/notgull/raw-window-handle.git", branch = "notgull/impl-more", version = "0.5.1" } From 62913ed98dd367884a9a25f5076189c9b8ace3d0 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Fri, 24 Mar 2023 05:08:12 -0700 Subject: [PATCH 3/7] Try new branch --- Cargo.toml | 2 +- examples/animation.rs | 2 +- examples/fruit.rs | 7 +- examples/rectangle.rs | 2 +- examples/winit.rs | 2 +- examples/winit_wrong_sized_buffer.rs | 2 +- src/lib.rs | 140 +++++++++++---------------- 7 files changed, 64 insertions(+), 93 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1632113..851b0c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,5 +79,5 @@ members = [ ] [patch.crates-io] -raw-window-handle = { git = "https://github.com/rust-windowing/raw-window-handle.git", version = "0.5.1" } +raw-window-handle = { git = "https://github.com/rust-windowing/raw-window-handle.git", version = "0.5.1", branch = "notgull/change-actie" } winit = { git = "https://github.com/bread-graphics/winit.git", branch = "window-handle", version = "0.28.3" } diff --git a/examples/animation.rs b/examples/animation.rs index 7d051d4..2f102cc 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -53,7 +53,7 @@ fn main() { }; let buffer = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)]; - surface.set_buffer(&context, buffer.as_slice(), width as u16, height as u16); + surface.set_buffer(buffer.as_slice(), width as u16, height as u16); } Event::MainEventsCleared => { window.request_redraw(); diff --git a/examples/fruit.rs b/examples/fruit.rs index 6a76398..01d5ee0 100644 --- a/examples/fruit.rs +++ b/examples/fruit.rs @@ -48,12 +48,7 @@ fn main() { match event { Event::RedrawRequested(window_id) if window_id == window.id() => { - surface.set_buffer( - &context, - &buffer, - fruit.width() as u16, - fruit.height() as u16, - ); + surface.set_buffer(&buffer, fruit.width() as u16, fruit.height() as u16); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/rectangle.rs b/examples/rectangle.rs index d3e951d..b01b5ac 100644 --- a/examples/rectangle.rs +++ b/examples/rectangle.rs @@ -69,7 +69,7 @@ fn main() { redraw(&mut buffer, width, height, flag); // Blit the offscreen buffer to the window's client area - surface.set_buffer(&context, &buffer, width as u16, height as u16); + surface.set_buffer(&buffer, width as u16, height as u16); } Event::WindowEvent { diff --git a/examples/winit.rs b/examples/winit.rs index 0cd4b15..06fd723 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -47,7 +47,7 @@ fn main() { }) .collect::>(); - surface.set_buffer(&context, &buffer, width as u16, height as u16); + surface.set_buffer(&buffer, width as u16, height as u16); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/examples/winit_wrong_sized_buffer.rs b/examples/winit_wrong_sized_buffer.rs index 143bbc1..6f3fb01 100644 --- a/examples/winit_wrong_sized_buffer.rs +++ b/examples/winit_wrong_sized_buffer.rs @@ -46,7 +46,7 @@ fn main() { }) .collect::>(); - surface.set_buffer(&context, &buffer, BUFFER_WIDTH as u16, BUFFER_HEIGHT as u16); + surface.set_buffer(&buffer, BUFFER_WIDTH as u16, BUFFER_HEIGHT as u16); } Event::WindowEvent { event: WindowEvent::CloseRequested, diff --git a/src/lib.rs b/src/lib.rs index a2940aa..22505c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ use std::sync::Arc; pub use error::SoftBufferError; use raw_window_handle::{ - Active, DisplayHandle, HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, + ActiveHandle, DisplayHandle, HasDisplayHandle, HasRawDisplayHandle, HasRawWindowHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, }; @@ -38,7 +38,7 @@ pub struct Context { context_impl: ContextDispatch, /// The reference to the event loop object. - display: D, + _display: D, } /// A macro for creating the enum used to statically dispatch to the platform-specific implementation. @@ -108,12 +108,7 @@ impl Context { where D: Sized, { - let active = match display.active() { - Some(active) => active, - None => return Err(SoftBufferError::Inactive), - }; - - let imple: ContextDispatch = match display.display_handle(&active).raw_display_handle() { + let imple: ContextDispatch = match display.display_handle().raw_display_handle() { #[cfg(x11_platform)] RawDisplayHandle::Xlib(xlib_handle) => unsafe { ContextDispatch::X11(Arc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?)) @@ -148,7 +143,7 @@ impl Context { Ok(Self { context_impl: imple, - display, + _display: display, }) } } @@ -161,12 +156,7 @@ 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 { // SAFETY: This is safe because the lifetime of the display handle is static. - unsafe { - Self::new(DisplayHandle::borrow_raw( - raw_display_handle, - &Active::new_unchecked(), - )) - } + unsafe { Self::new(DisplayHandle::borrow_raw(raw_display_handle)) } } } @@ -187,59 +177,57 @@ impl Surface { where W: Sized, { - let active = match context.display.active() { - Some(active) => active, - None => return Err(SoftBufferError::Inactive), - }; - - let raw_window_handle = window.window_handle(&active).raw_window_handle(); - let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle) { - #[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 { + let raw_window_handle = window.window_handle().unwrap(); + let imple: SurfaceDispatch = + match (&context.context_impl, raw_window_handle.raw_window_handle()) { + #[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())? - }) - } - #[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(target_os = "windows")] - (ContextDispatch::Win32(()), RawWindowHandle::Win32(win32_handle)) => { - SurfaceDispatch::Win32(unsafe { win32::Win32Impl::new(&win32_handle)? }) - } - #[cfg(target_os = "macos")] - (ContextDispatch::CG(()), RawWindowHandle::AppKit(appkit_handle)) => { - SurfaceDispatch::CG(unsafe { cg::CGImpl::new(appkit_handle)? }) - } - #[cfg(target_arch = "wasm32")] - (ContextDispatch::Web(context), RawWindowHandle::Web(web_handle)) => { - SurfaceDispatch::Web(web::WebImpl::new(context, web_handle)?) - } - #[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, - }) - } - }; + }), + #[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(target_os = "windows")] + (ContextDispatch::Win32(()), RawWindowHandle::Win32(win32_handle)) => { + SurfaceDispatch::Win32(unsafe { win32::Win32Impl::new(&win32_handle)? }) + } + #[cfg(target_os = "macos")] + (ContextDispatch::CG(()), RawWindowHandle::AppKit(appkit_handle)) => { + SurfaceDispatch::CG(unsafe { cg::CGImpl::new(appkit_handle)? }) + } + #[cfg(target_arch = "wasm32")] + (ContextDispatch::Web(context), RawWindowHandle::Web(web_handle)) => { + SurfaceDispatch::Web(web::WebImpl::new(context, web_handle)?) + } + #[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, + }) + } + }; Ok(Self { surface_impl: Box::new(imple), @@ -285,20 +273,8 @@ impl Surface { /// If the caller wishes to synchronize other surface/window changes, such requests must be sent to the /// Wayland compositor before calling this function. #[inline] - pub fn set_buffer( - &mut self, - context: &Context, - buffer: &[u32], - width: u16, - height: u16, - ) { - // Gain access to the window handle for the duration of this function. - let active = match context.display.active() { - Some(active) => active, - None => panic!("TODO: Handle not being active"), - }; - - let _ = self.window.window_handle(&active); + pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { + let _ = self.window.window_handle().unwrap(); // SAFETY: All of the below is safe because the window handle is valid for the lifetime of the // context, and the context is valid for the lifetime of the surface. @@ -327,7 +303,7 @@ impl Surface> { unsafe { Self::new( context, - WindowHandle::borrow_raw(raw_window_handle, &Active::new_unchecked()), + WindowHandle::borrow_raw(raw_window_handle, ActiveHandle::new_unchecked()), ) } } From 2cf733b5a763ea95d146e5e992322c0a9e8a504f Mon Sep 17 00:00:00 2001 From: jtnunley Date: Fri, 24 Mar 2023 10:34:50 -0700 Subject: [PATCH 4/7] Fix errors --- examples/animation.rs | 8 ++------ src/error.rs | 6 +++--- src/lib.rs | 4 ++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/examples/animation.rs b/examples/animation.rs index 2f102cc..5f167f0 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -25,12 +25,8 @@ fn main() { .unwrap(); } - let (context, mut surface) = { - let context = softbuffer::Context::new(window.clone()).unwrap(); - let surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); - - (context, surface) - }; + 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); diff --git a/src/error.rs b/src/error.rs index 786de35..f9a108e 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 thiserror::Error; @@ -27,8 +27,8 @@ pub enum SoftBufferError { #[error("The provided display handle is null.")] IncompleteDisplayHandle, - #[error("The provided display handle is not active.")] - Inactive, + #[error("A handle error occurred: {0}")] + HandleError(#[from] HandleError), #[error("Platform error")] PlatformError(Option, Option>), diff --git a/src/lib.rs b/src/lib.rs index 22505c5..dba984f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ impl Context { where D: Sized, { - let imple: ContextDispatch = match display.display_handle().raw_display_handle() { + let imple: ContextDispatch = match display.display_handle()?.raw_display_handle() { #[cfg(x11_platform)] RawDisplayHandle::Xlib(xlib_handle) => unsafe { ContextDispatch::X11(Arc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?)) @@ -177,7 +177,7 @@ impl Surface { where W: Sized, { - let raw_window_handle = window.window_handle().unwrap(); + let raw_window_handle = window.window_handle()?; let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle.raw_window_handle()) { #[cfg(x11_platform)] From f6318199dfa2f468a4fc1212ec11b77247922471 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Sun, 26 Mar 2023 10:15:37 -0700 Subject: [PATCH 5/7] Fix compiler errors --- Cargo.toml | 2 +- README.md | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 851b0c7..e5086c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ x11 = ["bytemuck", "nix", "x11rb", "x11-dl"] [dependencies] log = "0.4.17" -raw-window-handle = { version = "0.5.0", features = ["alloc"] } +raw-window-handle = { version = "0.5.0", features = ["std"] } thiserror = "1.0.30" [target.'cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))'.dependencies] diff --git a/README.md b/README.md index f15cb6e..0194b2a 100644 --- a/README.md +++ b/README.md @@ -58,15 +58,16 @@ To run an example with the web backend: `cargo run-wasm --example winit` Example == ```rust,no_run +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(Rc::clone(&window)).unwrap(); + let mut surface = softbuffer::Surface::new(&context, Rc::clone(&window)).unwrap(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; From d325d301bdeacf6f742cc4ed0b5b510dfc76f3a7 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Mon, 27 Mar 2023 11:34:17 -0700 Subject: [PATCH 6/7] Make sure the display is kept alive --- src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dba984f..09e1085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ mod x11; mod error; -#[cfg(any(wayland_platform, x11_platform))] use std::sync::Arc; pub use error::SoftBufferError; @@ -38,7 +37,7 @@ pub struct Context { context_impl: ContextDispatch, /// The reference to the event loop object. - _display: D, + display: Arc, } /// A macro for creating the enum used to statically dispatch to the platform-specific implementation. @@ -143,7 +142,7 @@ impl Context { Ok(Self { context_impl: imple, - _display: display, + display: Arc::new(display), }) } } @@ -160,20 +159,20 @@ impl Context> { } } -pub struct Surface { +pub struct Surface { /// This is boxed so that `Surface` is the same size on every platform. surface_impl: Box, + /// Make sure that the display object is still alive. + _display: Arc, + /// The reference to the window object. window: W, } -impl Surface { +impl Surface { /// Creates a new instance of this struct, using the provided window and display. - pub fn new( - context: &Context, - window: W, - ) -> Result + pub fn new(context: &Context, window: W) -> Result where W: Sized, { @@ -232,6 +231,7 @@ impl Surface { Ok(Self { surface_impl: Box::new(imple), window, + _display: context.display.clone(), }) } @@ -274,7 +274,7 @@ impl Surface { /// Wayland compositor before calling this function. #[inline] pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { - let _ = self.window.window_handle().unwrap(); + let _guard = self.window.window_handle().unwrap(); // SAFETY: All of the below is safe because the window handle is valid for the lifetime of the // context, and the context is valid for the lifetime of the surface. @@ -288,7 +288,7 @@ impl Surface { } } -impl Surface> { +impl Surface> { /// Creates a new instance of this struct, using the provided raw window and display handles /// /// # Safety @@ -296,7 +296,7 @@ impl Surface> { /// - 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, + context: &Context, raw_window_handle: RawWindowHandle, ) -> Result { // SAFETY: This is safe because the lifetime of the window handle is static. From ff31c0ee5f5b750a909c922f1335efc64d5f9770 Mon Sep 17 00:00:00 2001 From: jtnunley Date: Fri, 31 Mar 2023 14:33:46 -0700 Subject: [PATCH 7/7] Use crates.io rwh --- Cargo.toml | 1 - src/lib.rs | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e5086c2..bd78868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,5 +79,4 @@ members = [ ] [patch.crates-io] -raw-window-handle = { git = "https://github.com/rust-windowing/raw-window-handle.git", version = "0.5.1", branch = "notgull/change-actie" } winit = { git = "https://github.com/bread-graphics/winit.git", branch = "window-handle", version = "0.28.3" } diff --git a/src/lib.rs b/src/lib.rs index 09e1085..c29ae28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,6 +228,8 @@ impl Surface { } }; + drop(raw_window_handle); + Ok(Self { surface_impl: Box::new(imple), window,