Skip to content

Commit 0779e82

Browse files
committed
Provide a Vulkan path for create_surface_metal
Signed-off-by: Isaac Marovitz <[email protected]>
1 parent 119b4ef commit 0779e82

File tree

2 files changed

+86
-28
lines changed

2 files changed

+86
-28
lines changed

wgpu-core/src/instance.rs

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -317,31 +317,81 @@ impl Instance {
317317
) -> Result<Surface, CreateSurfaceError> {
318318
profiling::scope!("Instance::create_surface_metal");
319319

320-
let instance = unsafe { self.as_hal::<hal::api::Metal>() }
321-
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
320+
// HashMap unused in Metal-only path
321+
#[allow(unused_mut)]
322+
let mut errors = HashMap::default();
323+
let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
324+
HashMap::default();
322325

323-
let layer = layer.cast();
324-
// SAFETY: We do this cast and deref. (rather than using `metal` to get the
325-
// object we want) to avoid direct coupling on the `metal` crate.
326-
//
327-
// To wit, this pointer…
328-
//
329-
// - …is properly aligned.
330-
// - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
331-
// field.
332-
// - …points to an _initialized_ `MetalLayerRef`.
333-
// - …is only ever aliased via an immutable reference that lives within this
334-
// lexical scope.
335-
let layer = unsafe { &*layer };
336-
let raw_surface: Box<dyn hal::DynSurface> =
337-
Box::new(instance.create_surface_from_layer(layer));
326+
for (backend, instance) in &self.instance_per_backend {
327+
match *backend {
328+
#[cfg(vulkan)]
329+
Backend::Vulkan => {
330+
// Downcast to Vulkan instance
331+
let vk_instance = instance
332+
.as_any()
333+
.downcast_ref::<hal::vulkan::Instance>()
334+
.expect("Backend mismatch");
335+
336+
if let Some(mut layer) = core::ptr::NonNull::new(layer) {
337+
unsafe {
338+
match vk_instance.create_surface_from_layer(layer.as_mut()) {
339+
Ok(raw) => {
340+
surface_per_backend.insert(*backend, Box::new(raw));
341+
}
342+
Err(err) => {
343+
log::debug!(
344+
"Instance::create_surface_metal: failed to create Vulkan surface: {err:?}"
345+
);
346+
errors.insert(*backend, err);
347+
}
348+
}
349+
}
350+
}
351+
}
352+
#[cfg(metal)]
353+
Backend::Metal => {
354+
// Downcast to Metal instance
355+
let metal_instance = instance
356+
.as_any()
357+
.downcast_ref::<hal::metal::Instance>()
358+
.expect("Backend mismatch");
359+
360+
let layer_ref = layer.cast();
361+
// SAFETY: We do this cast and deref. (rather than using `metal` to get the
362+
// object we want) to avoid direct coupling on the `metal` crate.
363+
//
364+
// To wit, this pointer…
365+
//
366+
// - …is properly aligned.
367+
// - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
368+
// field.
369+
// - …points to an _initialized_ `MetalLayerRef`.
370+
// - …is only ever aliased via an immutable reference that lives within this
371+
// lexical scope.
372+
let layer_ref = unsafe { &*layer_ref };
373+
let raw = metal_instance.create_surface_from_layer(layer_ref);
374+
surface_per_backend.insert(*backend, Box::new(raw));
375+
}
376+
_ => {
377+
// Other backends don't support Metal layer input
378+
continue;
379+
}
380+
}
381+
}
338382

339-
let surface = Surface {
340-
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
341-
surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
342-
};
383+
if surface_per_backend.is_empty() {
384+
Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
385+
errors,
386+
))
387+
} else {
388+
let surface = Surface {
389+
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
390+
surface_per_backend,
391+
};
343392

344-
Ok(surface)
393+
Ok(surface)
394+
}
345395
}
346396

347397
#[cfg(dx12)]

wgpu-hal/src/vulkan/instance.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -519,24 +519,32 @@ impl super::Instance {
519519
fn create_surface_from_view(
520520
&self,
521521
view: core::ptr::NonNull<c_void>,
522+
) -> Result<super::Surface, crate::InstanceError> {
523+
let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) };
524+
// NOTE: The layer is retained by Vulkan's `vkCreateMetalSurfaceEXT`,
525+
// so no need to retain it beyond the scope of this function.
526+
let layer_ptr = (*layer).cast();
527+
528+
self.create_surface_from_layer(layer_ptr)
529+
}
530+
531+
#[cfg(metal)]
532+
pub fn create_surface_from_layer(
533+
&self,
534+
layer: *mut vk::CAMetalLayer,
522535
) -> Result<super::Surface, crate::InstanceError> {
523536
if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
524537
return Err(crate::InstanceError::new(String::from(
525538
"Vulkan driver does not support VK_EXT_metal_surface",
526539
)));
527540
}
528541

529-
let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) };
530-
// NOTE: The layer is retained by Vulkan's `vkCreateMetalSurfaceEXT`,
531-
// so no need to retain it beyond the scope of this function.
532-
let layer_ptr = (*layer).cast();
533-
534542
let surface = {
535543
let metal_loader =
536544
ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
537545
let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
538546
.flags(vk::MetalSurfaceCreateFlagsEXT::empty())
539-
.layer(layer_ptr);
547+
.layer(layer);
540548

541549
unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
542550
};

0 commit comments

Comments
 (0)