Skip to content

Commit 4fd4a71

Browse files
authored
Unify surface creation by introducing new SurfaceTarget enum (#4984)
1 parent bc65d84 commit 4fd4a71

File tree

9 files changed

+344
-504
lines changed

9 files changed

+344
-504
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ This feature allowed you to call `global_id` on any wgpu opaque handle to get a
5959

6060
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)
6161

62+
### Unified surface creation
63+
64+
Previously, there were various specialized surface creation functions for various platform specific handles.
65+
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.
66+
Conversion to `wgpu::SurfaceTarget` is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits,
67+
meaning that you can continue to e.g. pass references to winit windows as before.
68+
By @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984)
69+
6270
### New Features
6371

6472
#### General

player/src/bin/play.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ fn main() {
6363
window.window_handle().unwrap().into(),
6464
wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty),
6565
)
66-
};
66+
}
67+
.unwrap();
6768

6869
let device = match actions.pop() {
6970
Some(trace::Action::Init { desc, backend }) => {

tests/src/init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Opt
5151
let canvas = initialize_html_canvas();
5252

5353
_surface = instance
54-
.create_surface_from_canvas(canvas.clone())
54+
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
5555
.expect("could not create surface from canvas");
5656

5757
surface_guard = Some(SurfaceGuard { canvas });

tests/tests/create_surface_error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Test that `create_surface_*()` accurately reports those errors we can provoke.
22
3-
/// This test applies to those cfgs that have a `create_surface_from_canvas` method, which
3+
/// This test applies to those cfgs that can create a surface from a canvas, which
44
/// include WebGL and WebGPU, but *not* Emscripten GLES.
55
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
66
#[wasm_bindgen_test::wasm_bindgen_test]
@@ -15,7 +15,7 @@ fn canvas_get_context_returned_null() {
1515

1616
#[allow(clippy::redundant_clone)] // false positive — can't and shouldn't move out.
1717
let error = instance
18-
.create_surface_from_canvas(canvas.clone())
18+
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
1919
.unwrap_err();
2020

2121
assert!(

wgpu-core/src/instance.rs

Lines changed: 29 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -479,68 +479,55 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
479479
display_handle: raw_window_handle::RawDisplayHandle,
480480
window_handle: raw_window_handle::RawWindowHandle,
481481
id_in: Input<G, SurfaceId>,
482-
) -> SurfaceId {
482+
) -> Result<SurfaceId, hal::InstanceError> {
483483
profiling::scope!("Instance::create_surface");
484484

485485
fn init<A: HalApi>(
486-
any_surface: &mut Option<AnySurface>,
487486
inst: &Option<A::Instance>,
488487
display_handle: raw_window_handle::RawDisplayHandle,
489488
window_handle: raw_window_handle::RawWindowHandle,
490-
) {
491-
if any_surface.is_none() {
492-
if let Some(surface) = inst.as_ref().and_then(|inst| unsafe {
493-
match inst.create_surface(display_handle, window_handle) {
494-
Ok(raw) => Some(HalSurface::<A> { raw: Arc::new(raw) }),
495-
Err(e) => {
496-
log::warn!("Error: {:?}", e);
497-
None
498-
}
499-
}
500-
}) {
501-
*any_surface = Some(AnySurface::new(surface));
489+
) -> Option<Result<AnySurface, hal::InstanceError>> {
490+
inst.as_ref().map(|inst| unsafe {
491+
match inst.create_surface(display_handle, window_handle) {
492+
Ok(raw) => Ok(AnySurface::new(HalSurface::<A> { raw: Arc::new(raw) })),
493+
Err(e) => Err(e),
502494
}
503-
}
495+
})
504496
}
505497

506-
let mut hal_surface = None;
498+
let mut hal_surface: Option<Result<AnySurface, hal::InstanceError>> = None;
499+
507500
#[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))]
508-
init::<hal::api::Vulkan>(
509-
&mut hal_surface,
510-
&self.instance.vulkan,
511-
display_handle,
512-
window_handle,
513-
);
501+
if hal_surface.is_none() {
502+
hal_surface =
503+
init::<hal::api::Vulkan>(&self.instance.vulkan, display_handle, window_handle);
504+
}
514505
#[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
515-
init::<hal::api::Metal>(
516-
&mut hal_surface,
517-
&self.instance.metal,
518-
display_handle,
519-
window_handle,
520-
);
506+
if hal_surface.is_none() {
507+
hal_surface =
508+
init::<hal::api::Metal>(&self.instance.metal, display_handle, window_handle);
509+
}
521510
#[cfg(all(feature = "dx12", windows))]
522-
init::<hal::api::Dx12>(
523-
&mut hal_surface,
524-
&self.instance.dx12,
525-
display_handle,
526-
window_handle,
527-
);
511+
if hal_surface.is_none() {
512+
hal_surface =
513+
init::<hal::api::Dx12>(&self.instance.dx12, display_handle, window_handle);
514+
}
528515
#[cfg(feature = "gles")]
529-
init::<hal::api::Gles>(
530-
&mut hal_surface,
531-
&self.instance.gl,
532-
display_handle,
533-
window_handle,
534-
);
516+
if hal_surface.is_none() {
517+
hal_surface = init::<hal::api::Gles>(&self.instance.gl, display_handle, window_handle);
518+
}
519+
520+
// This is only None if there's no instance at all.
521+
let hal_surface = hal_surface.unwrap()?;
535522

536523
let surface = Surface {
537524
presentation: Mutex::new(None),
538525
info: ResourceInfo::new("<Surface>"),
539-
raw: hal_surface.unwrap(),
526+
raw: hal_surface,
540527
};
541528

542529
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
543-
id
530+
Ok(id)
544531
}
545532

546533
/// # Safety
@@ -578,78 +565,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
578565
id
579566
}
580567

581-
#[cfg(all(
582-
target_arch = "wasm32",
583-
not(target_os = "emscripten"),
584-
feature = "gles"
585-
))]
586-
pub fn create_surface_webgl_canvas(
587-
&self,
588-
canvas: web_sys::HtmlCanvasElement,
589-
id_in: Input<G, SurfaceId>,
590-
) -> Result<SurfaceId, hal::InstanceError> {
591-
profiling::scope!("Instance::create_surface_webgl_canvas");
592-
593-
let surface = Surface {
594-
presentation: Mutex::new(None),
595-
info: ResourceInfo::new("<Surface>"),
596-
raw: {
597-
let hal_surface: HalSurface<hal::api::Gles> = self
598-
.instance
599-
.gl
600-
.as_ref()
601-
.map(|inst| {
602-
let raw_surface = inst.create_surface_from_canvas(canvas)?;
603-
Ok(HalSurface {
604-
raw: Arc::new(raw_surface),
605-
})
606-
})
607-
.transpose()?
608-
.unwrap();
609-
AnySurface::new(hal_surface)
610-
},
611-
};
612-
613-
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
614-
Ok(id)
615-
}
616-
617-
#[cfg(all(
618-
target_arch = "wasm32",
619-
not(target_os = "emscripten"),
620-
feature = "gles"
621-
))]
622-
pub fn create_surface_webgl_offscreen_canvas(
623-
&self,
624-
canvas: web_sys::OffscreenCanvas,
625-
id_in: Input<G, SurfaceId>,
626-
) -> Result<SurfaceId, hal::InstanceError> {
627-
profiling::scope!("Instance::create_surface_webgl_offscreen_canvas");
628-
629-
let surface = Surface {
630-
presentation: Mutex::new(None),
631-
info: ResourceInfo::new("<Surface>"),
632-
raw: {
633-
let hal_surface: HalSurface<hal::api::Gles> = self
634-
.instance
635-
.gl
636-
.as_ref()
637-
.map(|inst| {
638-
let raw_surface = inst.create_surface_from_offscreen_canvas(canvas)?;
639-
Ok(HalSurface {
640-
raw: Arc::new(raw_surface),
641-
})
642-
})
643-
.transpose()?
644-
.unwrap();
645-
AnySurface::new(hal_surface)
646-
},
647-
};
648-
649-
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
650-
Ok(id)
651-
}
652-
653568
#[cfg(all(feature = "dx12", windows))]
654569
/// # Safety
655570
///

