From 4918b157ceeb830b5510686e90092cfc651b6975 Mon Sep 17 00:00:00 2001 From: Vincent Jousse Date: Thu, 3 Dec 2020 01:05:03 +0100 Subject: [PATCH 1/2] [gl] Add Instance struct in web version to align API with other backends. --- examples/quad/main.rs | 52 +++++++---------- src/backend/gl/src/lib.rs | 8 +-- src/backend/gl/src/window/web.rs | 97 +++++++++++++++++--------------- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/examples/quad/main.rs b/examples/quad/main.rs index 6a311778dc8..6f620477f55 100644 --- a/examples/quad/main.rs +++ b/examples/quad/main.rs @@ -102,48 +102,36 @@ fn main() { .with_title("quad".to_string()); // instantiate backend - #[cfg(not(target_arch = "wasm32"))] - let (_window, instance, mut adapters, surface) = { - let window = wb.build(&event_loop).unwrap(); - let instance = - back::Instance::create("gfx-rs quad", 1).expect("Failed to create an instance!"); - let adapters = instance.enumerate_adapters(); - let surface = unsafe { - instance - .create_surface(&window) - .expect("Failed to create a surface!") - }; - // Return `window` so it is not dropped: dropping it invalidates `surface`. - (window, Some(instance), adapters, surface) - }; + let window = wb.build(&event_loop).unwrap(); #[cfg(target_arch = "wasm32")] - let (_window, instance, mut adapters, surface) = { - let (window, surface) = { - let window = wb.build(&event_loop).unwrap(); - web_sys::window() - .unwrap() - .document() - .unwrap() - .body() - .unwrap() - .append_child(&winit::platform::web::WindowExtWebSys::canvas(&window)) - .unwrap(); - let surface = back::Surface::from_raw_handle(&window); - (window, surface) - }; - - let adapters = surface.enumerate_adapters(); - (window, None, adapters, surface) + web_sys::window() + .unwrap() + .document() + .unwrap() + .body() + .unwrap() + .append_child(&winit::platform::web::WindowExtWebSys::canvas(&window)) + .unwrap(); + + let instance = + back::Instance::create("gfx-rs quad", 1).expect("Failed to create an instance!"); + + let surface = unsafe { + instance + .create_surface(&window) + .expect("Failed to create a surface!") }; + let mut adapters = instance.enumerate_adapters(); + for adapter in &adapters { println!("{:?}", adapter.info); } let adapter = adapters.remove(0); - let mut renderer = Renderer::new(instance, surface, adapter); + let mut renderer = Renderer::new(Some(instance), surface, adapter); renderer.render(); diff --git a/src/backend/gl/src/lib.rs b/src/backend/gl/src/lib.rs index 04c360e60da..c056620dfd1 100644 --- a/src/backend/gl/src/lib.rs +++ b/src/backend/gl/src/lib.rs @@ -33,10 +33,10 @@ mod window; // Web implementation #[cfg(target_arch = "wasm32")] -pub use window::web::{Surface, Swapchain}; +pub use window::web::{Instance, Surface, Swapchain}; #[cfg(not(target_arch = "wasm32"))] -pub use crate::window::egl::{Instance, Surface, Swapchain}; +pub use window::egl::{Instance, Surface, Swapchain}; pub use glow::Context as GlContext; use glow::HasContext; @@ -101,12 +101,8 @@ impl Deref for GlContainer { pub enum Backend {} impl hal::Backend for Backend { - #[cfg(not(target_arch = "wasm32"))] type Instance = Instance; - #[cfg(target_arch = "wasm32")] - type Instance = Surface; - type PhysicalDevice = PhysicalDevice; type Device = Device; type Surface = Surface; diff --git a/src/backend/gl/src/window/web.rs b/src/backend/gl/src/window/web.rs index 9ec03185ac4..e75ba6c3ec4 100644 --- a/src/backend/gl/src/window/web.rs +++ b/src/backend/gl/src/window/web.rs @@ -4,7 +4,7 @@ use crate::{ use arrayvec::ArrayVec; use glow::HasContext; use hal::{adapter::Adapter, format as f, image, window}; -use std::iter; +use std::{iter, sync::Mutex}; use wasm_bindgen::JsCast; #[derive(Clone, Debug)] @@ -15,38 +15,68 @@ pub struct Swapchain { pub(crate) frame_buffers: ArrayVec<[native::RawFrameBuffer; 3]>, } -#[derive(Clone, Debug)] -pub struct Surface { - canvas: Starc, - pub(crate) swapchain: Option, - renderbuffer: Option, +#[derive(Debug)] +pub struct Instance { + canvas: Mutex>>, } -impl Surface { - pub fn from_canvas(canvas: web_sys::HtmlCanvasElement) -> Self { - Surface { - canvas: Starc::new(canvas), - swapchain: None, - renderbuffer: None, +impl hal::Instance for Instance { + fn create(_name: &str, _version: u32) -> Result { + Ok(Instance { + canvas: Mutex::new(None), + }) + } + + fn enumerate_adapters(&self) -> Vec> { + if let Some(canvas) = self.canvas.lock().unwrap().as_ref() { + let adapter = PhysicalDevice::new_adapter(GlContainer::from_canvas(canvas)); + vec![adapter] + } else { + vec![] } } - pub fn from_raw_handle(has_handle: &impl raw_window_handle::HasRawWindowHandle) -> Self { + unsafe fn create_surface( + &self, + has_handle: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result { if let raw_window_handle::RawWindowHandle::Web(handle) = has_handle.raw_window_handle() { - let canvas = web_sys::window() - .and_then(|win| win.document()) - .expect("Cannot get document") - .query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id)) - .expect("Cannot query for canvas") - .expect("Canvas is not found") - .dyn_into() - .expect("Failed to downcast to canvas type"); - Self::from_canvas(canvas) + let canvas: Starc = Starc::new( + web_sys::window() + .and_then(|win| win.document()) + .expect("Cannot get document") + .query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id)) + .expect("Cannot query for canvas") + .expect("Canvas is not found") + .dyn_into() + .expect("Failed to downcast to canvas type"), + ); + + *self.canvas.lock().unwrap() = Some(canvas.clone()); + + Ok(Surface { + canvas, + swapchain: None, + renderbuffer: None, + }) } else { unreachable!() } } + unsafe fn destroy_surface(&self, _surface: Surface) { + // TODO: Implement Surface cleanup + } +} + +#[derive(Clone, Debug)] +pub struct Surface { + canvas: Starc, + pub(crate) swapchain: Option, + renderbuffer: Option, +} + +impl Surface { fn swapchain_formats(&self) -> Vec { vec![f::Format::Rgba8Unorm, f::Format::Bgra8Unorm] } @@ -175,26 +205,3 @@ impl window::PresentationSurface for Surface { Ok((swapchain_image, None)) } } - -impl hal::Instance for Surface { - fn create(_name: &str, _version: u32) -> Result { - unimplemented!() - } - - fn enumerate_adapters(&self) -> Vec> { - // TODO: Move to `self` like native/window - let adapter = PhysicalDevice::new_adapter(GlContainer::from_canvas(&self.canvas)); - vec![adapter] - } - - unsafe fn create_surface( - &self, - _: &impl raw_window_handle::HasRawWindowHandle, - ) -> Result { - unimplemented!() - } - - unsafe fn destroy_surface(&self, _surface: Surface) { - // TODO: Implement Surface cleanup - } -} From 6fd2d81b13e8c7a00fd32ed6d3c46b21bcd2c27e Mon Sep 17 00:00:00 2001 From: Vincent Jousse Date: Thu, 3 Dec 2020 17:09:42 +0100 Subject: [PATCH 2/2] Use parking_lot::Mutex. Implement destroy_surface function. --- src/backend/gl/src/window/web.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/backend/gl/src/window/web.rs b/src/backend/gl/src/window/web.rs index e75ba6c3ec4..cefef4c6468 100644 --- a/src/backend/gl/src/window/web.rs +++ b/src/backend/gl/src/window/web.rs @@ -4,7 +4,8 @@ use crate::{ use arrayvec::ArrayVec; use glow::HasContext; use hal::{adapter::Adapter, format as f, image, window}; -use std::{iter, sync::Mutex}; +use parking_lot::Mutex; +use std::{iter, sync::Arc}; use wasm_bindgen::JsCast; #[derive(Clone, Debug)] @@ -28,7 +29,7 @@ impl hal::Instance for Instance { } fn enumerate_adapters(&self) -> Vec> { - if let Some(canvas) = self.canvas.lock().unwrap().as_ref() { + if let Some(canvas) = self.canvas.lock().as_ref() { let adapter = PhysicalDevice::new_adapter(GlContainer::from_canvas(canvas)); vec![adapter] } else { @@ -52,7 +53,7 @@ impl hal::Instance for Instance { .expect("Failed to downcast to canvas type"), ); - *self.canvas.lock().unwrap() = Some(canvas.clone()); + *self.canvas.lock() = Some(canvas.clone()); Ok(Surface { canvas, @@ -64,8 +65,14 @@ impl hal::Instance for Instance { } } - unsafe fn destroy_surface(&self, _surface: Surface) { - // TODO: Implement Surface cleanup + unsafe fn destroy_surface(&self, surface: Surface) { + let mut canvas_option_ref = self.canvas.lock(); + + if let Some(canvas) = canvas_option_ref.as_ref() { + if Arc::ptr_eq(&canvas.arc, &surface.canvas.arc) { + *canvas_option_ref = None; + } + } } }