diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 8ea2c934f2f..bc60183dd54 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -517,10 +517,12 @@ impl Device { }) } - fn create_texture( + fn texture_from_hal( &self, + hal_texture: A::Texture, self_id: id::DeviceId, adapter: &crate::instance::Adapter, + hal_usage: hal::TextureUses, desc: &resource::TextureDescriptor, ) -> Result, resource::CreateTextureError> { debug_assert_eq!(self_id.backend(), A::VARIANT); @@ -566,6 +568,29 @@ impl Device { return Err(resource::CreateTextureError::InvalidMipLevelCount(mips)); } + Ok(resource::Texture { + raw: Some(hal_texture), + device_id: Stored { + value: id::Valid(self_id), + ref_count: self.life_guard.add_ref(), + }, + desc: desc.map_label(|_| ()), + hal_usage, + format_features, + full_range: TextureSelector { + levels: 0..desc.mip_level_count, + layers: 0..desc.array_layer_count(), + }, + life_guard: LifeGuard::new(desc.label.borrow_or_default()), + }) + } + + fn create_texture( + &self, + self_id: id::DeviceId, + adapter: &crate::instance::Adapter, + desc: &resource::TextureDescriptor, + ) -> Result, resource::CreateTextureError> { let hal_usage = conv::map_texture_usage(desc.usage, desc.format.into()); let hal_desc = hal::TextureDescriptor { label: desc.label.borrow_option(), @@ -583,21 +608,7 @@ impl Device { .map_err(DeviceError::from)? }; - Ok(resource::Texture { - raw: Some(raw), - device_id: Stored { - value: id::Valid(self_id), - ref_count: self.life_guard.add_ref(), - }, - desc: desc.map_label(|_| ()), - hal_usage, - format_features, - full_range: TextureSelector { - levels: 0..desc.mip_level_count, - layers: 0..desc.array_layer_count(), - }, - life_guard: LifeGuard::new(desc.label.borrow_or_default()), - }) + self.texture_from_hal(raw, self_id, adapter, hal_usage, desc) } fn create_texture_view( @@ -2976,6 +2987,64 @@ impl Global { (id, Some(error)) } + /// # Safety + /// + /// - `hal_texture` must be created from `device_id` correspnding raw handle. + /// - `hal_texture` must be created respecting `desc` + pub unsafe fn texture_from_hal( + &self, + hal_texture: A::Texture, + device_id: id::DeviceId, + desc: &resource::TextureDescriptor, + id_in: Input, + ) -> (id::TextureId, Option) { + profiling::scope!("create_texture", "Device"); + + let hub = A::hub(self); + let mut token = Token::root(); + let fid = hub.textures.prepare(id_in); + + let (adapter_guard, mut token) = hub.adapters.read(&mut token); + let (device_guard, mut token) = hub.devices.read(&mut token); + let error = loop { + let device = match device_guard.get(device_id) { + Ok(device) => device, + Err(_) => break DeviceError::Invalid.into(), + }; + #[cfg(feature = "trace")] + if let Some(ref trace) = device.trace { + trace + .lock() + .add(trace::Action::CreateTexture(fid.id(), desc.clone())); + } + + let adapter = &adapter_guard[device.adapter_id.value]; + let hal_usage = conv::map_texture_usage(desc.usage, desc.format.into()); + let texture = + match device.texture_from_hal(hal_texture, device_id, adapter, hal_usage, desc) { + Ok(texture) => texture, + Err(error) => break error, + }; + let num_levels = texture.full_range.levels.end; + let num_layers = texture.full_range.layers.end; + let ref_count = texture.life_guard.add_ref(); + + let id = fid.assign(texture, &mut token); + log::info!("Created texture {:?} with {:?}", id, desc); + + device + .trackers + .lock() + .textures + .init(id, ref_count, TextureState::new(num_levels, num_layers)) + .unwrap(); + return (id.0, None); + }; + + let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + (id, Some(error)) + } + pub fn texture_label(&self, id: id::TextureId) -> String { A::hub(self).textures.label_for_resource(id) } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 5d632211da9..8f28285d8de 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -850,6 +850,22 @@ impl Global { } } + /// # Safety + /// + /// Refer to the creation of wgpu-hal Instance for every backend. + pub unsafe fn from_hal_instance( + name: &str, + factory: G, + hal_instance: A::Instance, + ) -> Self { + profiling::scope!("new", "Global"); + Self { + instance: A::instance_from_hal(name, hal_instance), + surfaces: Registry::without_backend(&factory, "Surface"), + hubs: Hubs::new(&factory), + } + } + pub fn clear_backend(&self, _dummy: ()) { let mut surface_guard = self.surfaces.data.write(); let hub = A::hub(self); @@ -933,6 +949,7 @@ impl Drop for Global { pub trait HalApi: hal::Api { const VARIANT: Backend; + fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn hub(global: &Global) -> &Hub; fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface; } @@ -940,6 +957,13 @@ pub trait HalApi: hal::Api { #[cfg(vulkan)] impl HalApi for hal::api::Vulkan { const VARIANT: Backend = Backend::Vulkan; + fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { + Instance { + name: name.to_owned(), + vulkan: Some(hal_instance), + ..Default::default() + } + } fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } @@ -951,6 +975,12 @@ impl HalApi for hal::api::Vulkan { #[cfg(metal)] impl HalApi for hal::api::Metal { const VARIANT: Backend = Backend::Metal; + fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { + Instance { + name: name.to_owned(), + metal: Some(hal_instance), + } + } fn hub(global: &Global) -> &Hub { &global.hubs.metal } @@ -962,6 +992,13 @@ impl HalApi for hal::api::Metal { #[cfg(dx12)] impl HalApi for hal::api::Dx12 { const VARIANT: Backend = Backend::Dx12; + fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { + Instance { + name: name.to_owned(), + dx12: Some(hal_instance), + ..Default::default() + } + } fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } @@ -986,6 +1023,13 @@ impl HalApi for hal::api::Dx11 { #[cfg(gl)] impl HalApi for hal::api::Gles { const VARIANT: Backend = Backend::Gl; + fn instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { + Instance { + name: name.to_owned(), + gl: Some(hal_instance), + ..Default::default() + } + } fn hub(global: &Global) -> &Hub { &global.hubs.gl } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 01921870f85..f28cce5937c 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -69,9 +69,10 @@ fn downlevel_default_limits_less_than_default_limits() { ) } +#[derive(Default)] pub struct Instance { #[allow(dead_code)] - name: String, + pub name: String, #[cfg(vulkan)] pub vulkan: Option>, #[cfg(metal)] @@ -248,9 +249,10 @@ impl Adapter { } } - fn create_device( + fn device_from_open( &self, self_id: AdapterId, + open: hal::OpenDevice, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, ) -> Result, RequestDeviceError> { @@ -281,11 +283,6 @@ impl Adapter { log::warn!("Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. This is a massive performance footgun and likely not what you wanted"); } - let gpu = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err { - hal::DeviceError::Lost => RequestDeviceError::DeviceLost, - hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory, - })?; - if let Some(_) = desc.label { //TODO } @@ -305,7 +302,7 @@ impl Adapter { } Device::new( - gpu, + open, Stored { value: Valid(self_id), ref_count: self.life_guard.add_ref(), @@ -317,6 +314,20 @@ impl Adapter { ) .or(Err(RequestDeviceError::OutOfMemory)) } + + fn create_device( + &self, + self_id: AdapterId, + desc: &DeviceDescriptor, + trace_path: Option<&std::path::Path>, + ) -> Result, RequestDeviceError> { + let open = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err { + hal::DeviceError::Lost => RequestDeviceError::DeviceLost, + hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory, + })?; + + self.device_from_open(self_id, open, desc, trace_path) + } } impl crate::hub::Resource for Adapter { @@ -649,6 +660,34 @@ impl Global { Err(RequestAdapterError::NotFound) } + /// # Safety + /// + /// `hal_adapter` must be created from this global internal instance handle. + pub unsafe fn adapter_from_hal( + &self, + hal_adapter: hal::ExposedAdapter, + input: Input, + ) -> AdapterId { + profiling::scope!("adapter_from_hal", "Instance"); + + let mut token = Token::root(); + let fid = A::hub(&self).adapters.prepare(input); + + match A::VARIANT { + #[cfg(vulkan)] + Backend::Vulkan => fid.assign(Adapter::new(hal_adapter), &mut token).0, + #[cfg(metal)] + Backend::Metal => fid.assign(Adapter::new(hal_adapter), &mut token).0, + #[cfg(dx12)] + Backend::Dx12 => fid.assign(Adapter::new(hal_adapter), &mut token).0, + #[cfg(dx11)] + Backend::Dx11 => fid.assign(Adapter::new(hal_adapter), &mut token).0, + #[cfg(gl)] + Backend::Gl => fid.assign(Adapter::new(hal_adapter), &mut token).0, + _ => unreachable!(), + } + } + pub fn adapter_get_info( &self, adapter_id: AdapterId, @@ -764,4 +803,40 @@ impl Global { let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); (id, Some(error)) } + + /// # Safety + /// + /// - `hal_device` must be created from `adapter_id` or its internal handle. + /// - `desc` must be a subset of `hal_device` features and limits. + pub unsafe fn device_from_hal( + &self, + adapter_id: AdapterId, + hal_device: hal::OpenDevice, + desc: &DeviceDescriptor, + trace_path: Option<&std::path::Path>, + id_in: Input, + ) -> (DeviceId, Option) { + profiling::scope!("request_device", "Adapter"); + + let hub = A::hub(self); + let mut token = Token::root(); + let fid = hub.devices.prepare(id_in); + + let error = loop { + let (adapter_guard, mut token) = hub.adapters.read(&mut token); + let adapter = match adapter_guard.get(adapter_id) { + Ok(adapter) => adapter, + Err(_) => break RequestDeviceError::InvalidAdapter, + }; + let device = match adapter.device_from_open(adapter_id, hal_device, desc, trace_path) { + Ok(device) => device, + Err(e) => break e, + }; + let id = fid.assign(device, &mut token); + return (id.0, None); + }; + + let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + (id, Some(error)) + } } diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 0ceef3a43f5..e97dec93a57 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -30,7 +30,7 @@ unsafe impl Sync for PhysicalDeviceFeatures {} impl PhysicalDeviceFeatures { /// Add the members of `self` into `info.enabled_features` and its `p_next` chain. - fn add_to_device_create_builder<'a>( + pub fn add_to_device_create_builder<'a>( &'a mut self, mut info: vk::DeviceCreateInfoBuilder<'a>, ) -> vk::DeviceCreateInfoBuilder<'a> { @@ -592,7 +592,7 @@ impl super::InstanceShared { } impl super::Instance { - pub(super) fn expose_adapter( + pub fn expose_adapter( &self, phd: vk::PhysicalDevice, ) -> Option> { @@ -723,28 +723,51 @@ impl super::Instance { } } -impl crate::Adapter for super::Adapter { - unsafe fn open( +impl super::Adapter { + pub fn required_device_extensions(&self, features: wgt::Features) -> Vec<&'static CStr> { + let (supported_extensions, unsupported_extensions) = self + .phd_capabilities + .get_required_extensions(features) + .iter() + .partition::, _>(|&&extension| { + self.phd_capabilities.supports_extension(extension) + }); + + if !unsupported_extensions.is_empty() { + log::warn!("Missing extensions: {:?}", unsupported_extensions); + } + + log::debug!("Supported extensions: {:?}", supported_extensions); + supported_extensions + } + + /// `features` must be the same features used to create `enabled_extensions`. + pub fn physical_device_features( &self, + enabled_extensions: &[&'static CStr], features: wgt::Features, - ) -> Result, crate::DeviceError> { - let enabled_extensions = { - let (supported_extensions, unsupported_extensions) = self - .phd_capabilities - .get_required_extensions(features) - .iter() - .partition::, _>(|&&extension| { - self.phd_capabilities.supports_extension(extension) - }); - - if !unsupported_extensions.is_empty() { - log::warn!("Missing extensions: {:?}", unsupported_extensions); - } - - log::debug!("Supported extensions: {:?}", supported_extensions); - supported_extensions - }; + ) -> PhysicalDeviceFeatures { + PhysicalDeviceFeatures::from_extensions_and_requested_features( + self.phd_capabilities.properties.api_version, + enabled_extensions, + features, + self.downlevel_flags, + &self.private_caps, + ) + } + /// # Safety + /// + /// - `raw_device` must be created from this adapter. + /// - `raw_device` must be created using `family_index`, `enabled_extensions` and `physical_device_features()` + /// - `enabled_extensions` must be a superset of `required_device_extensions()`. + pub unsafe fn device_from_raw( + &self, + raw_device: ash::Device, + enabled_extensions: &[&'static CStr], + family_index: u32, + queue_index: u32, + ) -> Result, crate::DeviceError> { let mem_properties = self .instance .raw @@ -759,39 +782,6 @@ impl crate::Adapter for super::Adapter { } }); - // Create device - let family_index = 0; //TODO - let raw_device = { - let family_info = vk::DeviceQueueCreateInfo::builder() - .queue_family_index(family_index) - .queue_priorities(&[1.0]) - .build(); - let family_infos = [family_info]; - - let str_pointers = enabled_extensions - .iter() - .map(|&s| { - // Safe because `enabled_extensions` entries have static lifetime. - s.as_ptr() - }) - .collect::>(); - - let mut enabled_phd_features = - PhysicalDeviceFeatures::from_extensions_and_requested_features( - self.phd_capabilities.properties.api_version, - &enabled_extensions, - features, - self.downlevel_flags, - &self.private_caps, - ); - let pre_info = vk::DeviceCreateInfo::builder() - .queue_create_infos(&family_infos) - .enabled_extension_names(&str_pointers); - let info = enabled_phd_features.add_to_device_create_builder(pre_info); - - self.instance.raw.create_device(self.raw, &info, None)? - }; - let swapchain_fn = khr::Swapchain::new(&self.instance.raw, &raw_device); let indirect_count_fn = if enabled_extensions.contains(&khr::DrawIndirectCount::name()) { @@ -841,7 +831,7 @@ impl crate::Adapter for super::Adapter { }; log::info!("Private capabilities: {:?}", self.private_caps); - let raw_queue = raw_device.get_device_queue(family_index, 0); + let raw_queue = raw_device.get_device_queue(family_index, queue_index); let shared = Arc::new(super::DeviceShared { raw: raw_device, @@ -909,6 +899,46 @@ impl crate::Adapter for super::Adapter { Ok(crate::OpenDevice { device, queue }) } +} + +impl crate::Adapter for super::Adapter { + unsafe fn open( + &self, + features: wgt::Features, + ) -> Result, crate::DeviceError> { + let enabled_extensions = self.required_device_extensions(features); + let mut enabled_phd_features = self.physical_device_features(&enabled_extensions, features); + + let family_index = 0; //TODO + let family_info = vk::DeviceQueueCreateInfo::builder() + .queue_family_index(family_index) + .queue_priorities(&[1.0]) + .build(); + let family_infos = [family_info]; + + let str_pointers = enabled_extensions + .iter() + .map(|&s| { + // Safe because `enabled_extensions` entries have static lifetime. + s.as_ptr() + }) + .collect::>(); + + let pre_info = vk::DeviceCreateInfo::builder() + .queue_create_infos(&family_infos) + .enabled_extension_names(&str_pointers); + let info = enabled_phd_features + .add_to_device_create_builder(pre_info) + .build(); + let raw_device = self.instance.raw.create_device(self.raw, &info, None)?; + + self.device_from_raw( + raw_device, + &enabled_extensions, + family_info.queue_family_index, + 0, + ) + } unsafe fn texture_format_capabilities( &self, diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 8333e096521..033d5ad9668 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -535,6 +535,40 @@ impl super::Device { config: config.clone(), }) } + + pub fn image_raw_flags(desc: &crate::TextureDescriptor) -> vk::ImageCreateFlags { + let mut raw_flags = vk::ImageCreateFlags::empty(); + if desc.dimension == wgt::TextureDimension::D2 && desc.size.depth_or_array_layers % 6 == 0 { + raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE; + } + + raw_flags + } + + /// The image handle and its memory are not handled by wgpu-hal + /// + /// # Safety + /// + /// - `vk_image` must be created respecting `desc` and `raw_flags` + /// - `raw_flags` must be a superset of `image_raw_flags(desc)`, where `desc` is the same `desc` + /// parameter passed here + pub unsafe fn texture_from_raw( + vk_image: vk::Image, + raw_flags: vk::ImageCreateFlags, + desc: &crate::TextureDescriptor, + drop_guard: super::DropGuard, + ) -> super::Texture { + super::Texture { + raw: vk_image, + handle_is_external: true, + _drop_guard: drop_guard, + block: None, + usage: desc.usage, + aspects: crate::FormatAspects::from(desc.format), + format_info: desc.format.describe(), + raw_flags, + } + } } impl crate::Device for super::Device { @@ -662,10 +696,7 @@ impl crate::Device for super::Device { _ => (1, desc.size.depth_or_array_layers), }; - let mut raw_flags = vk::ImageCreateFlags::empty(); - if desc.dimension == wgt::TextureDimension::D2 && desc.size.depth_or_array_layers % 6 == 0 { - raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE; - } + let raw_flags = Self::image_raw_flags(desc); let vk_info = vk::ImageCreateInfo::builder() .flags(raw_flags) @@ -708,6 +739,8 @@ impl crate::Device for super::Device { Ok(super::Texture { raw, + handle_is_external: false, + _drop_guard: Box::new(()), block: Some(block), usage: desc.usage, aspects: crate::FormatAspects::from(desc.format), @@ -716,10 +749,12 @@ impl crate::Device for super::Device { }) } unsafe fn destroy_texture(&self, texture: super::Texture) { - self.shared.raw.destroy_image(texture.raw, None); - self.mem_allocator - .lock() - .dealloc(&*self.shared, texture.block.unwrap()); + if !texture.handle_is_external { + self.shared.raw.destroy_image(texture.raw, None); + } + if let Some(block) = texture.block { + self.mem_allocator.lock().dealloc(&*self.shared, block); + } } unsafe fn create_texture_view( diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 763917844ab..9fcad1ae2a5 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -114,6 +114,131 @@ impl super::Swapchain { } impl super::Instance { + pub fn required_extensions( + entry: &ash::Entry, + driver_api_version: u32, + flags: crate::InstanceFlags, + ) -> Result, crate::InstanceError> { + let instance_extensions = entry + .enumerate_instance_extension_properties() + .map_err(|e| { + log::info!("enumerate_instance_extension_properties: {:?}", e); + crate::InstanceError + })?; + + // Check our extensions against the available extensions + let mut extensions: Vec<&'static CStr> = Vec::new(); + extensions.push(khr::Surface::name()); + + // Platform-specific WSI extensions + if cfg!(all( + unix, + not(target_os = "android"), + not(target_os = "macos") + )) { + extensions.push(khr::XlibSurface::name()); + extensions.push(khr::XcbSurface::name()); + extensions.push(khr::WaylandSurface::name()); + } + if cfg!(target_os = "android") { + extensions.push(khr::AndroidSurface::name()); + } + if cfg!(target_os = "windows") { + extensions.push(khr::Win32Surface::name()); + } + if cfg!(target_os = "macos") { + extensions.push(ext::MetalSurface::name()); + } + + if flags.contains(crate::InstanceFlags::DEBUG) { + extensions.push(ext::DebugUtils::name()); + } + + extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name()); + + // VK_KHR_storage_buffer_storage_class required for `Naga` on Vulkan 1.0 devices + if driver_api_version == vk::API_VERSION_1_0 { + extensions.push(vk::KhrStorageBufferStorageClassFn::name()); + } + + // Only keep available extensions. + extensions.retain(|&ext| { + if instance_extensions + .iter() + .any(|inst_ext| unsafe { CStr::from_ptr(inst_ext.extension_name.as_ptr()) == ext }) + { + true + } else { + log::info!("Unable to find extension: {}", ext.to_string_lossy()); + false + } + }); + Ok(extensions) + } + + /// # Safety + /// + /// - `raw_instance` must be created from `entry` + /// - `raw_instance` must be created respecting `driver_api_version`, `extensions` and `flags` + /// - `extensions` must be a superset of `required_extensions()` and must be created from the + /// same entry, driver_api_version and flags. + pub unsafe fn from_raw( + entry: ash::Entry, + raw_instance: ash::Instance, + driver_api_version: u32, + extensions: Vec<&'static CStr>, + flags: crate::InstanceFlags, + drop_guard: super::DropGuard, + ) -> Result { + if driver_api_version == vk::API_VERSION_1_0 + && !extensions.contains(&vk::KhrStorageBufferStorageClassFn::name()) + { + log::warn!("Required VK_KHR_storage_buffer_storage_class extension is not supported"); + return Err(crate::InstanceError); + } + + let debug_utils = if extensions.contains(&ext::DebugUtils::name()) { + let extension = ext::DebugUtils::new(&entry, &raw_instance); + let vk_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() + .flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty()) + .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) + .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all()) + .pfn_user_callback(Some(debug_utils_messenger_callback)); + let messenger = extension + .create_debug_utils_messenger(&vk_info, None) + .unwrap(); + Some(super::DebugUtils { + extension, + messenger, + }) + } else { + None + }; + + let get_physical_device_properties = extensions + .iter() + .find(|&&ext| ext == vk::KhrGetPhysicalDeviceProperties2Fn::name()) + .map(|_| { + vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| { + mem::transmute( + entry.get_instance_proc_addr(raw_instance.handle(), name.as_ptr()), + ) + }) + }); + + Ok(Self { + shared: Arc::new(super::InstanceShared { + raw: raw_instance, + _drop_guard: drop_guard, + flags, + debug_utils, + get_physical_device_properties, + entry, + }), + extensions, + }) + } + #[allow(dead_code)] fn create_surface_from_xlib( &self, @@ -339,76 +464,13 @@ impl crate::Instance for super::Instance { }) }); - let instance_extensions = entry - .enumerate_instance_extension_properties() - .map_err(|e| { - log::info!("enumerate_instance_extension_properties: {:?}", e); - crate::InstanceError - })?; + let extensions = Self::required_extensions(&entry, driver_api_version, desc.flags)?; let instance_layers = entry.enumerate_instance_layer_properties().map_err(|e| { log::info!("enumerate_instance_layer_properties: {:?}", e); crate::InstanceError })?; - // Check our extensions against the available extensions - let extensions = { - let mut extensions: Vec<&'static CStr> = Vec::new(); - extensions.push(khr::Surface::name()); - - // Platform-specific WSI extensions - if cfg!(all( - unix, - not(target_os = "android"), - not(target_os = "macos") - )) { - extensions.push(khr::XlibSurface::name()); - extensions.push(khr::XcbSurface::name()); - extensions.push(khr::WaylandSurface::name()); - } - if cfg!(target_os = "android") { - extensions.push(khr::AndroidSurface::name()); - } - if cfg!(target_os = "windows") { - extensions.push(khr::Win32Surface::name()); - } - if cfg!(target_os = "macos") { - extensions.push(ext::MetalSurface::name()); - } - - if desc.flags.contains(crate::InstanceFlags::DEBUG) { - extensions.push(ext::DebugUtils::name()); - } - - extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name()); - - // VK_KHR_storage_buffer_storage_class required for `Naga` on Vulkan 1.0 devices - if driver_api_version == vk::API_VERSION_1_0 { - extensions.push(vk::KhrStorageBufferStorageClassFn::name()); - } - - // Only keep available extensions. - extensions.retain(|&ext| { - if instance_extensions - .iter() - .any(|inst_ext| CStr::from_ptr(inst_ext.extension_name.as_ptr()) == ext) - { - true - } else { - log::info!("Unable to find extension: {}", ext.to_string_lossy()); - false - } - }); - extensions - }; - - if driver_api_version == vk::API_VERSION_1_0 - && !extensions.contains(&vk::KhrStorageBufferStorageClassFn::name()) - { - log::warn!("Required VK_KHR_storage_buffer_storage_class extension is not supported"); - return Err(crate::InstanceError); - } - // Check requested layers against the available layers let layers = { let mut layers: Vec<&'static CStr> = Vec::new(); @@ -453,45 +515,14 @@ impl crate::Instance for super::Instance { })? }; - let debug_utils = if extensions.contains(&ext::DebugUtils::name()) { - let extension = ext::DebugUtils::new(&entry, &vk_instance); - let vk_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() - .flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty()) - .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) - .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all()) - .pfn_user_callback(Some(debug_utils_messenger_callback)); - let messenger = extension - .create_debug_utils_messenger(&vk_info, None) - .unwrap(); - Some(super::DebugUtils { - extension, - messenger, - }) - } else { - None - }; - - let get_physical_device_properties = extensions - .iter() - .find(|&&ext| ext == vk::KhrGetPhysicalDeviceProperties2Fn::name()) - .map(|_| { - vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| { - mem::transmute( - entry.get_instance_proc_addr(vk_instance.handle(), name.as_ptr()), - ) - }) - }); - - Ok(Self { - shared: Arc::new(super::InstanceShared { - raw: vk_instance, - flags: desc.flags, - debug_utils, - get_physical_device_properties, - entry, - }), + Self::from_raw( + entry, + vk_instance, + driver_api_version, extensions, - }) + desc.flags, + Box::new(()), + ) } unsafe fn create_surface( @@ -645,6 +676,8 @@ impl crate::Surface for super::Surface { index, texture: super::Texture { raw: sc.images[index as usize], + handle_is_external: true, + _drop_guard: Box::new(()), block: None, usage: sc.config.usage, aspects: crate::FormatAspects::COLOR, diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 7818b5460de..d9549d8a4c1 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -44,6 +44,8 @@ use parking_lot::Mutex; const MILLIS_TO_NANOS: u64 = 1_000_000; const MAX_TOTAL_ATTACHMENTS: usize = crate::MAX_COLOR_TARGETS * 2 + 1; +pub type DropGuard = Box; + #[derive(Clone)] pub struct Api; @@ -80,6 +82,7 @@ struct DebugUtils { struct InstanceShared { raw: ash::Instance, + _drop_guard: DropGuard, flags: crate::InstanceFlags, debug_utils: Option, get_physical_device_properties: Option, @@ -257,6 +260,8 @@ pub struct Buffer { #[derive(Debug)] pub struct Texture { raw: vk::Image, + handle_is_external: bool, + _drop_guard: DropGuard, block: Option>, usage: crate::TextureUses, aspects: crate::FormatAspects, diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 6d4a00a3926..c5e6f234fb6 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -39,6 +39,14 @@ impl fmt::Debug for Context { } impl Context { + pub unsafe fn from_hal_instance(hal_instance: A::Instance) -> Self { + Self(wgc::hub::Global::from_hal_instance::( + "wgpu", + wgc::hub::IdentityManagerFactory, + hal_instance, + )) + } + pub(crate) fn global(&self) -> &wgc::hub::Global { &self.0 } @@ -50,6 +58,67 @@ impl Context { })) } + pub unsafe fn adapter_from_hal( + &self, + hal_adapter: hal::ExposedAdapter, + ) -> wgc::id::AdapterId { + self.0.adapter_from_hal(hal_adapter, PhantomData) + } + + pub unsafe fn device_from_hal( + &self, + adapter: &wgc::id::AdapterId, + hal_device: hal::OpenDevice, + desc: &crate::DeviceDescriptor, + trace_dir: Option<&std::path::Path>, + ) -> Result<(Device, wgc::id::QueueId), crate::RequestDeviceError> { + let global = &self.0; + let (device_id, error) = global.device_from_hal( + *adapter, + hal_device, + &desc.map_label(|l| l.map(Borrowed)), + trace_dir, + PhantomData, + ); + if let Some(err) = error { + self.handle_error_fatal(err, "Adapter::device_from_hal"); + } + let device = Device { + id: device_id, + error_sink: Arc::new(Mutex::new(ErrorSinkRaw::new())), + features: desc.features, + }; + Ok((device, device_id)) + } + + pub unsafe fn texture_from_hal( + &self, + hal_texture: A::Texture, + device: &Device, + desc: &TextureDescriptor, + ) -> Texture { + let global = &self.0; + let (id, error) = global.texture_from_hal::( + hal_texture, + device.id, + &desc.map_label(|l| l.map(Borrowed)), + PhantomData, + ); + if let Some(cause) = error { + self.handle_error( + &device.error_sink, + cause, + LABEL, + desc.label, + "Device::texture_from_hal", + ); + } + Texture { + id, + error_sink: Arc::clone(&device.error_sink), + } + } + pub fn generate_report(&self) -> wgc::hub::GlobalReport { self.0.generate_report() } @@ -589,7 +658,7 @@ fn map_pass_channel( } #[derive(Debug)] -pub(crate) struct Device { +pub struct Device { id: wgc::id::DeviceId, error_sink: ErrorSink, features: Features, @@ -602,7 +671,7 @@ pub(crate) struct Buffer { } #[derive(Debug)] -pub(crate) struct Texture { +pub struct Texture { id: wgc::id::TextureId, error_sink: ErrorSink, } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 0440bb82b27..ca33310278d 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1389,6 +1389,22 @@ impl Instance { } } + /// Create an new instance of wgpu from a wgpu-hal instance. + /// + /// # Arguments + /// + /// - `hal_instance` - wgpu-hal instance. + /// + /// # Safety + /// + /// Refer to the creation of wgpu-hal Instance for every backend. + #[cfg(not(target_arch = "wasm32"))] + pub unsafe fn from_hal(hal_instance: A::Instance) -> Self { + Instance { + context: Arc::new(C::from_hal_instance::(hal_instance)), + } + } + /// Retrieves all available [`Adapter`]s that match the given [`Backends`]. /// /// # Arguments @@ -1420,6 +1436,21 @@ impl Instance { async move { adapter.await.map(|id| Adapter { context, id }) } } + /// Converts a wgpu-hal `ExposedAdapter` to a wgpu [`Adapter`]. + /// + /// # Safety + /// + /// `hal_adapter` must be created from this instance internal handle. + #[cfg(not(target_arch = "wasm32"))] + pub unsafe fn adapter_from_hal( + &self, + hal_adapter: hal::ExposedAdapter, + ) -> Adapter { + let context = Arc::clone(&self.context); + let id = context.adapter_from_hal(hal_adapter); + Adapter { context, id } + } + /// Creates a surface from a raw window handle. /// /// # Safety @@ -1503,6 +1534,36 @@ impl Adapter { } } + /// Create a wgpu [`Device`] and [`Queue`] from a wgpu-hal `OpenDevice` + /// + /// # Safety + /// + /// - `hal_device` must be created from this adapter internal handle. + /// - `desc.features` must be a subset of `hal_device` features. + #[cfg(not(target_arch = "wasm32"))] + pub unsafe fn device_from_hal( + &self, + hal_device: hal::OpenDevice, + desc: &DeviceDescriptor, + trace_path: Option<&std::path::Path>, + ) -> Result<(Device, Queue), RequestDeviceError> { + let context = Arc::clone(&self.context); + self.context + .device_from_hal(&self.id, hal_device, desc, trace_path) + .map(|(device_id, queue_id)| { + ( + Device { + context: Arc::clone(&context), + id: device_id, + }, + Queue { + context, + id: queue_id, + }, + ) + }) + } + /// Returns an optimal texture format to use for the [`SwapChain`] with this adapter. /// /// Returns None if the surface is incompatible with the adapter. @@ -1687,6 +1748,27 @@ impl Device { } } + /// Creates a [`Texture`] from a wgpu-hal Texture. + /// + /// # Safety + /// + /// - `hal_texture` must be created from this device internal handle + /// - `hal_texture` must be created respecting `desc` + #[cfg(not(target_arch = "wasm32"))] + pub unsafe fn texture_from_hal( + &self, + hal_texture: A::Texture, + desc: &TextureDescriptor, + ) -> Texture { + Texture { + context: Arc::clone(&self.context), + id: self + .context + .texture_from_hal::(hal_texture, &self.id, desc), + owned: true, + } + } + /// Creates a new [`Sampler`]. /// /// `desc` specifies the behavior of the sampler.