From 8080a3c6da123a93ba62a099b2de934595ea13fa Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Thu, 9 Sep 2021 15:36:17 -0700 Subject: [PATCH] web: Add Instance::create_surface_from_canvas Add specialized methods on web for creating a wgpu Surface directly from an web_sys::HTMLCanvasElement and OffscreenCanvas. * Instance::create_surface_from_canvas * Instance::create_surface_from_offscreen_canvas Fixes #1837. --- wgpu/Cargo.toml | 1 + wgpu/src/backend/web.rs | 30 +++++++++++++++++++++++++----- wgpu/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index f8ad038f40..34305066ce 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -269,6 +269,7 @@ web-sys = { version = "0.3.53", features = [ "GpuVertexState", "GpuVertexStepMode", "HtmlCanvasElement", + "OffscreenCanvas", "Window", ]} js-sys = "0.3.50" diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index a4e957bd2f..15628de1e9 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -887,6 +887,30 @@ fn future_map_async(result: JsFutureResult) -> Result<(), crate::BufferAsyncErro result.map(|_| ()).map_err(|_| crate::BufferAsyncError) } +impl Context { + pub fn instance_create_surface_from_canvas( + &self, + canvas: &web_sys::HtmlCanvasElement, + ) -> ::SurfaceId { + let context: wasm_bindgen::JsValue = match canvas.get_context("webgpu") { + Ok(Some(ctx)) => ctx.into(), + _ => panic!("expected to get context from canvas"), + }; + Sendable(context.into()) + } + + pub fn instance_create_surface_from_offscreen_canvas( + &self, + canvas: &web_sys::OffscreenCanvas, + ) -> ::SurfaceId { + let context: wasm_bindgen::JsValue = match canvas.get_context("webgpu") { + Ok(Some(ctx)) => ctx.into(), + _ => panic!("expected to get context from canvas"), + }; + Sendable(context.into()) + } +} + impl crate::Context for Context { type AdapterId = Sendable; type DeviceId = Sendable; @@ -949,11 +973,7 @@ impl crate::Context for Context { .expect("expected to find single canvas") .into(); let canvas_element: web_sys::HtmlCanvasElement = canvas_node.into(); - let context: wasm_bindgen::JsValue = match canvas_element.get_context("webgpu") { - Ok(Some(ctx)) => ctx.into(), - _ => panic!("expected to get context from canvas"), - }; - Sendable(context.into()) + self.instance_create_surface_from_canvas(&canvas_element) } fn adapter_is_surface_supported( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 3d258cd2ff..3eecd45ac2 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1480,6 +1480,40 @@ impl Instance { self.context.create_surface_from_core_animation_layer(layer) } + /// Creates a surface from a `web_sys::HtmlCanvasElement`. + /// + /// # Safety + /// + /// - canvas must be a valid element to create a surface upon. + #[cfg(target_arch = "wasm32")] + pub unsafe fn create_surface_from_canvas( + &self, + canvas: &web_sys::HtmlCanvasElement, + ) -> Surface { + Surface { + context: Arc::clone(&self.context), + id: self.context.instance_create_surface_from_canvas(canvas), + } + } + + /// Creates a surface from a `web_sys::OffscreenCanvas`. + /// + /// # Safety + /// + /// - canvas must be a valid OffscreenCanvas to create a surface upon. + #[cfg(target_arch = "wasm32")] + pub unsafe fn create_surface_from_offscreen_canvas( + &self, + canvas: &web_sys::OffscreenCanvas, + ) -> Surface { + Surface { + context: Arc::clone(&self.context), + id: self + .context + .instance_create_surface_from_offscreen_canvas(canvas), + } + } + /// Polls all devices. /// If `force_wait` is true and this is not running on the web, /// then this function will block until all in-flight buffers have been mapped.