Skip to content

Commit a915331

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

File tree

2 files changed

+84
-28
lines changed

2 files changed

+84
-28
lines changed

wgpu-core/src/instance.rs

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -317,31 +317,79 @@ 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+
let mut errors = HashMap::default();
321+
let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
322+
HashMap::default();
322323

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

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-
};
381+
if surface_per_backend.is_empty() {
382+
Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
383+
errors,
384+
))
385+
} else {
386+
let surface = Surface {
387+
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
388+
surface_per_backend,
389+
};
343390

344-
Ok(surface)
391+
Ok(surface)
392+
}
345393
}
346394

347395
#[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)