From 20f743d74b4805c6d6d654e34412d8b04a7ae700 Mon Sep 17 00:00:00 2001 From: janis Date: Thu, 26 Mar 2026 23:18:02 +0100 Subject: [PATCH] instance refactor --- crates/renderer/src/device.rs | 457 ++++++++++++++----------------- crates/renderer/src/instance.rs | 171 ++++++++++++ crates/renderer/src/lib.rs | 26 +- crates/renderer/src/swapchain.rs | 20 +- 4 files changed, 380 insertions(+), 294 deletions(-) diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs index e84bbdd..7c0bced 100644 --- a/crates/renderer/src/device.rs +++ b/crates/renderer/src/device.rs @@ -16,7 +16,8 @@ use tinyvec::{ArrayVec, array_vec}; use crate::{ Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures, - PhysicalDeviceProperties, Queue, Result, VkNameList, make_extention_properties, sync, + PhysicalDeviceProperties, Queue, Result, VkNameList, instance::InstanceInner, + make_extention_properties, sync, }; #[derive(Debug, Default)] @@ -114,7 +115,7 @@ pub struct DeviceInner { alloc: vk_mem::Allocator, device: DeviceWrapper, physical: PhysicalDevice, - instance: Arc, + instance: Arc, swapchain: khr::swapchain::Device, debug_utils: ash::ext::debug_utils::Device, allocated_queues: BTreeMap<(u32, u32), Queue>, @@ -137,18 +138,18 @@ impl core::fmt::Debug for DeviceInner { } #[macro_export] -macro_rules! make_extention { +macro_rules! make_extension { ($module:path) => {{ use $module::{NAME as EXTENSION_NAME, SPEC_VERSION as EXTENSION_VERSION}; - Extension { - name: EXTENSION_NAME.to_str().unwrap(), + $crate::device::Extension { + name: EXTENSION_NAME, version: EXTENSION_VERSION, } }}; ($module:path as $version:expr) => {{ use $module::*; - Extension { - name: NAME.to_str().unwrap(), + $crate::device::Extension { + name: NAME, version: $version, } }}; @@ -156,7 +157,7 @@ macro_rules! make_extention { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Extension<'a> { - pub name: &'a str, + pub name: &'a CStr, pub version: u32, } @@ -229,7 +230,7 @@ struct DeviceBuilder; impl DeviceBuilder { fn queue_family_supports_presentation( - instance: &Instance, + instance: &Arc, pdev: vk::PhysicalDevice, queue_family: u32, display_handle: RawDisplayHandle, @@ -270,7 +271,7 @@ impl DeviceBuilder { } fn select_pdev_queue_families( - instance: &Instance, + instance: &Arc, display_handle: Option, pdev: vk::PhysicalDevice, ) -> DeviceQueueFamilies { @@ -454,7 +455,7 @@ impl DeviceBuilder { } fn choose_physical_device( - instance: &Instance, + instance: &Arc, display_handle: Option, requirements: &PhysicalDeviceFeatures, extra_properties: Vec>, @@ -505,173 +506,187 @@ impl DeviceBuilder { properties, }) } +} - fn get_available_extensions( - entry: &ash::Entry, - layers: &[&CStr], - ) -> Result> { - unsafe { - let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None)) - .chain( - layers - .iter() - .map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))), - ) - .filter_map(|result| result.ok()) - .flatten() - .collect::>(); - - Ok(extensions) - } - } - - /// returns a tuple of supported-or-enabled extensions and unsupported-and-requested extensions - fn get_extensions<'a>( - entry: &ash::Entry, - layers: &[&'a CStr], - extensions: impl Iterator> + 'a, - display_handle: Option, - ) -> Result<(HashSet>, HashSet>)> { - unsafe { - let available_extensions = Self::get_available_extensions(entry, layers)?; - - let available_extension_names = available_extensions - .iter() - .filter_map(|ext| { - Some(( - ext.extension_name_as_c_str().ok()?.to_str().ok()?, - ext.spec_version, - )) - }) - .collect::>(); - - tracing::debug!( - "Available extensions: {:?}", - available_extension_names.iter().collect::>() - ); - - let mut out_extensions = HashSet::new(); - let mut unsupported_extensions = HashSet::new(); - - let mut wsi_extensions = Vec::new(); - wsi_extensions.push(make_extention!(khr::surface)); - - // taken from wgpu-hal/src/vulkan/instance.rs: - if cfg!(all( - unix, - not(target_os = "android"), - not(target_os = "macos") - )) { - wsi_extensions.push(make_extention!(khr::xlib_surface)); - wsi_extensions.push(make_extention!(khr::xcb_surface)); - wsi_extensions.push(make_extention!(khr::wayland_surface)); - } - if cfg!(target_os = "windows") { - wsi_extensions.push(make_extention!(khr::win32_surface)); - } - if cfg!(target_os = "android") { - wsi_extensions.push(make_extention!(khr::android_surface)); - } - if cfg!(target_os = "macos") { - wsi_extensions.push(make_extention!(ext::metal_surface)); - wsi_extensions.push(make_extention!(khr::portability_enumeration)); - } - if cfg!(all( - unix, - not(target_vendor = "apple"), - not(target_family = "wasm") - )) { - wsi_extensions.push(make_extention!(ext::acquire_drm_display)); - wsi_extensions.push(make_extention!(ext::direct_mode_display)); - wsi_extensions.push(make_extention!(khr::display)); - } - - for extension in extensions { - if let Some(available_version) = available_extension_names.get(&extension.name) - && *available_version >= extension.version - { - out_extensions.insert(extension); - } else { - unsupported_extensions.insert(extension); - } - } - - for extension in wsi_extensions { - if let Some(available_version) = available_extension_names.get(&extension.name) - && *available_version >= extension.version - { - out_extensions.insert(extension); - } - // don't warn about missing WSI extensions, these might not all - // be needed and weren't requested by the user. - } - - // if a display handle is provided, ensure the required WSI extensions are present - let required_extension_names = display_handle - .map(ash_window::enumerate_required_extensions) - .unwrap_or(Ok(&[]))?; - - for &extension in required_extension_names { - let extension = core::ffi::CStr::from_ptr(extension); - let extension = Extension { - name: extension.to_str()?, - version: 0, - }; - - if let Some(available_version) = available_extension_names.get(&extension.name) - && *available_version >= extension.version - { - out_extensions.insert(extension); - } else { - unsupported_extensions.insert(extension); - } - } - - Ok((out_extensions, unsupported_extensions)) - } - } - - fn get_layers<'a>( - entry: &ash::Entry, - wants_layers: impl Iterator + 'a, - ) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> { - unsafe { - let wants_layers = wants_layers.collect::>(); - - let available_layers = entry - .enumerate_instance_layer_properties() - .map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?; - let available_layer_names = available_layers - .iter() - .map(|layer| layer.layer_name_as_c_str()) - .collect::, _>>() - .map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?; - - tracing::debug!( - "Available layers: {:?}", - available_layer_names +pub(crate) fn get_available_extensions( + entry: &ash::Entry, + layers: &[&CStr], +) -> Result> { + unsafe { + let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None)) + .chain( + layers .iter() - .map(|s| s.to_str().unwrap_or("")) - .collect::>() + .map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))), + ) + .filter_map(|result| result.ok()) + .flatten() + .collect::>(); + + Ok(extensions) + } +} + +/// returns a tuple of supported-or-enabled extensions and unsupported-and-requested extensions +pub(crate) fn get_extensions<'a>( + entry: &ash::Entry, + layers: &[&'a CStr], + mut extensions: Vec>, + display_handle: Option, +) -> Result<(HashSet>, HashSet>)> { + let available_extensions = get_available_extensions(entry, layers)?; + + let available_extension_names = available_extensions + .iter() + .filter_map(|ext| { + Some(( + ext.extension_name_as_c_str().ok()?.to_str().ok()?, + ext.spec_version, + )) + }) + .collect::>(); + + tracing::debug!( + "Available extensions: {:?}", + available_extension_names.iter().collect::>() + ); + + let mut wsi_extensions = Vec::new(); + wsi_extensions.push(make_extension!(khr::surface)); + + // taken from wgpu-hal/src/vulkan/instance.rs: + // + // we want to enable all the wsi extensions that are applicable to the + // platform, even if the user didn't explicitly request them, or + // supplied a different/no display handle, because we might later want + // to create a surface for a different windowing system, and enabling + // all the wsi extensions doesn't have any real downsides. + // We don't notify the user if some of these extensions aren't available + // (e.g. because wayland isn't supported on some unix system) + if cfg!(all( + unix, + not(target_os = "android"), + not(target_os = "macos") + )) { + wsi_extensions.push(make_extension!(khr::xlib_surface)); + wsi_extensions.push(make_extension!(khr::xcb_surface)); + wsi_extensions.push(make_extension!(khr::wayland_surface)); + } + if cfg!(target_os = "windows") { + wsi_extensions.push(make_extension!(khr::win32_surface)); + } + if cfg!(target_os = "android") { + wsi_extensions.push(make_extension!(khr::android_surface)); + } + if cfg!(target_os = "macos") { + wsi_extensions.push(make_extension!(ext::metal_surface)); + wsi_extensions.push(make_extension!(khr::portability_enumeration)); + } + if cfg!(all( + unix, + not(target_vendor = "apple"), + not(target_family = "wasm") + )) { + wsi_extensions.push(make_extension!(ext::acquire_drm_display)); + wsi_extensions.push(make_extension!(ext::direct_mode_display)); + wsi_extensions.push(make_extension!(khr::display)); + } + + let is_extension_available = |ext: &mut Extension| -> bool { + if available_extensions + .iter() + .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext.name)) + { + true + } else { + tracing::warn!( + "Extension {:?} v{} was requested but is not available", + ext.name, + ext.version ); + false + } + }; - let mut out_layers = Vec::new(); - let mut unsupported_layers = Vec::new(); + let mut enabled_extensions = extensions + .extract_if(.., is_extension_available) + .collect::>(); - for layer in wants_layers { - if available_layer_names.contains(&layer) { - out_layers.push(layer); - } else { - unsupported_layers.push(layer); - } - } + enabled_extensions.extend(wsi_extensions.extract_if(.., is_extension_available)); - if !unsupported_layers.is_empty() { - Err((out_layers, unsupported_layers)) + // if a display handle is provided, ensure the required WSI extensions are present + if let Some(display_handle) = display_handle { + let mut required_extensions = ash_window::enumerate_required_extensions(display_handle)? + .iter() + .map(|&p| Extension { + name: unsafe { CStr::from_ptr(p) }, + version: 0, + }) + // filter out extensions that are already enabled + .filter(|ext| { + !enabled_extensions + .iter() + .any(|enabled| enabled.name == ext.name) + }) + .collect::>(); + + // filter out extensions that aren't available, and log a warning for them + let display_extensions = required_extensions.extract_if(.., is_extension_available); + + enabled_extensions.extend(display_extensions); + extensions.extend(required_extensions); + } + + // all extensions remaining in `extensions` at this point are unsupported, + // and were requested by the user or are required by the display handle + let unsupported_extensions = HashSet::from_iter(extensions); + let out_extensions = HashSet::from_iter(enabled_extensions); + + Ok((out_extensions, unsupported_extensions)) +} + +/// returns a list of enabled, or a tuple of enabled and unsupported but requested layers. +pub(crate) fn get_layers<'a>( + entry: &ash::Entry, + wants_layers: Vec<&'a CStr>, +) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> { + unsafe { + let Ok(available_layers) = entry.enumerate_instance_layer_properties() else { + return Err((vec![], wants_layers)); + }; + + let Ok(available_layer_names) = available_layers + .iter() + .map(|layer| layer.layer_name_as_c_str()) + .collect::, _>>() + else { + return Err((vec![], wants_layers)); + }; + + tracing::debug!( + "Available layers: {:?}", + available_layer_names + .iter() + .map(|s| s.to_str().unwrap_or("")) + .collect::>() + ); + + let mut enabled_layers = Vec::new(); + let mut unsupported_layers = Vec::new(); + + for layer in wants_layers { + if available_layer_names.contains(&layer) { + enabled_layers.push(layer); } else { - Ok(out_layers) + unsupported_layers.push(layer); } } + + if !unsupported_layers.is_empty() { + Err((enabled_layers, unsupported_layers)) + } else { + Ok(enabled_layers) + } } } @@ -733,92 +748,18 @@ impl Device { }) } pub fn new_from_desc(desc: DeviceDesc) -> crate::Result { - tracing::debug!("creating new device with: {desc:#?}"); - let entry = unsafe { ash::Entry::load()? }; - - let app_name = desc - .app_name - .and_then(|name| CString::new(name).ok()) - .unwrap_or(c"ShooterGame".to_owned()); - - let app_info = vk::ApplicationInfo::default() - .api_version(desc.features.version) - .application_name(&app_name) - .application_version(desc.app_version) - .engine_name(c"VidyaEngine") - .engine_version(vk::make_api_version(0, 0, 1, 0)); - - let mut validation_info = - vk::LayerSettingsCreateInfoEXT::default().settings(desc.layer_settings); - - let extra_instance_extensions = [ - make_extention!(ext::debug_utils as 1), - #[cfg(debug_assertions)] - make_extention!(ext::layer_settings), - ]; - - let layers = DeviceBuilder::get_layers(&entry, desc.layers.iter().cloned()).unwrap(); - - let (extensions, unsupported_extensions) = DeviceBuilder::get_extensions( - &entry, - &layers, - desc.instance_extensions + let instance = Instance::new(&crate::instance::InstanceDesc { + app_name: desc.app_name, + app_version: desc.app_version, + instance_extensions: &desc + .instance_extensions .iter() - .cloned() - .chain(extra_instance_extensions), - desc.display_handle, - )?; - - if !unsupported_extensions.is_empty() { - tracing::error!( - "extensions were requested but not supported by instance: {:?}", - unsupported_extensions - ); - } - - let layers = VkNameList::from_strs(&layers); - let extensions = crate::util::CStringList::from_iter(extensions.iter().map(|ext| ext.name)); - - let create_info = vk::InstanceCreateInfo::default() - .application_info(&app_info) - .enabled_extension_names(&extensions.strings) - .enabled_layer_names(&layers.names) - .push_next(&mut validation_info); - - tracing::debug!( - "Creating instance:\napp_info: {app_info:#?}\ncreate_info: {create_info:#?}" - ); - - let instance = unsafe { entry.create_instance(&create_info, None)? }; - - let debug_utils = { - let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default() - .message_severity( - vk::DebugUtilsMessageSeverityFlagsEXT::ERROR - | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING - | vk::DebugUtilsMessageSeverityFlagsEXT::INFO, - ) - .message_type( - vk::DebugUtilsMessageTypeFlagsEXT::GENERAL - | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION - | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, - ) - .pfn_user_callback(Some(crate::debug::debug_callback)); - - let instance = ext::debug_utils::Instance::new(&entry, &instance); - let messenger = unsafe { instance.create_debug_utils_messenger(&debug_info, None)? }; - - crate::DebugUtils { - instance, - messenger, - } - }; - - let instance = Arc::new(Instance { - raw: instance, - _debug_utils: debug_utils, - entry, - }); + .map(|ext| ext.name) + .collect::>(), + layers: desc.layers, + layer_settings: desc.layer_settings, + display_handle: desc.display_handle, + })?; let mut features = desc.features.with_extension2(make_extention_properties( khr::swapchain::NAME, @@ -836,7 +777,7 @@ impl Device { // additionally, pdev would have to be derived from a device and not a scoring function. let pdev = DeviceBuilder::choose_physical_device( - &instance, + &instance.inner, desc.display_handle, &features, vec![Box::new( @@ -845,13 +786,13 @@ impl Device { )?; tracing::trace!("pdev: {pdev:?}"); - let device = Device::new(instance.clone(), pdev, features)?; + let device = Device::new(instance.inner.clone(), pdev, features)?; Ok(device) } pub fn new( - instance: Arc, + instance: Arc, physical: PhysicalDevice, mut features: crate::PhysicalDeviceFeatures, ) -> VkResult { @@ -953,7 +894,7 @@ impl Device { pub fn dev(&self) -> &ash::Device { &self.0.device } - pub fn instance(&self) -> &Arc { + pub fn instance(&self) -> &Arc { &self.0.instance } pub fn swapchain(&self) -> &khr::swapchain::Device { diff --git a/crates/renderer/src/instance.rs b/crates/renderer/src/instance.rs index 8b13789..c1b6509 100644 --- a/crates/renderer/src/instance.rs +++ b/crates/renderer/src/instance.rs @@ -1 +1,172 @@ +use std::{ + ffi::{CStr, CString}, + sync::Arc, +}; +use ash::{Entry, ext, vk}; +use raw_window_handle::RawDisplayHandle; + +use crate::{ + device::{Extension, get_extensions, get_layers}, + make_extension, +}; + +pub struct DebugUtilsCreateInfo { + pub severity: vk::DebugUtilsMessageSeverityFlagsEXT, + pub message_type: vk::DebugUtilsMessageTypeFlagsEXT, +} + +pub struct InstanceInner { + pub raw: ash::Instance, + pub entry: Entry, + pub(crate) _debug_utils: DebugUtils, +} + +#[derive(Clone)] +pub struct Instance { + pub(crate) inner: Arc, +} + +impl core::fmt::Debug for Instance { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Instance") + .field("raw", &self.inner.raw.handle()) + .finish_non_exhaustive() + } +} + +pub struct InstanceDesc<'a> { + pub app_name: Option<&'a str>, + pub app_version: u32, + pub instance_extensions: &'a [&'a CStr], + pub layer_settings: &'a [vk::LayerSettingEXT<'a>], + pub layers: &'a [&'a CStr], + pub display_handle: Option, +} + +impl Instance { + pub fn new<'a>(desc: &InstanceDesc<'a>) -> crate::Result { + let entry = unsafe { ash::Entry::load()? }; + + let app_name = desc + .app_name + .and_then(|name| CString::new(name).ok()) + .unwrap_or(c"ShooterGame".to_owned()); + + let version = + unsafe { entry.try_enumerate_instance_version()? }.unwrap_or(vk::API_VERSION_1_0); + + let app_info = vk::ApplicationInfo::default() + .api_version(if version < vk::API_VERSION_1_1 { + vk::API_VERSION_1_0 + } else { + // ash doesn't support 1.4 yet + vk::API_VERSION_1_3 + }) + .application_name(&app_name) + .application_version(desc.app_version) + .engine_name(c"Bevy Engine") + .engine_version(vk::make_api_version(0, 0, 1, 0)); + + let mut validation_info = + vk::LayerSettingsCreateInfoEXT::default().settings(desc.layer_settings); + + let layers = match get_layers(&entry, desc.layers.to_vec()) { + Ok(layers) => layers, + Err((supported, unsupported)) => { + tracing::error!( + "Some requested layers were not supported by instance:\nSupported: {:?}\nUnsupported: {:?}", + supported, + unsupported + ); + supported + } + }; + + let mut requested_extensions = desc + .instance_extensions + .iter() + .map(|name| Extension { name, version: 0 }) + .collect::>(); + + requested_extensions.push(make_extension!(ext::debug_utils as 1)); + #[cfg(debug_assertions)] + requested_extensions.push(make_extension!(ext::layer_settings)); + + let (extensions, unsupported_extensions) = + get_extensions(&entry, &layers, requested_extensions, desc.display_handle)?; + + if !unsupported_extensions.is_empty() { + tracing::error!( + "extensions were requested but not supported by instance: {:?}", + unsupported_extensions + ); + } + + let layers = layers + .iter() + .map(|layer| layer.as_ptr()) + .collect::>(); + let extensions = extensions + .iter() + .map(|ext| ext.name.as_ptr()) + .collect::>(); + + let create_info = vk::InstanceCreateInfo::default() + .application_info(&app_info) + .enabled_extension_names(&extensions) + .enabled_layer_names(&layers) + .push_next(&mut validation_info); + + tracing::debug!( + "Creating instance:\napp_info: {app_info:#?}\ncreate_info: {create_info:#?}" + ); + + let instance = unsafe { entry.create_instance(&create_info, None)? }; + + let debug_utils = { + let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default() + .message_severity( + vk::DebugUtilsMessageSeverityFlagsEXT::ERROR + | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING + | vk::DebugUtilsMessageSeverityFlagsEXT::INFO, + ) + .message_type( + vk::DebugUtilsMessageTypeFlagsEXT::GENERAL + | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION + | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, + ) + .pfn_user_callback(Some(crate::debug::debug_callback)); + + let instance = ext::debug_utils::Instance::new(&entry, &instance); + let messenger = unsafe { instance.create_debug_utils_messenger(&debug_info, None)? }; + + crate::DebugUtils { + instance, + messenger, + } + }; + + let instance = Arc::new(InstanceInner { + raw: instance, + _debug_utils: debug_utils, + entry, + }); + + Ok(Self { inner: instance }) + } +} + +pub(crate) struct DebugUtils { + pub instance: ext::debug_utils::Instance, + pub messenger: vk::DebugUtilsMessengerEXT, +} + +impl Drop for DebugUtils { + fn drop(&mut self) { + unsafe { + self.instance + .destroy_debug_utils_messenger(self.messenger, None); + } + } +} diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 99fb292..279e0aa 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -435,30 +435,8 @@ pub struct PhysicalDevice { properties: PhysicalDeviceProperties, } -struct DebugUtils { - instance: ext::debug_utils::Instance, - messenger: vk::DebugUtilsMessengerEXT, -} - -impl Drop for DebugUtils { - fn drop(&mut self) { - unsafe { - self.instance - .destroy_debug_utils_messenger(self.messenger, None); - } - } -} - -pub struct DebugUtilsCreateInfo { - pub severity: vk::DebugUtilsMessageSeverityFlagsEXT, - pub message_type: vk::DebugUtilsMessageTypeFlagsEXT, -} - -pub struct Instance { - entry: Entry, - raw: ash::Instance, - _debug_utils: DebugUtils, -} +pub(crate) use instance::DebugUtils; +pub use instance::{DebugUtilsCreateInfo, Instance}; pub struct SamplerCache { device: Device, diff --git a/crates/renderer/src/swapchain.rs b/crates/renderer/src/swapchain.rs index f59598b..df900c5 100644 --- a/crates/renderer/src/swapchain.rs +++ b/crates/renderer/src/swapchain.rs @@ -17,7 +17,9 @@ use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use crate::{ Instance, Result, define_device_owned_handle, device::{Device, DeviceOwned}, - images, sync, + images, + instance::InstanceInner, + sync, util::RawMutexGuard, }; @@ -40,7 +42,7 @@ impl Drop for Surface { impl Surface { #[allow(dead_code)] - pub fn headless(instance: &Arc) -> Result { + pub fn headless(instance: &Arc) -> Result { let headless_instance = ash::ext::headless_surface::Instance::new(&instance.entry, &instance.raw); let functor = khr::surface::Instance::new(&instance.entry, &instance.raw); @@ -67,7 +69,7 @@ impl Surface { /// was created with the appropriate platform-specific surface extensions /// enabled. pub unsafe fn new_from_raw_window_handle( - instance: &Arc, + instance: &Arc, display_handle: RawDisplayHandle, window_handle: RawWindowHandle, ) -> Result { @@ -704,7 +706,7 @@ impl WindowSurface { #[cfg(test)] mod tests { - use crate::device; + use crate::make_extension; use super::*; @@ -712,14 +714,8 @@ mod tests { let device = Device::new_from_default_desc( None, &[ - device::Extension { - name: "VK_EXT_headless_surface", - version: ash::ext::headless_surface::SPEC_VERSION, - }, - device::Extension { - name: "VK_KHR_surface", - version: ash::khr::surface::SPEC_VERSION, - }, + make_extension!(ash::ext::headless_surface), + make_extension!(ash::khr::surface), ], )?;