wgpu/src/backend/direct.rs

Lines changed: 34 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use crate::{
77
DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode, Operations,
88
PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor,
99
SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, ShaderSource, StoreOp,
10-
SurfaceStatus, TextureDescriptor, TextureViewDescriptor, UncapturedErrorHandler,
10+
SurfaceStatus, SurfaceTargetUnsafe, TextureDescriptor, TextureViewDescriptor,
11+
UncapturedErrorHandler,
1112
};
1213

1314
use arrayvec::ArrayVec;
@@ -231,81 +232,6 @@ impl Context {
231232
self.0.generate_report()
232233
}
233234

234-
#[cfg(metal)]
235-
pub unsafe fn create_surface_from_core_animation_layer(
236-
&self,
237-
layer: *mut std::ffi::c_void,
238-
) -> Surface {
239-
let id = unsafe { self.0.instance_create_surface_metal(layer, ()) };
240-
Surface {
241-
id,
242-
configured_device: Mutex::default(),
243-
}
244-
}
245-
246-
#[cfg(any(webgpu, webgl))]
247-
pub fn instance_create_surface_from_canvas(
248-
&self,
249-
canvas: web_sys::HtmlCanvasElement,
250-
) -> Result<Surface, crate::CreateSurfaceError> {
251-
let id = self.0.create_surface_webgl_canvas(canvas, ())?;
252-
Ok(Surface {
253-
id,
254-
configured_device: Mutex::default(),
255-
})
256-
}
257-
258-
#[cfg(any(webgpu, webgl))]
259-
pub fn instance_create_surface_from_offscreen_canvas(
260-
&self,
261-
canvas: web_sys::OffscreenCanvas,
262-
) -> Result<Surface, crate::CreateSurfaceError> {
263-
let id = self.0.create_surface_webgl_offscreen_canvas(canvas, ())?;
264-
Ok(Surface {
265-
id,
266-
configured_device: Mutex::default(),
267-
})
268-
}
269-
270-
#[cfg(dx12)]
271-
pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
272-
let id = unsafe { self.0.instance_create_surface_from_visual(visual, ()) };
273-
Surface {
274-
id,
275-
configured_device: Mutex::default(),
276-
}
277-
}
278-
279-
#[cfg(dx12)]
280-
pub unsafe fn create_surface_from_surface_handle(
281-
&self,
282-
surface_handle: *mut std::ffi::c_void,
283-
) -> Surface {
284-
let id = unsafe {
285-
self.0
286-
.instance_create_surface_from_surface_handle(surface_handle, ())
287-
};
288-
Surface {
289-
id,
290-
configured_device: Mutex::default(),
291-
}
292-
}
293-
294-
#[cfg(dx12)]
295-
pub unsafe fn create_surface_from_swap_chain_panel(
296-
&self,
297-
swap_chain_panel: *mut std::ffi::c_void,
298-
) -> Surface {
299-
let id = unsafe {
300-
self.0
301-
.instance_create_surface_from_swap_chain_panel(swap_chain_panel, ())
302-
};
303-
Surface {
304-
id,
305-
configured_device: Mutex::default(),
306-
}
307-
}
308-
309235
fn handle_error(
310236
&self,
311237
sink_mutex: &Mutex<ErrorSinkRaw>,
@@ -594,19 +520,45 @@ impl crate::Context for Context {
594520

595521
unsafe fn instance_create_surface(
596522
&self,
597-
display_handle: raw_window_handle::RawDisplayHandle,
598-
window_handle: raw_window_handle::RawWindowHandle,
523+
target: SurfaceTargetUnsafe,
599524
) -> Result<(Self::SurfaceId, Self::SurfaceData), crate::CreateSurfaceError> {
600-
let id = unsafe {
601-
self.0
602-
.instance_create_surface(display_handle, window_handle, ())
525+
let id = match target {
526+
SurfaceTargetUnsafe::RawHandle {
527+
raw_display_handle,
528+
raw_window_handle,
529+
} => unsafe {
530+
self.0
531+
.instance_create_surface(raw_display_handle, raw_window_handle, ())?
532+
},
533+
534+
#[cfg(metal)]
535+
SurfaceTargetUnsafe::CoreAnimationLayer(layer) => unsafe {
536+
self.0.instance_create_surface_metal(layer, ())
537+
},
538+
539+
#[cfg(dx12)]
540+
SurfaceTargetUnsafe::CompositionVisual(visual) => unsafe {
541+
self.0.instance_create_surface_from_visual(visual, ())
542+
},
543+
544+
#[cfg(dx12)]
545+
SurfaceTargetUnsafe::SurfaceHandle(surface_handle) => unsafe {
546+
self.0
547+
.instance_create_surface_from_surface_handle(surface_handle, ())
548+
},
549+
550+
#[cfg(dx12)]
551+
SurfaceTargetUnsafe::SwapChainPanel(swap_chain_panel) => unsafe {
552+
self.0
553+
.instance_create_surface_from_swap_chain_panel(swap_chain_panel, ())
554+
},
603555
};
604556

605557
Ok((
606558
id,
607559
Surface {
608560
id,
609-
configured_device: Mutex::new(None),
561+
configured_device: Mutex::default(),
610562
},
611563
))
612564
}

0 commit comments

Comments
 (0)