From 5e8e1b0bcd15d548673ce0ed034c965c0f18eeba Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 15:23:18 +0100 Subject: [PATCH 01/15] introduce SurfaceTarget to unify all surface creation methods on the wgpu instance --- wgpu/src/lib.rs | 437 +++++++++++++++++++++++++----------------------- 1 file changed, 231 insertions(+), 206 deletions(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9c5173e6e0..b8543f5232 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -365,7 +365,7 @@ static_assertions::assert_impl_all!(SurfaceConfiguration: Send, Sync); /// serves a similar role. pub struct Surface<'window> { context: Arc, - _surface: Option>, + _surface: Option>, id: ObjectId, data: Box, // Stores the latest `SurfaceConfiguration` that was set using `Surface::configure`. @@ -409,6 +409,100 @@ impl Drop for Surface<'_> { } } +/// Super trait for window handles as used in [`SurfaceTargetCanvas`]. +pub trait WindowHandle: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} + +impl WindowHandle for T where T: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} + +/// The window/canvas/surface/swap-chain/etc. a surface is attached to. +/// +/// This is either a window or an actual web canvas depending on the platform and +/// enabled features. +/// Refer to the individual variants for more information. +pub enum SurfaceTarget<'window> { + /// Raw window handle. + /// + /// If the specified display and window handle are not supported by any of the backends, then the surface + /// will not be supported by any adapters. + /// + /// # Errors + /// + /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// or declines to provide GPU access (such as due to a resource shortage). + /// + /// # Panics + /// + /// - On macOS/Metal: surface creation will panic if not called on the main thread. + /// - On web: surface creation will panic if the `raw_window_handle` does not properly refer to a + /// canvas element. + WindowHandle(Box), + + /// Surface from `CoreAnimationLayer`. + /// + /// # Safety + /// + /// - layer must be a valid object to create a surface upon. + #[cfg(metal)] + CoreAnimationLayer(*mut std::ffi::c_void), + + /// Surface from `IDCompositionVisual`. + /// + /// # Safety + /// + /// - visual must be a valid IDCompositionVisual to create a surface upon. + #[cfg(dx12)] + CompositionVisual(*mut std::ffi::c_void), + + /// Surface from DX12 `SurfaceHandle`. + /// + /// # Safety + /// + /// - surface_handle must be a valid SurfaceHandle to create a surface upon. + #[cfg(dx12)] + SurfaceHandle(*mut std::ffi::c_void), + + /// Surface from DX12 `SwapChainPanel`. + /// + /// # Safety + /// + /// - visual must be a valid SwapChainPanel to create a surface upon. + #[cfg(dx12)] + SwapChainPanel(*mut std::ffi::c_void), + + /// Surface from a `web_sys::HtmlCanvasElement`. + /// + /// The `canvas` argument must be a valid `` element to + /// create a surface upon. + /// + /// # Errors + /// + /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// or declines to provide GPU access (such as due to a resource shortage). + #[cfg(any(webgpu, webgl))] + Canvas(web_sys::HtmlCanvasElement), + + /// Surface from a `web_sys::OffscreenCanvas`. + /// + /// The `canvas` argument must be a valid `OffscreenCanvas` object + /// to create a surface upon. + /// + /// # Errors + /// + /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// or declines to provide GPU access (such as due to a resource shortage). + #[cfg(any(webgpu, webgl))] + OffscreenCanvas(web_sys::OffscreenCanvas), +} + +impl<'a, T> From for SurfaceTarget<'a> +where + T: WindowHandle + 'a, +{ + fn from(handle: T) -> Self { + Self::WindowHandle(Box::new(handle)) + } +} + /// Handle to a binding group layout. /// /// A `BindGroupLayout` is a handle to the GPU-side layout of a binding group. It can be used to @@ -1740,38 +1834,147 @@ impl Instance { } } - /// Creates a surface from a raw window handle. - /// - /// If the specified display and window handle are not supported by any of the backends, then the surface - /// will not be supported by any adapters. - /// - /// If a reference is passed in `window`, the returned [`Surface`] will - /// hold a lifetime to it. Owned values will return a [`Surface<'static>`] - /// instead. + /// Creates a new surface drawing to the target specified via the [`SurfaceTarget`] enum. /// - /// # Errors - /// - /// - On WebGL2: Will return an error if the browser does not support WebGL2, - /// or declines to provide GPU access (such as due to a resource shortage). - /// - /// # Panics - /// - /// - On macOS/Metal: will panic if not called on the main thread. - /// - On web: will panic if the `raw_window_handle` does not properly refer to a - /// canvas element. - pub fn create_surface<'window, W>( + /// Most commonly used are window handles (or provider of windows handles) + /// which can be passed directly as they're automatically converted to [`SurfaceTarget`]. + pub fn create_surface<'window>( &self, - window: W, - ) -> Result, CreateSurfaceError> - where - W: HasWindowHandle + HasDisplayHandle + WasmNotSendSync + 'window, - { - let mut surface = unsafe { self.create_surface_from_raw(&window) }?; - surface._surface = Some(Box::new(window)); - Ok(surface) + target: impl Into>, + ) -> Result, CreateSurfaceError> { + match target.into() { + SurfaceTarget::WindowHandle(window) => { + let mut surface = unsafe { self.create_surface_from_raw(&window) }?; + surface._surface = Some(window); + Ok(surface) + } + + #[cfg(metal)] + SurfaceTarget::CoreAnimationLayer(layer) => { + let surface = unsafe { + self.context + .as_any() + .downcast_ref::() + .unwrap() + .create_surface_from_core_animation_layer(layer) + }; + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + id: ObjectId::from(surface.id()), + data: Box::new(surface), + config: Mutex::new(None), + }) + } + + #[cfg(dx12)] + SurfaceTarget::CompositionVisual(visual) => { + let surface = unsafe { + self.context + .as_any() + .downcast_ref::() + .unwrap() + .create_surface_from_visual(visual) + }; + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + id: ObjectId::from(surface.id()), + data: Box::new(surface), + config: Mutex::new(None), + }) + } + + #[cfg(dx12)] + SurfaceTarget::SurfaceHandle(surface_handle) => { + let surface = unsafe { + self.context + .as_any() + .downcast_ref::() + .unwrap() + .create_surface_from_surface_handle(surface_handle) + }; + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + id: ObjectId::from(surface.id()), + data: Box::new(surface), + config: Mutex::new(None), + }) + } + + #[cfg(dx12)] + SurfaceTarget::SwapChainPanel(swap_chain_panel) => { + let surface = unsafe { + self.context + .as_any() + .downcast_ref::() + .unwrap() + .create_surface_from_swap_chain_panel(swap_chain_panel) + }; + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + id: ObjectId::from(surface.id()), + data: Box::new(surface), + config: Mutex::new(None), + }) + } + + #[cfg(any(webgpu, webgl))] + SurfaceTarget::Canvas(canvas) => { + let surface = self + .context + .as_any() + .downcast_ref::() + .unwrap() + .instance_create_surface_from_canvas(canvas)?; + + // TODO: This is ugly, a way to create things from a native context needs to be made nicer. + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + #[cfg(webgl)] + id: ObjectId::from(surface.id()), + #[cfg(webgl)] + data: Box::new(surface), + #[cfg(webgpu)] + id: ObjectId::UNUSED, + #[cfg(webgpu)] + data: Box::new(surface.1), + config: Mutex::new(None), + }) + } + + #[cfg(any(webgpu, webgl))] + SurfaceTarget::OffscreenCanvas(canvas) => { + let surface = self + .context + .as_any() + .downcast_ref::() + .unwrap() + .instance_create_surface_from_offscreen_canvas(canvas)?; + + // TODO: This is ugly, a way to create things from a native context needs to be made nicer. + Ok(Surface { + context: Arc::clone(&self.context), + _surface: None, + #[cfg(webgl)] + id: ObjectId::from(surface.id()), + #[cfg(webgl)] + data: Box::new(surface), + #[cfg(webgpu)] + id: ObjectId::UNUSED, + #[cfg(webgpu)] + data: Box::new(surface.1), + config: Mutex::new(None), + }) + } + } } /// An alternative version to [`create_surface()`](Self::create_surface) + /// with [`SurfaceTargetCanvas::WindowHandle`] /// which has no lifetime requirements to `window` and doesn't require /// [`Send`] or [`Sync`] (on non-Wasm targets). This makes it `unsafe` /// instead and always returns a [`Surface<'static>`]. @@ -1818,184 +2021,6 @@ impl Instance { }) } - /// Creates a surface from `CoreAnimationLayer`. - /// - /// # Safety - /// - /// - layer must be a valid object to create a surface upon. - #[cfg(metal)] - pub unsafe fn create_surface_from_core_animation_layer( - &self, - layer: *mut std::ffi::c_void, - ) -> Surface<'static> { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_core_animation_layer(layer) - }; - Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - } - } - - /// Creates a surface from `IDCompositionVisual`. - /// - /// # Safety - /// - /// - visual must be a valid IDCompositionVisual to create a surface upon. - #[cfg(dx12)] - pub unsafe fn create_surface_from_visual( - &self, - visual: *mut std::ffi::c_void, - ) -> Surface<'static> { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_visual(visual) - }; - Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - } - } - - /// Creates a surface from `SurfaceHandle`. - /// - /// # Safety - /// - /// - surface_handle must be a valid SurfaceHandle to create a surface upon. - #[cfg(dx12)] - pub unsafe fn create_surface_from_surface_handle( - &self, - surface_handle: *mut std::ffi::c_void, - ) -> Surface<'static> { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_surface_handle(surface_handle) - }; - Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - } - } - - /// Creates a surface from `SwapChainPanel`. - /// - /// # Safety - /// - /// - visual must be a valid SwapChainPanel to create a surface upon. - #[cfg(dx12)] - pub unsafe fn create_surface_from_swap_chain_panel( - &self, - swap_chain_panel: *mut std::ffi::c_void, - ) -> Surface<'static> { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_swap_chain_panel(swap_chain_panel) - }; - Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - } - } - - /// Creates a surface from a `web_sys::HtmlCanvasElement`. - /// - /// The `canvas` argument must be a valid `` element to - /// create a surface upon. - /// - /// # Errors - /// - /// - On WebGL2: Will return an error if the browser does not support WebGL2, - /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] - pub fn create_surface_from_canvas( - &self, - canvas: web_sys::HtmlCanvasElement, - ) -> Result, CreateSurfaceError> { - let surface = self - .context - .as_any() - .downcast_ref::() - .unwrap() - .instance_create_surface_from_canvas(canvas)?; - - // TODO: This is ugly, a way to create things from a native context needs to be made nicer. - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - #[cfg(webgl)] - id: ObjectId::from(surface.id()), - #[cfg(webgl)] - data: Box::new(surface), - #[cfg(webgpu)] - id: ObjectId::UNUSED, - #[cfg(webgpu)] - data: Box::new(surface.1), - config: Mutex::new(None), - }) - } - - /// Creates a surface from a `web_sys::OffscreenCanvas`. - /// - /// The `canvas` argument must be a valid `OffscreenCanvas` object - /// to create a surface upon. - /// - /// # Errors - /// - /// - On WebGL2: Will return an error if the browser does not support WebGL2, - /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] - pub fn create_surface_from_offscreen_canvas( - &self, - canvas: web_sys::OffscreenCanvas, - ) -> Result, CreateSurfaceError> { - let surface = self - .context - .as_any() - .downcast_ref::() - .unwrap() - .instance_create_surface_from_offscreen_canvas(canvas)?; - - // TODO: This is ugly, a way to create things from a native context needs to be made nicer. - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - #[cfg(webgl)] - id: ObjectId::from(surface.id()), - #[cfg(webgl)] - data: Box::new(surface), - #[cfg(webgpu)] - id: ObjectId::UNUSED, - #[cfg(webgpu)] - data: Box::new(surface.1), - config: Mutex::new(None), - }) - } - /// Polls all devices. /// /// If `force_wait` is true and this is not running on the web, then this From dd7990953e2c8eed8d5db17f6dc79cd5bee18285 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:16:47 +0100 Subject: [PATCH 02/15] use SurfaceTarget within direct & web backend implementations --- wgpu/src/backend/direct.rs | 141 ++++++++++++----------------- wgpu/src/backend/web.rs | 112 +++++++++++------------ wgpu/src/context.rs | 18 ++-- wgpu/src/lib.rs | 179 +++---------------------------------- 4 files changed, 129 insertions(+), 321 deletions(-) diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 057c4f1453..655a89ed01 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -4,10 +4,11 @@ use crate::{ context::{ObjectId, Unused}, AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BufferBinding, BufferDescriptor, CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, - DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode, Operations, - PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor, - SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, ShaderSource, StoreOp, - SurfaceStatus, TextureDescriptor, TextureViewDescriptor, UncapturedErrorHandler, + CreateSurfaceError, CreateSurfaceErrorKind, DownlevelCapabilities, Features, Label, Limits, + LoadOp, MapMode, Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, + RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleDescriptor, + ShaderModuleDescriptorSpirV, ShaderSource, StoreOp, SurfaceStatus, SurfaceTarget, + TextureDescriptor, TextureViewDescriptor, UncapturedErrorHandler, }; use arrayvec::ArrayVec; @@ -231,81 +232,6 @@ impl Context { self.0.generate_report() } - #[cfg(metal)] - pub unsafe fn create_surface_from_core_animation_layer( - &self, - layer: *mut std::ffi::c_void, - ) -> Surface { - let id = unsafe { self.0.instance_create_surface_metal(layer, ()) }; - Surface { - id, - configured_device: Mutex::default(), - } - } - - #[cfg(any(webgpu, webgl))] - pub fn instance_create_surface_from_canvas( - &self, - canvas: web_sys::HtmlCanvasElement, - ) -> Result { - let id = self.0.create_surface_webgl_canvas(canvas, ())?; - Ok(Surface { - id, - configured_device: Mutex::default(), - }) - } - - #[cfg(any(webgpu, webgl))] - pub fn instance_create_surface_from_offscreen_canvas( - &self, - canvas: web_sys::OffscreenCanvas, - ) -> Result { - let id = self.0.create_surface_webgl_offscreen_canvas(canvas, ())?; - Ok(Surface { - id, - configured_device: Mutex::default(), - }) - } - - #[cfg(dx12)] - pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface { - let id = unsafe { self.0.instance_create_surface_from_visual(visual, ()) }; - Surface { - id, - configured_device: Mutex::default(), - } - } - - #[cfg(dx12)] - pub unsafe fn create_surface_from_surface_handle( - &self, - surface_handle: *mut std::ffi::c_void, - ) -> Surface { - let id = unsafe { - self.0 - .instance_create_surface_from_surface_handle(surface_handle, ()) - }; - Surface { - id, - configured_device: Mutex::default(), - } - } - - #[cfg(dx12)] - pub unsafe fn create_surface_from_swap_chain_panel( - &self, - swap_chain_panel: *mut std::ffi::c_void, - ) -> Surface { - let id = unsafe { - self.0 - .instance_create_surface_from_swap_chain_panel(swap_chain_panel, ()) - }; - Surface { - id, - configured_device: Mutex::default(), - } - } - fn handle_error( &self, sink_mutex: &Mutex, @@ -594,19 +520,64 @@ impl crate::Context for Context { unsafe fn instance_create_surface( &self, - display_handle: raw_window_handle::RawDisplayHandle, - window_handle: raw_window_handle::RawWindowHandle, + target: &SurfaceTarget<'_>, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError> { - let id = unsafe { - self.0 - .instance_create_surface(display_handle, window_handle, ()) + let id = match target { + SurfaceTarget::WindowHandle(window) => { + let raw_display_handle = window + .display_handle() + .map_err(|e| CreateSurfaceError { + inner: CreateSurfaceErrorKind::RawHandle(e), + })? + .as_raw(); + let raw_window_handle = window + .window_handle() + .map_err(|e| CreateSurfaceError { + inner: CreateSurfaceErrorKind::RawHandle(e), + })? + .as_raw(); + + unsafe { + self.0 + .instance_create_surface(raw_display_handle, raw_window_handle, ()) + } + } + + SurfaceTarget::CoreAnimationLayer(layer) => unsafe { + self.0.instance_create_surface_metal(*layer, ()) + }, + + #[cfg(dx12)] + SurfaceTarget::CompositionVisual(visual) => unsafe { + self.0.instance_create_surface_from_visual(*visual, ()) + }, + + #[cfg(dx12)] + SurfaceTarget::SurfaceHandle(surface_handle) => unsafe { + self.0 + .instance_create_surface_from_surface_handle(*surface_handle, ()) + }, + + #[cfg(dx12)] + SurfaceTarget::SwapChainPanel(swap_chain_panel) => unsafe { + self.0 + .instance_create_surface_from_swap_chain_panel(*swap_chain_panel, ()) + }, + + #[cfg(any(webgpu, webgl))] + SurfaceTarget::Canvas(canvas) => self.0.create_surface_webgl_canvas(*canvas, ())?, + + #[cfg(any(webgpu, webgl))] + SurfaceTarget::OffscreenCanvas(canvas) => { + self.0.create_surface_webgl_offscreen_canvas(*canvas, ())? + } }; Ok(( id, Surface { id, - configured_device: Mutex::new(None), + configured_device: Mutex::default(), }, )) } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index ee606e6d9c..5f14301c7c 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -18,7 +18,7 @@ use wasm_bindgen::{prelude::*, JsCast}; use crate::{ context::{downcast_ref, ObjectId, QueueWriteBuffer, Unused}, - UncapturedErrorHandler, + CreateSurfaceError, CreateSurfaceErrorKind, SurfaceTarget, UncapturedErrorHandler, }; fn create_identified(value: T) -> (Identified, Sendable) { @@ -878,35 +878,7 @@ where } impl Context { - pub fn instance_create_surface_from_canvas( - &self, - canvas: web_sys::HtmlCanvasElement, - ) -> Result< - ( - ::SurfaceId, - ::SurfaceData, - ), - crate::CreateSurfaceError, - > { - let result = canvas.get_context("webgpu"); - self.create_surface_from_context(Canvas::Canvas(canvas), result) - } - - pub fn instance_create_surface_from_offscreen_canvas( - &self, - canvas: web_sys::OffscreenCanvas, - ) -> Result< - ( - ::SurfaceId, - ::SurfaceData, - ), - crate::CreateSurfaceError, - > { - let result = canvas.get_context("webgpu"); - self.create_surface_from_context(Canvas::Offscreen(canvas), result) - } - - /// Common portion of public `instance_create_surface_from_*` functions. + /// Common portion of the internal branches of the public `instance_create_surface` function. /// /// Note: Analogous code also exists in the WebGL2 backend at /// `wgpu_hal::gles::web::Instance`. @@ -1068,36 +1040,64 @@ impl crate::context::Context for Context { unsafe fn instance_create_surface( &self, - _display_handle: raw_window_handle::RawDisplayHandle, - window_handle: raw_window_handle::RawWindowHandle, + target: &SurfaceTarget<'_>, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError> { - let canvas_element: web_sys::HtmlCanvasElement = match window_handle { - raw_window_handle::RawWindowHandle::Web(handle) => { - let canvas_node: wasm_bindgen::JsValue = web_sys::window() - .and_then(|win| win.document()) - .and_then(|doc| { - doc.query_selector_all(&format!("[data-raw-handle=\"{}\"]", handle.id)) - .ok() - }) - .and_then(|nodes| nodes.get(0)) - .expect("expected to find single canvas") - .into(); - canvas_node.into() - } - raw_window_handle::RawWindowHandle::WebCanvas(handle) => { - let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; - value.clone().unchecked_into() + match target { + SurfaceTarget::WindowHandle(window) => { + let raw_window_handle = window + .window_handle() + .map_err(|e| CreateSurfaceError { + inner: CreateSurfaceErrorKind::RawHandle(e), + })? + .as_raw(); + + let canvas_element: web_sys::HtmlCanvasElement = match raw_window_handle { + raw_window_handle::RawWindowHandle::Web(handle) => { + let canvas_node: wasm_bindgen::JsValue = web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| { + doc.query_selector_all(&format!( + "[data-raw-handle=\"{}\"]", + handle.id + )) + .ok() + }) + .and_then(|nodes| nodes.get(0)) + .expect("expected to find single canvas") + .into(); + canvas_node.into() + } + raw_window_handle::RawWindowHandle::WebCanvas(handle) => { + let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; + value.clone().unchecked_into() + } + raw_window_handle::RawWindowHandle::WebOffscreenCanvas(handle) => { + let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; + let canvas: web_sys::OffscreenCanvas = value.clone().unchecked_into(); + let context_result = canvas.get_context("webgpu"); + + return self.create_surface_from_context( + Canvas::Offscreen(canvas), + context_result, + ); + } + _ => panic!("expected valid handle for canvas"), + }; + + let context_result = canvas_element.get_context("webgpu"); + self.create_surface_from_context(Canvas::Canvas(canvas_element), context_result) } - raw_window_handle::RawWindowHandle::WebOffscreenCanvas(handle) => { - let value: &JsValue = unsafe { handle.obj.cast().as_ref() }; - let canvas: web_sys::OffscreenCanvas = value.clone().unchecked_into(); - return self.instance_create_surface_from_offscreen_canvas(canvas); + SurfaceTarget::Canvas(canvas) => { + let context_result = canvas.get_context("webgpu"); + self.create_surface_from_context(Canvas::Canvas(canvas.clone()), context_result) } - _ => panic!("expected valid handle for canvas"), - }; - self.instance_create_surface_from_canvas(canvas_element) + SurfaceTarget::OffscreenCanvas(canvas) => { + let context_result = canvas.get_context("webgpu"); + self.create_surface_from_context(Canvas::Offscreen(canvas.clone()), context_result) + } + } } fn instance_request_adapter( @@ -2146,7 +2146,7 @@ impl crate::context::Context for Context { _pipeline_layout: &Self::PipelineLayoutId, _pipeline_layout_data: &Self::PipelineLayoutData, ) { - // Dropped automatically + // Dropped automaticaly } fn shader_module_drop( diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 785bba6114..9b79ab54e8 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -14,7 +14,7 @@ use crate::{ PipelineLayoutDescriptor, QuerySetDescriptor, RenderBundleDescriptor, RenderBundleEncoderDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, RequestAdapterOptions, RequestDeviceError, SamplerDescriptor, ShaderModuleDescriptor, - ShaderModuleDescriptorSpirV, Texture, TextureDescriptor, TextureViewDescriptor, + ShaderModuleDescriptorSpirV, SurfaceTarget, Texture, TextureDescriptor, TextureViewDescriptor, UncapturedErrorHandler, }; @@ -98,8 +98,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { fn init(instance_desc: wgt::InstanceDescriptor) -> Self; unsafe fn instance_create_surface( &self, - display_handle: raw_window_handle::RawDisplayHandle, - window_handle: raw_window_handle::RawWindowHandle, + target: &SurfaceTarget<'_>, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError>; fn instance_request_adapter( &self, @@ -1141,10 +1140,9 @@ pub type DeviceLostCallback = Box; pub(crate) trait DynContext: Debug + WasmNotSendSync { fn as_any(&self) -> &dyn Any; - unsafe fn instance_create_surface( + fn instance_create_surface( &self, - display_handle: raw_window_handle::RawDisplayHandle, - window_handle: raw_window_handle::RawWindowHandle, + target: &SurfaceTarget<'_>, ) -> Result<(ObjectId, Box), crate::CreateSurfaceError>; #[allow(clippy::type_complexity)] fn instance_request_adapter( @@ -1999,13 +1997,11 @@ where self } - unsafe fn instance_create_surface( + fn instance_create_surface( &self, - display_handle: raw_window_handle::RawDisplayHandle, - window_handle: raw_window_handle::RawWindowHandle, + target: &SurfaceTarget<'_>, ) -> Result<(ObjectId, Box), crate::CreateSurfaceError> { - let (surface, data) = - unsafe { Context::instance_create_surface(self, display_handle, window_handle) }?; + let (surface, data) = unsafe { Context::instance_create_surface(self, target) }?; Ok((surface.into(), Box::new(data) as _)) } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index b8543f5232..20c527ad66 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -435,6 +435,8 @@ pub enum SurfaceTarget<'window> { /// - On macOS/Metal: surface creation will panic if not called on the main thread. /// - On web: surface creation will panic if the `raw_window_handle` does not properly refer to a /// canvas element. + /// - the window handle must remain valid until after the [`Surface`] returned on creation is + /// dropped. WindowHandle(Box), /// Surface from `CoreAnimationLayer`. @@ -1842,179 +1844,18 @@ impl Instance { &self, target: impl Into>, ) -> Result, CreateSurfaceError> { - match target.into() { - SurfaceTarget::WindowHandle(window) => { - let mut surface = unsafe { self.create_surface_from_raw(&window) }?; - surface._surface = Some(window); - Ok(surface) - } - - #[cfg(metal)] - SurfaceTarget::CoreAnimationLayer(layer) => { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_core_animation_layer(layer) - }; - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - }) - } - - #[cfg(dx12)] - SurfaceTarget::CompositionVisual(visual) => { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_visual(visual) - }; - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - }) - } - - #[cfg(dx12)] - SurfaceTarget::SurfaceHandle(surface_handle) => { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_surface_handle(surface_handle) - }; - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - }) - } - - #[cfg(dx12)] - SurfaceTarget::SwapChainPanel(swap_chain_panel) => { - let surface = unsafe { - self.context - .as_any() - .downcast_ref::() - .unwrap() - .create_surface_from_swap_chain_panel(swap_chain_panel) - }; - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - id: ObjectId::from(surface.id()), - data: Box::new(surface), - config: Mutex::new(None), - }) - } - - #[cfg(any(webgpu, webgl))] - SurfaceTarget::Canvas(canvas) => { - let surface = self - .context - .as_any() - .downcast_ref::() - .unwrap() - .instance_create_surface_from_canvas(canvas)?; - - // TODO: This is ugly, a way to create things from a native context needs to be made nicer. - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - #[cfg(webgl)] - id: ObjectId::from(surface.id()), - #[cfg(webgl)] - data: Box::new(surface), - #[cfg(webgpu)] - id: ObjectId::UNUSED, - #[cfg(webgpu)] - data: Box::new(surface.1), - config: Mutex::new(None), - }) - } + let target = target.into(); - #[cfg(any(webgpu, webgl))] - SurfaceTarget::OffscreenCanvas(canvas) => { - let surface = self - .context - .as_any() - .downcast_ref::() - .unwrap() - .instance_create_surface_from_offscreen_canvas(canvas)?; - - // TODO: This is ugly, a way to create things from a native context needs to be made nicer. - Ok(Surface { - context: Arc::clone(&self.context), - _surface: None, - #[cfg(webgl)] - id: ObjectId::from(surface.id()), - #[cfg(webgl)] - data: Box::new(surface), - #[cfg(webgpu)] - id: ObjectId::UNUSED, - #[cfg(webgpu)] - data: Box::new(surface.1), - config: Mutex::new(None), - }) - } - } - } + let (id, data) = self.context.instance_create_surface(&target)?; + let _surface = if let SurfaceTarget::WindowHandle(window) = target { + Some(window) + } else { + None + }; - /// An alternative version to [`create_surface()`](Self::create_surface) - /// with [`SurfaceTargetCanvas::WindowHandle`] - /// which has no lifetime requirements to `window` and doesn't require - /// [`Send`] or [`Sync`] (on non-Wasm targets). This makes it `unsafe` - /// instead and always returns a [`Surface<'static>`]. - /// - /// See [`create_surface()`](Self::create_surface) for more details. - /// - /// # Safety - /// - /// - `raw_window_handle` must be a valid object to create a surface upon. - /// - `raw_window_handle` must remain valid until after the returned [`Surface`] is - /// dropped. - pub unsafe fn create_surface_from_raw( - &self, - window: &W, - ) -> Result, CreateSurfaceError> - where - W: HasWindowHandle + HasDisplayHandle, - { - let raw_display_handle = window - .display_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - let raw_window_handle = window - .window_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - let (id, data) = unsafe { - DynContext::instance_create_surface( - &*self.context, - raw_display_handle, - raw_window_handle, - ) - }?; Ok(Surface { context: Arc::clone(&self.context), - _surface: None, + _surface, id, data, config: Mutex::new(None), From 547bc001252c879f088bf2089944a92453aee4dc Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:17:37 +0100 Subject: [PATCH 03/15] changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e4cae9ca0..0d8d9ccd70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,14 @@ This feature allowed you to call `global_id` on any wgpu opaque handle to get a Wgpu now exposes backend feature for the Direct3D 12 (`dx12`) and Metal (`metal`) backend. These are enabled by default, but don't do anything when not targetting the corresponding OS. By @daxpedda in [#4815](https://github.com/gfx-rs/wgpu/pull/4815) +### Unified surface creation + +Previously, there were various specialized surface creation functions for various platform specific handles. +Now, `wgpu::Instance::create_surface` instead always take a value that can be converted to the unified `wgpu::SurfaceTarget` enum. +Conversion is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, +meaning that you can continue to e.g. pass references to winit windows as before. +By @wumpf in [#????](https://github.com/gfx-rs/wgpu/pull/????) + ### New Features #### General From 67c29bf1669670e408eed303e32fdd45e8f553ca Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:24:41 +0100 Subject: [PATCH 04/15] fix missing #[cfg(metal)] & incorrect canvas passing --- wgpu/src/backend/direct.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 655a89ed01..adc96fe783 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -543,6 +543,7 @@ impl crate::Context for Context { } } + #[cfg(metal)] SurfaceTarget::CoreAnimationLayer(layer) => unsafe { self.0.instance_create_surface_metal(*layer, ()) }, @@ -565,12 +566,14 @@ impl crate::Context for Context { }, #[cfg(any(webgpu, webgl))] - SurfaceTarget::Canvas(canvas) => self.0.create_surface_webgl_canvas(*canvas, ())?, + SurfaceTarget::Canvas(canvas) => { + self.0.create_surface_webgl_canvas(canvas.clone(), ())? + } #[cfg(any(webgpu, webgl))] - SurfaceTarget::OffscreenCanvas(canvas) => { - self.0.create_surface_webgl_offscreen_canvas(*canvas, ())? - } + SurfaceTarget::OffscreenCanvas(canvas) => self + .0 + .create_surface_webgl_offscreen_canvas(canvas.clone(), ())?, }; Ok(( From 25dfb5843af2376112f36bf2cdb56b7aed52625a Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:35:43 +0100 Subject: [PATCH 05/15] improve doc --- wgpu/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 20c527ad66..3332331698 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1836,7 +1836,9 @@ impl Instance { } } - /// Creates a new surface drawing to the target specified via the [`SurfaceTarget`] enum. + /// Creates a new surface targeting a given window/canvas/surface/etc.. + /// + /// See [`SurfaceTarget`] for what targets for surface are supported. /// /// Most commonly used are window handles (or provider of windows handles) /// which can be passed directly as they're automatically converted to [`SurfaceTarget`]. From 4d6e75a17a78af5932f0a87354ac15bc7e579716 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:39:10 +0100 Subject: [PATCH 06/15] changelog pr number update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d8d9ccd70..d6b03d8ed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,7 +65,7 @@ Previously, there were various specialized surface creation functions for variou Now, `wgpu::Instance::create_surface` instead always take a value that can be converted to the unified `wgpu::SurfaceTarget` enum. Conversion is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, meaning that you can continue to e.g. pass references to winit windows as before. -By @wumpf in [#????](https://github.com/gfx-rs/wgpu/pull/????) +By @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984) ### New Features From d1782711cd079c1cd37b3ec8e6347b9c575866f4 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:43:41 +0100 Subject: [PATCH 07/15] warning fix for some platforms --- wgpu/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 3332331698..91b68148b4 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1849,6 +1849,8 @@ impl Instance { let target = target.into(); let (id, data) = self.context.instance_create_surface(&target)?; + + #[allow(irrefutable_let_patterns)] let _surface = if let SurfaceTarget::WindowHandle(window) = target { Some(window) } else { From 6c9c63a8cb7fec2603e59a65f1fab77d3dc277e7 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:56:33 +0100 Subject: [PATCH 08/15] doc fix --- wgpu/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 91b68148b4..94ca05782e 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -409,7 +409,7 @@ impl Drop for Surface<'_> { } } -/// Super trait for window handles as used in [`SurfaceTargetCanvas`]. +/// Super trait for window handles as used in [`SurfaceTarget`]. pub trait WindowHandle: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} impl WindowHandle for T where T: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} From bfc8e7e39c1991b38a73c7263fe0ffc99d4dab99 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 4 Jan 2024 16:59:58 +0100 Subject: [PATCH 09/15] fix wasm test compilation --- tests/src/init.rs | 2 +- tests/tests/create_surface_error.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/init.rs b/tests/src/init.rs index 4615516b50..6a24f5faec 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -51,7 +51,7 @@ pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Opt let canvas = initialize_html_canvas(); _surface = instance - .create_surface_from_canvas(canvas.clone()) + .create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone())) .expect("could not create surface from canvas"); surface_guard = Some(SurfaceGuard { canvas }); diff --git a/tests/tests/create_surface_error.rs b/tests/tests/create_surface_error.rs index 9749642f2f..87aeb15726 100644 --- a/tests/tests/create_surface_error.rs +++ b/tests/tests/create_surface_error.rs @@ -1,6 +1,6 @@ //! Test that `create_surface_*()` accurately reports those errors we can provoke. -/// This test applies to those cfgs that have a `create_surface_from_canvas` method, which +/// This test applies to those cfgs that can create a surface from a canvas, which /// include WebGL and WebGPU, but *not* Emscripten GLES. #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] #[wasm_bindgen_test::wasm_bindgen_test] @@ -15,7 +15,7 @@ fn canvas_get_context_returned_null() { #[allow(clippy::redundant_clone)] // false positive — can't and shouldn't move out. let error = instance - .create_surface_from_canvas(canvas.clone()) + .create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone())) .unwrap_err(); assert!( From 0c390f61c6ff9985258cf5afd722ee5d7c0d9976 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 10 Jan 2024 00:20:54 +0100 Subject: [PATCH 10/15] split SurfaceTarget into SurfaceTarget & SurfaceTargetUnsafe. backends only use SurfaceTargetUnsafe --- wgpu-core/src/instance.rs | 72 -------------- wgpu/src/backend/direct.rs | 58 ++++------- wgpu/src/backend/web.rs | 26 ++--- wgpu/src/context.rs | 14 +-- wgpu/src/lib.rs | 196 +++++++++++++++++++++++++++---------- 5 files changed, 178 insertions(+), 188 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 7a12d98a6d..232b68fd90 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -578,78 +578,6 @@ impl Global { id } - #[cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - feature = "gles" - ))] - pub fn create_surface_webgl_canvas( - &self, - canvas: web_sys::HtmlCanvasElement, - id_in: Input, - ) -> Result { - profiling::scope!("Instance::create_surface_webgl_canvas"); - - let surface = Surface { - presentation: Mutex::new(None), - info: ResourceInfo::new(""), - raw: { - let hal_surface: HalSurface = self - .instance - .gl - .as_ref() - .map(|inst| { - let raw_surface = inst.create_surface_from_canvas(canvas)?; - Ok(HalSurface { - raw: Arc::new(raw_surface), - }) - }) - .transpose()? - .unwrap(); - AnySurface::new(hal_surface) - }, - }; - - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); - Ok(id) - } - - #[cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - feature = "gles" - ))] - pub fn create_surface_webgl_offscreen_canvas( - &self, - canvas: web_sys::OffscreenCanvas, - id_in: Input, - ) -> Result { - profiling::scope!("Instance::create_surface_webgl_offscreen_canvas"); - - let surface = Surface { - presentation: Mutex::new(None), - info: ResourceInfo::new(""), - raw: { - let hal_surface: HalSurface = self - .instance - .gl - .as_ref() - .map(|inst| { - let raw_surface = inst.create_surface_from_offscreen_canvas(canvas)?; - Ok(HalSurface { - raw: Arc::new(raw_surface), - }) - }) - .transpose()? - .unwrap(); - AnySurface::new(hal_surface) - }, - }; - - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); - Ok(id) - } - #[cfg(all(feature = "dx12", windows))] /// # Safety /// diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index adc96fe783..6a7775be7e 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -4,11 +4,11 @@ use crate::{ context::{ObjectId, Unused}, AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BufferBinding, BufferDescriptor, CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, - CreateSurfaceError, CreateSurfaceErrorKind, DownlevelCapabilities, Features, Label, Limits, - LoadOp, MapMode, Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, - RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleDescriptor, - ShaderModuleDescriptorSpirV, ShaderSource, StoreOp, SurfaceStatus, SurfaceTarget, - TextureDescriptor, TextureViewDescriptor, UncapturedErrorHandler, + DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode, Operations, + PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor, + SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, ShaderSource, StoreOp, + SurfaceStatus, SurfaceTargetUnsafe, TextureDescriptor, TextureViewDescriptor, + UncapturedErrorHandler, }; use arrayvec::ArrayVec; @@ -520,60 +520,38 @@ impl crate::Context for Context { unsafe fn instance_create_surface( &self, - target: &SurfaceTarget<'_>, + target: SurfaceTargetUnsafe, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError> { let id = match target { - SurfaceTarget::WindowHandle(window) => { - let raw_display_handle = window - .display_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - let raw_window_handle = window - .window_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - - unsafe { - self.0 - .instance_create_surface(raw_display_handle, raw_window_handle, ()) - } - } + SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + } => unsafe { + self.0 + .instance_create_surface(raw_display_handle, raw_window_handle, ()) + }, #[cfg(metal)] - SurfaceTarget::CoreAnimationLayer(layer) => unsafe { - self.0.instance_create_surface_metal(*layer, ()) + SurfaceTargetUnsafe::CoreAnimationLayer(layer) => unsafe { + self.0.instance_create_surface_metal(layer, ()) }, #[cfg(dx12)] - SurfaceTarget::CompositionVisual(visual) => unsafe { + SurfaceTargetUnsafe::CompositionVisual(visual) => unsafe { self.0.instance_create_surface_from_visual(*visual, ()) }, #[cfg(dx12)] - SurfaceTarget::SurfaceHandle(surface_handle) => unsafe { + SurfaceTargetUnsafe::SurfaceHandle(surface_handle) => unsafe { self.0 .instance_create_surface_from_surface_handle(*surface_handle, ()) }, #[cfg(dx12)] - SurfaceTarget::SwapChainPanel(swap_chain_panel) => unsafe { + SurfaceTargetUnsafe::SwapChainPanel(swap_chain_panel) => unsafe { self.0 .instance_create_surface_from_swap_chain_panel(*swap_chain_panel, ()) }, - - #[cfg(any(webgpu, webgl))] - SurfaceTarget::Canvas(canvas) => { - self.0.create_surface_webgl_canvas(canvas.clone(), ())? - } - - #[cfg(any(webgpu, webgl))] - SurfaceTarget::OffscreenCanvas(canvas) => self - .0 - .create_surface_webgl_offscreen_canvas(canvas.clone(), ())?, }; Ok(( diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 5f14301c7c..705d33dcca 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -18,7 +18,7 @@ use wasm_bindgen::{prelude::*, JsCast}; use crate::{ context::{downcast_ref, ObjectId, QueueWriteBuffer, Unused}, - CreateSurfaceError, CreateSurfaceErrorKind, SurfaceTarget, UncapturedErrorHandler, + SurfaceTargetUnsafe, UncapturedErrorHandler, }; fn create_identified(value: T) -> (Identified, Sendable) { @@ -1040,17 +1040,13 @@ impl crate::context::Context for Context { unsafe fn instance_create_surface( &self, - target: &SurfaceTarget<'_>, + target: SurfaceTargetUnsafe, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError> { match target { - SurfaceTarget::WindowHandle(window) => { - let raw_window_handle = window - .window_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - + SurfaceTargetUnsafe::RawHandle { + raw_display_handle: _, + raw_window_handle, + } => { let canvas_element: web_sys::HtmlCanvasElement = match raw_window_handle { raw_window_handle::RawWindowHandle::Web(handle) => { let canvas_node: wasm_bindgen::JsValue = web_sys::window() @@ -1087,16 +1083,6 @@ impl crate::context::Context for Context { let context_result = canvas_element.get_context("webgpu"); self.create_surface_from_context(Canvas::Canvas(canvas_element), context_result) } - - SurfaceTarget::Canvas(canvas) => { - let context_result = canvas.get_context("webgpu"); - self.create_surface_from_context(Canvas::Canvas(canvas.clone()), context_result) - } - - SurfaceTarget::OffscreenCanvas(canvas) => { - let context_result = canvas.get_context("webgpu"); - self.create_surface_from_context(Canvas::Offscreen(canvas.clone()), context_result) - } } } diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 9b79ab54e8..2221921623 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -14,8 +14,8 @@ use crate::{ PipelineLayoutDescriptor, QuerySetDescriptor, RenderBundleDescriptor, RenderBundleEncoderDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, RequestAdapterOptions, RequestDeviceError, SamplerDescriptor, ShaderModuleDescriptor, - ShaderModuleDescriptorSpirV, SurfaceTarget, Texture, TextureDescriptor, TextureViewDescriptor, - UncapturedErrorHandler, + ShaderModuleDescriptorSpirV, SurfaceTargetUnsafe, Texture, TextureDescriptor, + TextureViewDescriptor, UncapturedErrorHandler, }; /// Meta trait for an id tracked by a context. @@ -98,7 +98,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { fn init(instance_desc: wgt::InstanceDescriptor) -> Self; unsafe fn instance_create_surface( &self, - target: &SurfaceTarget<'_>, + target: SurfaceTargetUnsafe, ) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError>; fn instance_request_adapter( &self, @@ -1140,9 +1140,9 @@ pub type DeviceLostCallback = Box; pub(crate) trait DynContext: Debug + WasmNotSendSync { fn as_any(&self) -> &dyn Any; - fn instance_create_surface( + unsafe fn instance_create_surface( &self, - target: &SurfaceTarget<'_>, + target: SurfaceTargetUnsafe, ) -> Result<(ObjectId, Box), crate::CreateSurfaceError>; #[allow(clippy::type_complexity)] fn instance_request_adapter( @@ -1997,9 +1997,9 @@ where self } - fn instance_create_surface( + unsafe fn instance_create_surface( &self, - target: &SurfaceTarget<'_>, + target: SurfaceTargetUnsafe, ) -> Result<(ObjectId, Box), crate::CreateSurfaceError> { let (surface, data) = unsafe { Context::instance_create_surface(self, target) }?; Ok((surface.into(), Box::new(data) as _)) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 94ca05782e..f22f00275b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -414,30 +414,92 @@ pub trait WindowHandle: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} impl WindowHandle for T where T: HasWindowHandle + HasDisplayHandle + WasmNotSendSync {} -/// The window/canvas/surface/swap-chain/etc. a surface is attached to. +/// The window/canvas/surface/swap-chain/etc. a surface is attached to, for use with safe surface creation. /// /// This is either a window or an actual web canvas depending on the platform and /// enabled features. /// Refer to the individual variants for more information. +/// +/// See also [`SurfaceTargetUnsafe`] for unsafe variants. +#[non_exhaustive] pub enum SurfaceTarget<'window> { - /// Raw window handle. + /// Window handle producer. /// /// If the specified display and window handle are not supported by any of the backends, then the surface /// will not be supported by any adapters. /// /// # Errors /// - /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// - On WebGL2: surface creation returns an error if the browser does not support WebGL2, /// or declines to provide GPU access (such as due to a resource shortage). /// /// # Panics /// - /// - On macOS/Metal: surface creation will panic if not called on the main thread. - /// - On web: surface creation will panic if the `raw_window_handle` does not properly refer to a + /// - On macOS/Metal: will panic if not called on the main thread. + /// - On web: will panic if the `raw_window_handle` does not properly refer to a /// canvas element. - /// - the window handle must remain valid until after the [`Surface`] returned on creation is - /// dropped. - WindowHandle(Box), + Window(Box), + + /// Surface from a `web_sys::HtmlCanvasElement`. + /// + /// The `canvas` argument must be a valid `` element to + /// create a surface upon. + /// + /// # Errors + /// + /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// or declines to provide GPU access (such as due to a resource shortage). + #[cfg(any(webgpu, webgl))] + Canvas(web_sys::HtmlCanvasElement), + + /// Surface from a `web_sys::OffscreenCanvas`. + /// + /// The `canvas` argument must be a valid `OffscreenCanvas` object + /// to create a surface upon. + /// + /// # Errors + /// + /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, + /// or declines to provide GPU access (such as due to a resource shortage). + #[cfg(any(webgpu, webgl))] + OffscreenCanvas(web_sys::OffscreenCanvas), +} + +impl<'a, T> From for SurfaceTarget<'a> +where + T: WindowHandle + 'a, +{ + fn from(window: T) -> Self { + Self::Window(Box::new(window)) + } +} + +/// The window/canvas/surface/swap-chain/etc. a surface is attached to, for use with unsafe surface creation. +/// +/// This is either a window or an actual web canvas depending on the platform and +/// enabled features. +/// Refer to the individual variants for more information. +/// +/// See also [`SurfaceTarget`] for safe variants. +#[non_exhaustive] +pub enum SurfaceTargetUnsafe { + /// Raw window & display handle. + /// + /// If the specified display and window handle are not supported by any of the backends, then the surface + /// will not be supported by any adapters. + /// + /// # Safety + /// + /// - `raw_window_handle` & `raw_display_handle` must be valid objects to create a surface upon. + /// - `raw_window_handle` & `raw_display_handle` must remain valid until after the returned + /// [`Surface`] is dropped. + RawHandle { + /// Raw display handle, underlying display must outlive the surface created from this. + raw_display_handle: raw_window_handle::RawDisplayHandle, + + /// Raw display handle, underlying window must outlive the surface created from this. + raw_window_handle: raw_window_handle::RawWindowHandle, + }, /// Surface from `CoreAnimationLayer`. /// @@ -470,39 +532,6 @@ pub enum SurfaceTarget<'window> { /// - visual must be a valid SwapChainPanel to create a surface upon. #[cfg(dx12)] SwapChainPanel(*mut std::ffi::c_void), - - /// Surface from a `web_sys::HtmlCanvasElement`. - /// - /// The `canvas` argument must be a valid `` element to - /// create a surface upon. - /// - /// # Errors - /// - /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, - /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] - Canvas(web_sys::HtmlCanvasElement), - - /// Surface from a `web_sys::OffscreenCanvas`. - /// - /// The `canvas` argument must be a valid `OffscreenCanvas` object - /// to create a surface upon. - /// - /// # Errors - /// - /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, - /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] - OffscreenCanvas(web_sys::OffscreenCanvas), -} - -impl<'a, T> From for SurfaceTarget<'a> -where - T: WindowHandle + 'a, -{ - fn from(handle: T) -> Self { - Self::WindowHandle(Box::new(handle)) - } } /// Handle to a binding group layout. @@ -1838,7 +1867,8 @@ impl Instance { /// Creates a new surface targeting a given window/canvas/surface/etc.. /// - /// See [`SurfaceTarget`] for what targets for surface are supported. + /// See [`SurfaceTarget`] for what targets are supported. + /// See [`Instance::create_surface`] for surface creation with unsafe target variants. /// /// Most commonly used are window handles (or provider of windows handles) /// which can be passed directly as they're automatically converted to [`SurfaceTarget`]. @@ -1846,20 +1876,88 @@ impl Instance { &self, target: impl Into>, ) -> Result, CreateSurfaceError> { + // Handle origin (i.e. window) to optionally take ownership of to make the surface outlast the window. + let handle_origin; + let target = target.into(); + let unsafe_target = match target { + SurfaceTarget::Window(window) => { + let raw_display_handle = window + .display_handle() + .map_err(|e| CreateSurfaceError { + inner: CreateSurfaceErrorKind::RawHandle(e), + })? + .as_raw(); + let raw_window_handle = window + .window_handle() + .map_err(|e| CreateSurfaceError { + inner: CreateSurfaceErrorKind::RawHandle(e), + })? + .as_raw(); + + handle_origin = Some(window); + + SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + } + } - let (id, data) = self.context.instance_create_surface(&target)?; + #[cfg(any(webgpu, webgl))] + SurfaceTarget::Canvas(canvas) => { + handle_origin = None; - #[allow(irrefutable_let_patterns)] - let _surface = if let SurfaceTarget::WindowHandle(window) = target { - Some(window) - } else { - None + let value: &wasm_bindgen::JsValue = &canvas; + let obj = std::ptr::NonNull::from(value).cast(); + let raw_window_handle = raw_window_handle::WebCanvasWindowHandle::new(obj).into(); + let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into(); + + SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + } + } + + #[cfg(any(webgpu, webgl))] + SurfaceTarget::OffscreenCanvas(canvas) => { + handle_origin = None; + + let value: &wasm_bindgen::JsValue = &canvas; + let obj = std::ptr::NonNull::from(value).cast(); + let raw_window_handle = + raw_window_handle::WebOffscreenCanvasWindowHandle::new(obj).into(); + let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into(); + + SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + } + } }; + let mut surface = unsafe { self.create_surface_unsafe(unsafe_target) }?; + surface._surface = handle_origin; + + Ok(surface) + } + + /// Creates a new surface targeting a given window/canvas/surface/etc. using an unsafe target. + /// + /// See [`SurfaceTargetUnsafe`] for what targets are supported. + /// See [`Instance::create_surface`] for surface creation with safe target variants. + /// + /// # Safety + /// + /// - See respective [`SurfaceTargetUnsafe`] variants for safety requirements. + pub unsafe fn create_surface_unsafe<'window>( + &self, + target: SurfaceTargetUnsafe, + ) -> Result, CreateSurfaceError> { + let (id, data) = unsafe { self.context.instance_create_surface(target) }?; + Ok(Surface { context: Arc::clone(&self.context), - _surface, + _surface: None, id, data, config: Mutex::new(None), From d37c0f68971407a0c63a19a4f62fcffb6e123f48 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 10 Jan 2024 00:23:47 +0100 Subject: [PATCH 11/15] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b03d8ed8..3adfa5f44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,8 +62,8 @@ Wgpu now exposes backend feature for the Direct3D 12 (`dx12`) and Metal (`metal` ### Unified surface creation Previously, there were various specialized surface creation functions for various platform specific handles. -Now, `wgpu::Instance::create_surface` instead always take a value that can be converted to the unified `wgpu::SurfaceTarget` enum. -Conversion is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, +Now, `wgpu::Instance::create_surface` & `wgpu::Instance::create_surface_unsafe` instead each take a value that can be converted to the unified `wgpu::SurfaceTarget`/`wgpu::SurfaceTargetUnsafe` enums. +Conversion to `wgpu::SurfaceTarget` is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, meaning that you can continue to e.g. pass references to winit windows as before. By @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984) From ef5abe32b6bd3eab3ece509c6725fa9e26745d5b Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 10 Jan 2024 00:43:34 +0100 Subject: [PATCH 12/15] fix incorrect dereference on windows --- wgpu/src/backend/direct.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 6a7775be7e..c9efec3f75 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -538,19 +538,19 @@ impl crate::Context for Context { #[cfg(dx12)] SurfaceTargetUnsafe::CompositionVisual(visual) => unsafe { - self.0.instance_create_surface_from_visual(*visual, ()) + self.0.instance_create_surface_from_visual(visual, ()) }, #[cfg(dx12)] SurfaceTargetUnsafe::SurfaceHandle(surface_handle) => unsafe { self.0 - .instance_create_surface_from_surface_handle(*surface_handle, ()) + .instance_create_surface_from_surface_handle(surface_handle, ()) }, #[cfg(dx12)] SurfaceTargetUnsafe::SwapChainPanel(swap_chain_panel) => unsafe { self.0 - .instance_create_surface_from_swap_chain_panel(*swap_chain_panel, ()) + .instance_create_surface_from_swap_chain_panel(swap_chain_panel, ()) }, }; From b666de78464a5ee99f3b40b439feacb0b397154f Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 10 Jan 2024 18:26:50 +0100 Subject: [PATCH 13/15] fix webgl crash --- wgpu/src/lib.rs | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index f22f00275b..7d55d72e71 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1880,7 +1880,7 @@ impl Instance { let handle_origin; let target = target.into(); - let unsafe_target = match target { + let mut surface = match target { SurfaceTarget::Window(window) => { let raw_display_handle = window .display_handle() @@ -1897,10 +1897,12 @@ impl Instance { handle_origin = Some(window); - SurfaceTargetUnsafe::RawHandle { - raw_display_handle, - raw_window_handle, - } + unsafe { + self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + }) + }? } #[cfg(any(webgpu, webgl))] @@ -1912,10 +1914,14 @@ impl Instance { let raw_window_handle = raw_window_handle::WebCanvasWindowHandle::new(obj).into(); let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into(); - SurfaceTargetUnsafe::RawHandle { - raw_display_handle, - raw_window_handle, - } + // Note that we need to call this while we still have `value` around. + // This is safe without storing canvas to `handle_origin` since the surface will create a copy internally. + unsafe { + self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + }) + }? } #[cfg(any(webgpu, webgl))] @@ -1928,14 +1934,17 @@ impl Instance { raw_window_handle::WebOffscreenCanvasWindowHandle::new(obj).into(); let raw_display_handle = raw_window_handle::WebDisplayHandle::new().into(); - SurfaceTargetUnsafe::RawHandle { - raw_display_handle, - raw_window_handle, - } + // Note that we need to call this while we still have `value` around. + // This is safe without storing canvas to `handle_origin` since the surface will create a copy internally. + unsafe { + self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle { + raw_display_handle, + raw_window_handle, + }) + }? } }; - let mut surface = unsafe { self.create_surface_unsafe(unsafe_target) }?; surface._surface = handle_origin; Ok(surface) From 656c79a7f3f2989afd0ebb545e22ce09f7c26188 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 10 Jan 2024 18:43:46 +0100 Subject: [PATCH 14/15] forward wgpu-core surface creation errors --- player/src/bin/play.rs | 3 +- wgpu-core/src/instance.rs | 71 ++++++++++++++++---------------------- wgpu/src/backend/direct.rs | 2 +- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 3a05511b80..cc62010fbb 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -63,7 +63,8 @@ fn main() { window.window_handle().unwrap().into(), wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty), ) - }; + } + .unwrap(); let device = match actions.pop() { Some(trace::Action::Init { desc, backend }) => { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 3def7b6164..2101fb8edc 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -479,68 +479,55 @@ impl Global { display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, id_in: Input, - ) -> SurfaceId { + ) -> Result { profiling::scope!("Instance::create_surface"); fn init( - any_surface: &mut Option, inst: &Option, display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, - ) { - if any_surface.is_none() { - if let Some(surface) = inst.as_ref().and_then(|inst| unsafe { - match inst.create_surface(display_handle, window_handle) { - Ok(raw) => Some(HalSurface:: { raw: Arc::new(raw) }), - Err(e) => { - log::warn!("Error: {:?}", e); - None - } - } - }) { - *any_surface = Some(AnySurface::new(surface)); + ) -> Option> { + inst.as_ref().map(|inst| unsafe { + match inst.create_surface(display_handle, window_handle) { + Ok(raw) => Ok(AnySurface::new(HalSurface:: { raw: Arc::new(raw) })), + Err(e) => Err(e), } - } + }) } - let mut hal_surface = None; + let mut hal_surface: Option> = None; + #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] - init::( - &mut hal_surface, - &self.instance.vulkan, - display_handle, - window_handle, - ); + if hal_surface.is_none() { + hal_surface = + init::(&self.instance.vulkan, display_handle, window_handle); + } #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] - init::( - &mut hal_surface, - &self.instance.metal, - display_handle, - window_handle, - ); + if hal_surface.is_none() { + hal_surface = + init::(&self.instance.metal, display_handle, window_handle); + } #[cfg(all(feature = "dx12", windows))] - init::( - &mut hal_surface, - &self.instance.dx12, - display_handle, - window_handle, - ); + if hal_surface.is_none() { + hal_surface = + init::(&self.instance.dx12, display_handle, window_handle); + } #[cfg(feature = "gles")] - init::( - &mut hal_surface, - &self.instance.gl, - display_handle, - window_handle, - ); + if hal_surface.is_none() { + hal_surface = init::(&self.instance.gl, display_handle, window_handle); + } + + // This is only None if there's no instance at all. + let hal_surface = hal_surface.unwrap()?; let surface = Surface { presentation: Mutex::new(None), info: ResourceInfo::new(""), - raw: hal_surface.unwrap(), + raw: hal_surface, }; let (id, _) = self.surfaces.prepare::(id_in).assign(surface); - id + Ok(id) } /// # Safety diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index c9efec3f75..05a0db4263 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -528,7 +528,7 @@ impl crate::Context for Context { raw_window_handle, } => unsafe { self.0 - .instance_create_surface(raw_display_handle, raw_window_handle, ()) + .instance_create_surface(raw_display_handle, raw_window_handle, ())? }, #[cfg(metal)] From b5192e803b1b342e3ce71afe1a7216cb2bb0b0e8 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 11 Jan 2024 15:41:44 +0100 Subject: [PATCH 15/15] add SurfaceTargetUnsafe::from_window utility --- wgpu/src/lib.rs | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7d55d72e71..0c65a43100 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -534,6 +534,24 @@ pub enum SurfaceTargetUnsafe { SwapChainPanel(*mut std::ffi::c_void), } +impl SurfaceTargetUnsafe { + /// Creates a [`SurfaceTargetUnsafe::RawHandle`] from a window. + /// + /// # Safety + /// + /// - `window` must outlive the resulting surface target + /// (and subsequently the surface created for this target). + pub unsafe fn from_window(window: &T) -> Result + where + T: HasDisplayHandle + HasWindowHandle, + { + Ok(Self::RawHandle { + raw_display_handle: window.display_handle()?.as_raw(), + raw_window_handle: window.window_handle()?.as_raw(), + }) + } +} + /// Handle to a binding group layout. /// /// A `BindGroupLayout` is a handle to the GPU-side layout of a binding group. It can be used to @@ -1881,29 +1899,16 @@ impl Instance { let target = target.into(); let mut surface = match target { - SurfaceTarget::Window(window) => { - let raw_display_handle = window - .display_handle() - .map_err(|e| CreateSurfaceError { - inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - let raw_window_handle = window - .window_handle() - .map_err(|e| CreateSurfaceError { + SurfaceTarget::Window(window) => unsafe { + let surface = self.create_surface_unsafe( + SurfaceTargetUnsafe::from_window(&window).map_err(|e| CreateSurfaceError { inner: CreateSurfaceErrorKind::RawHandle(e), - })? - .as_raw(); - + })?, + ); handle_origin = Some(window); - unsafe { - self.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle { - raw_display_handle, - raw_window_handle, - }) - }? - } + surface + }?, #[cfg(any(webgpu, webgl))] SurfaceTarget::Canvas(canvas) => {