Take a reference to a window in GraphicsContext::new, like glutin and wgpu

This commit is contained in:
Jeremy Soller 2022-12-20 08:43:26 -07:00
parent 85b4f189bd
commit 99d63063b6
13 changed files with 40 additions and 78 deletions

View file

@ -63,15 +63,15 @@ use winit::window::WindowBuilder;
fn main() { fn main() {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap(); let mut graphics_context = unsafe { GraphicsContext::new(&window) }.unwrap();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { Event::RedrawRequested(window_id) if window_id == window.id() => {
let (width, height) = { let (width, height) = {
let size = graphics_context.window().inner_size(); let size = window.inner_size();
(size.width, size.height) (size.width, size.height)
}; };
let buffer = (0..((width * height) as usize)) let buffer = (0..((width * height) as usize))
@ -93,7 +93,7 @@ fn main() {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window_id == graphics_context.window().id() => { } if window_id == window.id() => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}

View file

@ -25,7 +25,7 @@ fn main() {
.unwrap(); .unwrap();
} }
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap(); let mut graphics_context = unsafe { GraphicsContext::new(&window) }.unwrap();
let mut old_size = (0, 0); let mut old_size = (0, 0);
let mut frames = pre_render_frames(0, 0); let mut frames = pre_render_frames(0, 0);
@ -35,10 +35,10 @@ fn main() {
*control_flow = ControlFlow::Poll; *control_flow = ControlFlow::Poll;
match event { match event {
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { Event::RedrawRequested(window_id) if window_id == window.id() => {
let elapsed = start.elapsed().as_secs_f64() % 1.0; let elapsed = start.elapsed().as_secs_f64() % 1.0;
let (width, height) = { let (width, height) = {
let size = graphics_context.window().inner_size(); let size = window.inner_size();
(size.width, size.height) (size.width, size.height)
}; };
@ -51,12 +51,12 @@ fn main() {
graphics_context.set_buffer(buffer.as_slice(), width as u16, height as u16); graphics_context.set_buffer(buffer.as_slice(), width as u16, height as u16);
} }
Event::MainEventsCleared => { Event::MainEventsCleared => {
graphics_context.window().request_redraw(); window.request_redraw();
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window_id == graphics_context.window().id() => { } if window_id == window.id() => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}
@ -89,4 +89,4 @@ fn pre_render_frames(width: usize, height: usize) -> Vec<Vec<u32>>{
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
(0..60).into_par_iter().map(render).collect() (0..60).into_par_iter().map(render).collect()
} }

View file

@ -32,19 +32,19 @@ fn main() {
.unwrap(); .unwrap();
} }
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap(); let mut graphics_context = unsafe { GraphicsContext::new(&window) }.unwrap();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { Event::RedrawRequested(window_id) if window_id == window.id() => {
graphics_context.set_buffer(&buffer, fruit.width() as u16, fruit.height() as u16); graphics_context.set_buffer(&buffer, fruit.width() as u16, fruit.height() as u16);
} }
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window_id == graphics_context.window().id() => { } if window_id == window.id() => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}

View file

@ -21,15 +21,15 @@ fn main() {
.unwrap(); .unwrap();
} }
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap(); let mut graphics_context = unsafe { GraphicsContext::new(&window) }.unwrap();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { Event::RedrawRequested(window_id) if window_id == window.id() => {
let (width, height) = { let (width, height) = {
let size = graphics_context.window().inner_size(); let size = window.inner_size();
(size.width, size.height) (size.width, size.height)
}; };
let buffer = (0..((width * height) as usize)) let buffer = (0..((width * height) as usize))
@ -51,7 +51,7 @@ fn main() {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window_id == graphics_context.window().id() => { } if window_id == window.id() => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}

View file

@ -24,13 +24,13 @@ fn main() {
.unwrap(); .unwrap();
} }
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap(); let mut graphics_context = unsafe { GraphicsContext::new(&window) }.unwrap();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { Event::RedrawRequested(window_id) if window_id == window.id() => {
let buffer = (0..((BUFFER_WIDTH * BUFFER_HEIGHT) as usize)) let buffer = (0..((BUFFER_WIDTH * BUFFER_HEIGHT) as usize))
.map(|index| { .map(|index| {
let y = index / (BUFFER_WIDTH as usize); let y = index / (BUFFER_WIDTH as usize);
@ -50,7 +50,7 @@ fn main() {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window_id == graphics_context.window().id() => { } if window_id == window.id() => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => {} _ => {}

View file

@ -1,5 +1,5 @@
use crate::{GraphicsContextImpl, SwBufError}; use crate::{GraphicsContextImpl, SwBufError};
use raw_window_handle::{HasRawWindowHandle, AppKitWindowHandle}; use raw_window_handle::AppKitWindowHandle;
use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault}; use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault};
use core_graphics::color_space::CGColorSpace; use core_graphics::color_space::CGColorSpace;
use core_graphics::data_provider::CGDataProvider; use core_graphics::data_provider::CGDataProvider;
@ -17,7 +17,7 @@ pub struct CGImpl {
} }
impl CGImpl { impl CGImpl {
pub unsafe fn new<W: HasRawWindowHandle>(handle: AppKitWindowHandle) -> Result<Self, SwBufError<W>> { pub unsafe fn new(handle: AppKitWindowHandle) -> Result<Self, SwBufError> {
let view = handle.ns_view as id; let view = handle.ns_view as id;
let layer = CALayer::new(); let layer = CALayer::new();
let subview: id = NSView::alloc(nil).initWithFrame_(view.frame()); let subview: id = NSView::alloc(nil).initWithFrame_(view.frame());

View file

@ -1,14 +1,13 @@
use std::error::Error; use std::error::Error;
use raw_window_handle::{HasRawWindowHandle, RawDisplayHandle, RawWindowHandle}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SwBufError<W: HasRawWindowHandle> { pub enum SwBufError {
#[error( #[error(
"The provided window returned an unsupported platform: {human_readable_window_platform_name}, {human_readable_display_platform_name}." "The provided window returned an unsupported platform: {human_readable_window_platform_name}, {human_readable_display_platform_name}."
)] )]
UnsupportedPlatform { UnsupportedPlatform {
window: W,
human_readable_window_platform_name: &'static str, human_readable_window_platform_name: &'static str,
human_readable_display_platform_name: &'static str, human_readable_display_platform_name: &'static str,
window_handle: RawWindowHandle, window_handle: RawWindowHandle,
@ -19,9 +18,9 @@ pub enum SwBufError<W: HasRawWindowHandle> {
} }
#[allow(unused)] // This isn't used on all platforms #[allow(unused)] // This isn't used on all platforms
pub(crate) fn unwrap<T, E: std::error::Error + 'static, W: HasRawWindowHandle>(res: Result<T, E>, str: &str) -> Result<T, SwBufError<W>>{ pub(crate) fn unwrap<T, E: std::error::Error + 'static>(res: Result<T, E>, str: &str) -> Result<T, SwBufError>{
match res{ match res{
Ok(t) => Ok(t), Ok(t) => Ok(t),
Err(e) => Err(SwBufError::PlatformError(Some(str.into()), Some(Box::new(e)))) Err(e) => Err(SwBufError::PlatformError(Some(str.into()), Some(Box::new(e))))
} }
} }

View file

@ -28,18 +28,18 @@ use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandl
/// write to a window on that platform. This struct owns the window that this data corresponds to /// write to a window on that platform. This struct owns the window that this data corresponds to
/// to ensure safety, as that data must be destroyed before the window itself is destroyed. You may /// to ensure safety, as that data must be destroyed before the window itself is destroyed. You may
/// access the underlying window via [`window`](Self::window) and [`window_mut`](Self::window_mut). /// access the underlying window via [`window`](Self::window) and [`window_mut`](Self::window_mut).
pub struct GraphicsContext<W: HasRawWindowHandle + HasRawDisplayHandle> { pub struct GraphicsContext {
window: W,
graphics_context_impl: Box<dyn GraphicsContextImpl>, graphics_context_impl: Box<dyn GraphicsContextImpl>,
} }
impl<W: HasRawWindowHandle + HasRawDisplayHandle> GraphicsContext<W> { impl GraphicsContext {
/// Creates a new instance of this struct, consuming the given window. /// Creates a new instance of this struct, consuming the given window.
/// ///
/// # Safety /// # Safety
/// ///
/// - Ensure that the passed object is valid to draw a 2D buffer to /// - Ensure that the passed object is valid to draw a 2D buffer to, and is valid for the
pub unsafe fn new(window: W) -> Result<Self, SwBufError<W>> { /// lifetime of the GraphicsContext
pub unsafe fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(window: &W) -> Result<Self, SwBufError> {
let raw_window_handle = window.raw_window_handle(); let raw_window_handle = window.raw_window_handle();
let raw_display_handle = window.raw_display_handle(); let raw_display_handle = window.raw_display_handle();
@ -57,7 +57,6 @@ impl<W: HasRawWindowHandle + HasRawDisplayHandle> GraphicsContext<W> {
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
(RawWindowHandle::Orbital(orbital_handle), _) => Box::new(orbital::OrbitalImpl::new(orbital_handle)?), (RawWindowHandle::Orbital(orbital_handle), _) => Box::new(orbital::OrbitalImpl::new(orbital_handle)?),
(unimplemented_window_handle, unimplemented_display_handle) => return Err(SwBufError::UnsupportedPlatform { (unimplemented_window_handle, unimplemented_display_handle) => return Err(SwBufError::UnsupportedPlatform {
window,
human_readable_window_platform_name: window_handle_type_name(&unimplemented_window_handle), human_readable_window_platform_name: window_handle_type_name(&unimplemented_window_handle),
human_readable_display_platform_name: display_handle_type_name(&unimplemented_display_handle), human_readable_display_platform_name: display_handle_type_name(&unimplemented_display_handle),
window_handle: unimplemented_window_handle, window_handle: unimplemented_window_handle,
@ -66,36 +65,10 @@ impl<W: HasRawWindowHandle + HasRawDisplayHandle> GraphicsContext<W> {
}; };
Ok(Self { Ok(Self {
window,
graphics_context_impl: imple, graphics_context_impl: imple,
}) })
} }
/// Gets shared access to the underlying window.
#[inline]
pub fn window(&self) -> &W {
&self.window
}
/// Gets mut/exclusive access to the underlying window.
///
/// This method is `unsafe` because it could be used to replace the window with another one,
/// thus dropping the original window and violating the property that this [`GraphicsContext`]
/// will always be destroyed before the window it writes into. This method should only be used
/// when the window type in use requires mutable access to perform some action on an existing
/// window.
///
/// # Safety
///
/// - After the returned mutable reference is dropped, the window must still be the same window
/// which this [`GraphicsContext`] was created for; and within that window, the
/// platform-specific configuration for 2D drawing must not have been modified. (For example,
/// on macOS the view hierarchy of the window must not have been modified.)
#[inline]
pub unsafe fn window_mut(&mut self) -> &mut W {
&mut self.window
}
/// Shows the given buffer with the given width and height on the window corresponding to this /// Shows the given buffer with the given width and height on the window corresponding to this
/// graphics context. Panics if buffer.len() ≠ width*height. If the size of the buffer does /// graphics context. Panics if buffer.len() ≠ width*height. If the size of the buffer does
/// not match the size of the window, the buffer is drawn in the upper-left corner of the window. /// not match the size of the window, the buffer is drawn in the upper-left corner of the window.
@ -131,14 +104,6 @@ impl<W: HasRawWindowHandle + HasRawDisplayHandle> GraphicsContext<W> {
} }
} }
impl<W: HasRawWindowHandle + HasRawDisplayHandle> AsRef<W> for GraphicsContext<W> {
/// Equivalent to [`self.window()`](Self::window()).
#[inline]
fn as_ref(&self) -> &W {
self.window()
}
}
trait GraphicsContextImpl { trait GraphicsContextImpl {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16); unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16);
} }

View file

@ -1,4 +1,3 @@
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::OrbitalWindowHandle; use raw_window_handle::OrbitalWindowHandle;
use std::{ use std::{
cmp, cmp,
@ -47,7 +46,7 @@ pub struct OrbitalImpl {
} }
impl OrbitalImpl { impl OrbitalImpl {
pub fn new<W: HasRawWindowHandle>(handle: OrbitalWindowHandle) -> Result<Self, SwBufError<W>> { pub fn new(handle: OrbitalWindowHandle) -> Result<Self, SwBufError> {
Ok(Self { handle }) Ok(Self { handle })
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{error::unwrap, GraphicsContextImpl, SwBufError}; use crate::{error::unwrap, GraphicsContextImpl, SwBufError};
use nix::sys::memfd::{memfd_create, MemFdCreateFlag}; use nix::sys::memfd::{memfd_create, MemFdCreateFlag};
use raw_window_handle::{HasRawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle}; use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};
use std::{ use std::{
ffi::CStr, ffi::CStr,
fs::File, fs::File,
@ -40,10 +40,10 @@ impl Drop for WaylandBuffer {
} }
impl WaylandImpl { impl WaylandImpl {
pub unsafe fn new<W: HasRawWindowHandle>( pub unsafe fn new(
window_handle: WaylandWindowHandle, window_handle: WaylandWindowHandle,
display_handle: WaylandDisplayHandle, display_handle: WaylandDisplayHandle,
) -> Result<Self, SwBufError<W>> { ) -> Result<Self, SwBufError> {
let conn = Connection::from_backend(Backend::from_foreign_display( let conn = Connection::from_backend(Backend::from_foreign_display(
display_handle.display as *mut _, display_handle.display as *mut _,
)); ));

View file

@ -1,4 +1,3 @@
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::WebWindowHandle; use raw_window_handle::WebWindowHandle;
use wasm_bindgen::Clamped; use wasm_bindgen::Clamped;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
@ -15,7 +14,7 @@ pub struct WebImpl {
} }
impl WebImpl { impl WebImpl {
pub fn new<W: HasRawWindowHandle>(handle: WebWindowHandle) -> Result<Self, SwBufError<W>> { pub fn new(handle: WebWindowHandle) -> Result<Self, SwBufError> {
let canvas: HtmlCanvasElement = web_sys::window() let canvas: HtmlCanvasElement = web_sys::window()
.ok_or_else(|| { .ok_or_else(|| {
SwBufError::PlatformError( SwBufError::PlatformError(

View file

@ -1,5 +1,5 @@
use crate::{GraphicsContextImpl, SwBufError}; use crate::{GraphicsContextImpl, SwBufError};
use raw_window_handle::{HasRawWindowHandle, Win32WindowHandle}; use raw_window_handle::Win32WindowHandle;
use std::os::raw::c_int; use std::os::raw::c_int;
use windows_sys::Win32::Foundation::HWND; use windows_sys::Win32::Foundation::HWND;
@ -22,7 +22,7 @@ struct BitmapInfo {
} }
impl Win32Impl { impl Win32Impl {
pub unsafe fn new<W: HasRawWindowHandle>(handle: &Win32WindowHandle) -> Result<Self, crate::SwBufError<W>> { pub unsafe fn new(handle: &Win32WindowHandle) -> Result<Self, crate::SwBufError> {
let dc = GetDC(handle.hwnd as HWND); let dc = GetDC(handle.hwnd as HWND);
if dc == 0 { if dc == 0 {

View file

@ -1,5 +1,5 @@
use crate::{GraphicsContextImpl, SwBufError}; use crate::{GraphicsContextImpl, SwBufError};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, XlibDisplayHandle, XlibWindowHandle}; use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle};
use std::os::raw::{c_char, c_uint}; use std::os::raw::{c_char, c_uint};
use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC}; use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC};
@ -13,7 +13,7 @@ pub struct X11Impl {
} }
impl X11Impl { impl X11Impl {
pub unsafe fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(window_handle: XlibWindowHandle, display_handle: XlibDisplayHandle) -> Result<Self, SwBufError<W>> { pub unsafe fn new(window_handle: XlibWindowHandle, display_handle: XlibDisplayHandle) -> Result<Self, SwBufError> {
let lib = match Xlib::open() { let lib = match Xlib::open() {
Ok(lib) => lib, Ok(lib) => lib,
Err(e) => return Err(SwBufError::PlatformError(Some("Failed to open Xlib".into()), Some(Box::new(e)))) Err(e) => return Err(SwBufError::PlatformError(Some("Failed to open Xlib".into()), Some(Box::new(e))))