1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use crate::{ 6 backend, conv, 7 device::{Device, DeviceDescriptor}, 8 hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Token}, 9 id::{AdapterId, DeviceId, SurfaceId, Valid}, 10 LabelHelpers, LifeGuard, PrivateFeatures, Stored, DOWNLEVEL_WARNING_MESSAGE, MAX_BIND_GROUPS, 11 }; 12 13 use wgt::{Backend, BackendBit, PowerPreference, BIND_BUFFER_ALIGNMENT}; 14 15 use hal::{ 16 adapter::PhysicalDevice as _, queue::QueueFamily as _, window::Surface as _, Instance as _, 17 }; 18 use thiserror::Error; 19 20 /// Size that is guaranteed to be available in push constants. 21 /// 22 /// This is needed because non-vulkan backends might not 23 /// provide a push-constant size limit. 24 const MIN_PUSH_CONSTANT_SIZE: u32 = 128; 25 26 pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>; 27 28 #[derive(Debug)] 29 pub struct Instance { 30 #[cfg(vulkan)] 31 pub vulkan: Option<gfx_backend_vulkan::Instance>, 32 #[cfg(metal)] 33 pub metal: Option<gfx_backend_metal::Instance>, 34 #[cfg(dx12)] 35 pub dx12: Option<gfx_backend_dx12::Instance>, 36 #[cfg(dx11)] 37 pub dx11: Option<gfx_backend_dx11::Instance>, 38 #[cfg(gl)] 39 pub gl: Option<gfx_backend_gl::Instance>, 40 } 41 42 impl Instance { new(name: &str, version: u32, backends: BackendBit) -> Self43 pub fn new(name: &str, version: u32, backends: BackendBit) -> Self { 44 backends_map! { 45 let map = |(backend, backend_create)| { 46 if backends.contains(backend.into()) { 47 backend_create(name, version).ok() 48 } else { 49 None 50 } 51 }; 52 Self { 53 #[cfg(vulkan)] 54 vulkan: map((Backend::Vulkan, gfx_backend_vulkan::Instance::create)), 55 #[cfg(metal)] 56 metal: map((Backend::Metal, gfx_backend_metal::Instance::create)), 57 #[cfg(dx12)] 58 dx12: map((Backend::Dx12, gfx_backend_dx12::Instance::create)), 59 #[cfg(dx11)] 60 dx11: map((Backend::Dx11, gfx_backend_dx11::Instance::create)), 61 #[cfg(gl)] 62 gl: map((Backend::Gl, gfx_backend_gl::Instance::create)), 63 } 64 } 65 } 66 destroy_surface(&self, surface: Surface)67 pub(crate) fn destroy_surface(&self, surface: Surface) { 68 backends_map! { 69 let map = |(surface_backend, self_backend)| { 70 unsafe { 71 if let Some(suf) = surface_backend { 72 self_backend.as_ref().unwrap().destroy_surface(suf); 73 } 74 } 75 }; 76 77 #[cfg(vulkan)] 78 map((surface.vulkan, &self.vulkan)), 79 #[cfg(metal)] 80 map((surface.metal, &self.metal)), 81 #[cfg(dx12)] 82 map((surface.dx12, &self.dx12)), 83 #[cfg(dx11)] 84 map((surface.dx11, &self.dx11)), 85 #[cfg(gl)] 86 map((surface.gl, &self.gl)), 87 } 88 } 89 } 90 91 type GfxSurface<B> = <B as hal::Backend>::Surface; 92 93 #[derive(Debug)] 94 pub struct Surface { 95 #[cfg(vulkan)] 96 pub vulkan: Option<GfxSurface<backend::Vulkan>>, 97 #[cfg(metal)] 98 pub metal: Option<GfxSurface<backend::Metal>>, 99 #[cfg(dx12)] 100 pub dx12: Option<GfxSurface<backend::Dx12>>, 101 #[cfg(dx11)] 102 pub dx11: Option<GfxSurface<backend::Dx11>>, 103 #[cfg(gl)] 104 pub gl: Option<GfxSurface<backend::Gl>>, 105 } 106 107 impl crate::hub::Resource for Surface { 108 const TYPE: &'static str = "Surface"; 109 life_guard(&self) -> &LifeGuard110 fn life_guard(&self) -> &LifeGuard { 111 unreachable!() 112 } 113 label(&self) -> &str114 fn label(&self) -> &str { 115 "<Surface>" 116 } 117 } 118 119 const FEATURE_MAP: &[(wgt::Features, hal::Features)] = &[ 120 (wgt::Features::DEPTH_CLAMPING, hal::Features::DEPTH_CLAMP), 121 ( 122 wgt::Features::TEXTURE_COMPRESSION_BC, 123 hal::Features::FORMAT_BC, 124 ), 125 ( 126 wgt::Features::TEXTURE_COMPRESSION_ETC2, 127 hal::Features::FORMAT_ETC2, 128 ), 129 ( 130 wgt::Features::TEXTURE_COMPRESSION_ASTC_LDR, 131 hal::Features::FORMAT_ASTC_LDR, 132 ), 133 ( 134 wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY, 135 hal::Features::TEXTURE_DESCRIPTOR_ARRAY, 136 ), 137 ( 138 wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING, 139 hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING, 140 ), 141 ( 142 wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, 143 hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING, 144 ), 145 ( 146 wgt::Features::UNSIZED_BINDING_ARRAY, 147 hal::Features::UNSIZED_DESCRIPTOR_ARRAY, 148 ), 149 ( 150 wgt::Features::MULTI_DRAW_INDIRECT, 151 hal::Features::MULTI_DRAW_INDIRECT, 152 ), 153 ( 154 wgt::Features::MULTI_DRAW_INDIRECT_COUNT, 155 hal::Features::DRAW_INDIRECT_COUNT, 156 ), 157 ( 158 wgt::Features::NON_FILL_POLYGON_MODE, 159 hal::Features::NON_FILL_POLYGON_MODE, 160 ), 161 ( 162 wgt::Features::PIPELINE_STATISTICS_QUERY, 163 hal::Features::PIPELINE_STATISTICS_QUERY, 164 ), 165 (wgt::Features::SHADER_FLOAT64, hal::Features::SHADER_FLOAT64), 166 ( 167 wgt::Features::CONSERVATIVE_RASTERIZATION, 168 hal::Features::CONSERVATIVE_RASTERIZATION, 169 ), 170 ( 171 wgt::Features::BUFFER_BINDING_ARRAY, 172 hal::Features::BUFFER_DESCRIPTOR_ARRAY, 173 ), 174 ( 175 wgt::Features::UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING, 176 hal::Features::SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING, 177 ), 178 ( 179 wgt::Features::UNIFORM_BUFFER_ARRAY_NON_UNIFORM_INDEXING, 180 hal::Features::UNIFORM_BUFFER_DESCRIPTOR_INDEXING, 181 ), 182 ( 183 wgt::Features::STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING, 184 hal::Features::SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING, 185 ), 186 ( 187 wgt::Features::STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, 188 hal::Features::STORAGE_BUFFER_DESCRIPTOR_INDEXING, 189 ), 190 ( 191 wgt::Features::VERTEX_WRITABLE_STORAGE, 192 hal::Features::VERTEX_STORES_AND_ATOMICS, 193 ), 194 ( 195 wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER, 196 hal::Features::SAMPLER_BORDER_COLOR, 197 ), 198 ]; 199 200 #[derive(Debug)] 201 pub struct Adapter<B: hal::Backend> { 202 pub(crate) raw: hal::adapter::Adapter<B>, 203 features: wgt::Features, 204 pub(crate) private_features: PrivateFeatures, 205 limits: wgt::Limits, 206 downlevel: wgt::DownlevelProperties, 207 life_guard: LifeGuard, 208 } 209 210 impl<B: GfxBackend> Adapter<B> { new(raw: hal::adapter::Adapter<B>) -> Self211 fn new(raw: hal::adapter::Adapter<B>) -> Self { 212 profiling::scope!("new", "Adapter"); 213 214 let adapter_features = raw.physical_device.features(); 215 let properties = raw.physical_device.properties(); 216 217 let mut features = wgt::Features::default() 218 | wgt::Features::MAPPABLE_PRIMARY_BUFFERS 219 | wgt::Features::PUSH_CONSTANTS 220 | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES 221 | wgt::Features::CLEAR_COMMANDS; 222 for &(hi, lo) in FEATURE_MAP.iter() { 223 features.set(hi, adapter_features.contains(lo)); 224 } 225 features.set( 226 wgt::Features::TIMESTAMP_QUERY, 227 properties.limits.timestamp_compute_and_graphics, 228 ); 229 230 let private_features = PrivateFeatures { 231 anisotropic_filtering: adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY), 232 texture_d24: raw 233 .physical_device 234 .format_properties(Some(hal::format::Format::X8D24Unorm)) 235 .optimal_tiling 236 .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), 237 texture_d24_s8: raw 238 .physical_device 239 .format_properties(Some(hal::format::Format::D24UnormS8Uint)) 240 .optimal_tiling 241 .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), 242 }; 243 244 let default_limits = wgt::Limits::default(); 245 246 // All these casts to u32 are safe as the underlying vulkan types are u32s. 247 // If another backend provides larger limits than u32, we need to clamp them to u32::MAX. 248 // TODO: fix all gfx-hal backends to produce limits we care about, and remove .max 249 let desc_limits = &properties.limits.descriptor_limits; 250 let limits = wgt::Limits { 251 max_texture_dimension_1d: properties 252 .limits 253 .max_image_1d_size 254 .max(default_limits.max_texture_dimension_1d), 255 max_texture_dimension_2d: properties 256 .limits 257 .max_image_2d_size 258 .max(default_limits.max_texture_dimension_1d), 259 max_texture_dimension_3d: properties 260 .limits 261 .max_image_3d_size 262 .max(default_limits.max_texture_dimension_1d), 263 max_texture_array_layers: (properties.limits.max_image_array_layers as u32) 264 .max(default_limits.max_texture_array_layers), 265 max_bind_groups: (properties.limits.max_bound_descriptor_sets as u32) 266 .min(MAX_BIND_GROUPS as u32) 267 .max(default_limits.max_bind_groups), 268 max_dynamic_uniform_buffers_per_pipeline_layout: desc_limits 269 .max_descriptor_set_uniform_buffers_dynamic 270 .max(default_limits.max_dynamic_uniform_buffers_per_pipeline_layout), 271 max_dynamic_storage_buffers_per_pipeline_layout: desc_limits 272 .max_descriptor_set_storage_buffers_dynamic 273 .max(default_limits.max_dynamic_storage_buffers_per_pipeline_layout), 274 max_sampled_textures_per_shader_stage: desc_limits 275 .max_per_stage_descriptor_sampled_images 276 .max(default_limits.max_sampled_textures_per_shader_stage), 277 max_samplers_per_shader_stage: desc_limits 278 .max_per_stage_descriptor_samplers 279 .max(default_limits.max_samplers_per_shader_stage), 280 max_storage_buffers_per_shader_stage: desc_limits 281 .max_per_stage_descriptor_storage_buffers 282 .max(default_limits.max_storage_buffers_per_shader_stage), 283 max_storage_textures_per_shader_stage: desc_limits 284 .max_per_stage_descriptor_storage_images 285 .max(default_limits.max_storage_textures_per_shader_stage), 286 max_uniform_buffers_per_shader_stage: desc_limits 287 .max_per_stage_descriptor_uniform_buffers 288 .max(default_limits.max_uniform_buffers_per_shader_stage), 289 max_uniform_buffer_binding_size: (properties.limits.max_uniform_buffer_range as u32) 290 .max(default_limits.max_uniform_buffer_binding_size), 291 max_storage_buffer_binding_size: (properties.limits.max_storage_buffer_range as u32) 292 .max(default_limits.max_storage_buffer_binding_size), 293 max_vertex_buffers: (properties.limits.max_vertex_input_bindings as u32) 294 .max(default_limits.max_vertex_buffers), 295 max_vertex_attributes: (properties.limits.max_vertex_input_attributes as u32) 296 .max(default_limits.max_vertex_attributes), 297 max_vertex_buffer_array_stride: (properties.limits.max_vertex_input_binding_stride 298 as u32) 299 .max(default_limits.max_vertex_buffer_array_stride), 300 max_push_constant_size: (properties.limits.max_push_constants_size as u32) 301 .max(MIN_PUSH_CONSTANT_SIZE), // As an extension, the default is always 0, so define a separate minimum. 302 }; 303 304 let mut downlevel_flags = wgt::DownlevelFlags::empty(); 305 downlevel_flags.set( 306 wgt::DownlevelFlags::COMPUTE_SHADERS, 307 properties.downlevel.compute_shaders, 308 ); 309 downlevel_flags.set( 310 wgt::DownlevelFlags::STORAGE_IMAGES, 311 properties.downlevel.storage_images, 312 ); 313 downlevel_flags.set( 314 wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL, 315 properties.downlevel.read_only_depth_stencil, 316 ); 317 downlevel_flags.set( 318 wgt::DownlevelFlags::DEVICE_LOCAL_IMAGE_COPIES, 319 properties.downlevel.device_local_image_copies, 320 ); 321 downlevel_flags.set( 322 wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES, 323 properties.downlevel.non_power_of_two_mipmapped_textures, 324 ); 325 downlevel_flags.set( 326 wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES, 327 adapter_features.contains(hal::Features::IMAGE_CUBE_ARRAY), 328 ); 329 downlevel_flags.set( 330 wgt::DownlevelFlags::ANISOTROPIC_FILTERING, 331 private_features.anisotropic_filtering, 332 ); 333 334 let downlevel = wgt::DownlevelProperties { 335 flags: downlevel_flags, 336 shader_model: match properties.downlevel.shader_model { 337 hal::DownlevelShaderModel::ShaderModel2 => wgt::ShaderModel::Sm2, 338 hal::DownlevelShaderModel::ShaderModel4 => wgt::ShaderModel::Sm4, 339 hal::DownlevelShaderModel::ShaderModel5 => wgt::ShaderModel::Sm5, 340 }, 341 }; 342 343 Self { 344 raw, 345 features, 346 private_features, 347 limits, 348 downlevel, 349 life_guard: LifeGuard::new("<Adapter>"), 350 } 351 } 352 get_swap_chain_preferred_format( &self, surface: &mut Surface, ) -> Result<wgt::TextureFormat, GetSwapChainPreferredFormatError>353 pub fn get_swap_chain_preferred_format( 354 &self, 355 surface: &mut Surface, 356 ) -> Result<wgt::TextureFormat, GetSwapChainPreferredFormatError> { 357 let formats = { 358 let surface = B::get_surface_mut(surface); 359 let queue_family = &self.raw.queue_families[0]; 360 if !surface.supports_queue_family(queue_family) { 361 return Err(GetSwapChainPreferredFormatError::UnsupportedQueueFamily); 362 } 363 surface.supported_formats(&self.raw.physical_device) 364 }; 365 if let Some(formats) = formats { 366 // Check the four formats mentioned in the WebGPU spec: 367 // Bgra8UnormSrgb, Rgba8UnormSrgb, Bgra8Unorm, Rgba8Unorm 368 // Also, prefer sRGB over linear as it is better in 369 // representing perceived colors. 370 if formats.contains(&hal::format::Format::Bgra8Srgb) { 371 return Ok(wgt::TextureFormat::Bgra8UnormSrgb); 372 } 373 if formats.contains(&hal::format::Format::Rgba8Srgb) { 374 return Ok(wgt::TextureFormat::Rgba8UnormSrgb); 375 } 376 if formats.contains(&hal::format::Format::Bgra8Unorm) { 377 return Ok(wgt::TextureFormat::Bgra8Unorm); 378 } 379 if formats.contains(&hal::format::Format::Rgba8Unorm) { 380 return Ok(wgt::TextureFormat::Rgba8Unorm); 381 } 382 return Err(GetSwapChainPreferredFormatError::NotFound); 383 } 384 385 // If no formats were returned, use Bgra8UnormSrgb 386 Ok(wgt::TextureFormat::Bgra8UnormSrgb) 387 } 388 get_texture_format_features( &self, format: wgt::TextureFormat, ) -> wgt::TextureFormatFeatures389 pub(crate) fn get_texture_format_features( 390 &self, 391 format: wgt::TextureFormat, 392 ) -> wgt::TextureFormatFeatures { 393 let texture_format_properties = self 394 .raw 395 .physical_device 396 .format_properties(Some(conv::map_texture_format( 397 format, 398 self.private_features, 399 ))) 400 .optimal_tiling; 401 402 let mut allowed_usages = format.describe().guaranteed_format_features.allowed_usages; 403 if texture_format_properties.contains(hal::format::ImageFeature::SAMPLED) { 404 allowed_usages |= wgt::TextureUsage::SAMPLED; 405 } 406 if texture_format_properties.contains(hal::format::ImageFeature::STORAGE) { 407 allowed_usages |= wgt::TextureUsage::STORAGE; 408 } 409 if texture_format_properties.contains(hal::format::ImageFeature::COLOR_ATTACHMENT) { 410 allowed_usages |= wgt::TextureUsage::RENDER_ATTACHMENT; 411 } 412 if texture_format_properties.contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT) { 413 allowed_usages |= wgt::TextureUsage::RENDER_ATTACHMENT; 414 } 415 416 let mut flags = wgt::TextureFormatFeatureFlags::empty(); 417 if texture_format_properties.contains(hal::format::ImageFeature::STORAGE_ATOMIC) { 418 flags |= wgt::TextureFormatFeatureFlags::STORAGE_ATOMICS; 419 } 420 if texture_format_properties.contains(hal::format::ImageFeature::STORAGE_READ_WRITE) { 421 flags |= wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE; 422 } 423 424 let filterable = 425 texture_format_properties.contains(hal::format::ImageFeature::SAMPLED_LINEAR); 426 427 wgt::TextureFormatFeatures { 428 allowed_usages, 429 flags, 430 filterable, 431 } 432 } 433 create_device( &self, self_id: AdapterId, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, ) -> Result<Device<B>, RequestDeviceError>434 fn create_device( 435 &self, 436 self_id: AdapterId, 437 desc: &DeviceDescriptor, 438 trace_path: Option<&std::path::Path>, 439 ) -> Result<Device<B>, RequestDeviceError> { 440 // Verify all features were exposed by the adapter 441 if !self.features.contains(desc.features) { 442 return Err(RequestDeviceError::UnsupportedFeature( 443 desc.features - self.features, 444 )); 445 } 446 447 if !self.downlevel.is_webgpu_compliant() { 448 log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE); 449 } 450 451 // Verify feature preconditions 452 if desc 453 .features 454 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS) 455 && self.raw.info.device_type == hal::adapter::DeviceType::DiscreteGpu 456 { 457 log::warn!("Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. This is a massive performance footgun and likely not what you wanted"); 458 } 459 460 let phd = &self.raw.physical_device; 461 let available_features = phd.features(); 462 463 // Check features that are always needed 464 let wishful_features = hal::Features::ROBUST_BUFFER_ACCESS 465 | hal::Features::FRAGMENT_STORES_AND_ATOMICS 466 | hal::Features::NDC_Y_UP 467 | hal::Features::INDEPENDENT_BLENDING 468 | hal::Features::SAMPLER_ANISOTROPY 469 | hal::Features::IMAGE_CUBE_ARRAY 470 | hal::Features::SAMPLE_RATE_SHADING; 471 let mut enabled_features = available_features & wishful_features; 472 if enabled_features != wishful_features { 473 log::warn!( 474 "Missing internal features: {:?}", 475 wishful_features - enabled_features 476 ); 477 } 478 479 // Enable low-level features 480 for &(hi, lo) in FEATURE_MAP.iter() { 481 enabled_features.set(lo, desc.features.contains(hi)); 482 } 483 484 let family = self 485 .raw 486 .queue_families 487 .iter() 488 .find(|family| family.queue_type().supports_graphics()) 489 .ok_or(RequestDeviceError::NoGraphicsQueue)?; 490 491 let mut gpu = 492 unsafe { phd.open(&[(family, &[1.0])], enabled_features) }.map_err(|err| { 493 use hal::device::CreationError::*; 494 match err { 495 DeviceLost => RequestDeviceError::DeviceLost, 496 InitializationFailed => RequestDeviceError::Internal, 497 OutOfMemory(_) => RequestDeviceError::OutOfMemory, 498 _ => panic!("failed to create `gfx-hal` device: {}", err), 499 } 500 })?; 501 502 if let Some(_) = desc.label { 503 //TODO 504 } 505 506 let limits = phd.properties().limits; 507 assert_eq!( 508 0, 509 BIND_BUFFER_ALIGNMENT % limits.min_storage_buffer_offset_alignment, 510 "Adapter storage buffer offset alignment not compatible with WGPU" 511 ); 512 assert_eq!( 513 0, 514 BIND_BUFFER_ALIGNMENT % limits.min_uniform_buffer_offset_alignment, 515 "Adapter uniform buffer offset alignment not compatible with WGPU" 516 ); 517 if self.limits < desc.limits { 518 return Err(RequestDeviceError::LimitsExceeded); 519 } 520 521 let mem_props = phd.memory_properties(); 522 523 Device::new( 524 gpu.device, 525 Stored { 526 value: Valid(self_id), 527 ref_count: self.life_guard.add_ref(), 528 }, 529 gpu.queue_groups.swap_remove(0), 530 mem_props, 531 limits, 532 self.private_features, 533 self.downlevel, 534 desc, 535 trace_path, 536 ) 537 .or(Err(RequestDeviceError::OutOfMemory)) 538 } 539 } 540 541 impl<B: hal::Backend> crate::hub::Resource for Adapter<B> { 542 const TYPE: &'static str = "Adapter"; 543 life_guard(&self) -> &LifeGuard544 fn life_guard(&self) -> &LifeGuard { 545 &self.life_guard 546 } 547 } 548 549 #[derive(Clone, Debug, Error)] 550 pub enum GetSwapChainPreferredFormatError { 551 #[error("no suitable format found")] 552 NotFound, 553 #[error("invalid adapter")] 554 InvalidAdapter, 555 #[error("invalid surface")] 556 InvalidSurface, 557 #[error("surface does not support the adapter's queue family")] 558 UnsupportedQueueFamily, 559 } 560 561 #[derive(Clone, Debug, Error)] 562 /// Error when requesting a device from the adaptor 563 pub enum RequestDeviceError { 564 #[error("parent adapter is invalid")] 565 InvalidAdapter, 566 #[error("connection to device was lost during initialization")] 567 DeviceLost, 568 #[error("device initialization failed due to implementation specific errors")] 569 Internal, 570 #[error("some of the requested device limits are not supported")] 571 LimitsExceeded, 572 #[error("device has no queue supporting graphics")] 573 NoGraphicsQueue, 574 #[error("not enough memory left")] 575 OutOfMemory, 576 #[error("unsupported features were requested: {0:?}")] 577 UnsupportedFeature(wgt::Features), 578 } 579 580 pub enum AdapterInputs<'a, I> { 581 IdSet(&'a [I], fn(&I) -> Backend), 582 Mask(BackendBit, fn(Backend) -> I), 583 } 584 585 impl<I: Clone> AdapterInputs<'_, I> { find(&self, b: Backend) -> Option<I>586 fn find(&self, b: Backend) -> Option<I> { 587 match *self { 588 Self::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).cloned(), 589 Self::Mask(bits, ref fun) => { 590 if bits.contains(b.into()) { 591 Some(fun(b)) 592 } else { 593 None 594 } 595 } 596 } 597 } 598 } 599 600 #[derive(Clone, Debug, Error)] 601 #[error("adapter is invalid")] 602 pub struct InvalidAdapter; 603 604 #[derive(Clone, Debug, Error)] 605 pub enum RequestAdapterError { 606 #[error("no suitable adapter found")] 607 NotFound, 608 #[error("surface {0:?} is invalid")] 609 InvalidSurface(SurfaceId), 610 } 611 612 impl<G: GlobalIdentityHandlerFactory> Global<G> { 613 #[cfg(feature = "raw-window-handle")] instance_create_surface( &self, handle: &impl raw_window_handle::HasRawWindowHandle, id_in: Input<G, SurfaceId>, ) -> SurfaceId614 pub fn instance_create_surface( 615 &self, 616 handle: &impl raw_window_handle::HasRawWindowHandle, 617 id_in: Input<G, SurfaceId>, 618 ) -> SurfaceId { 619 profiling::scope!("create_surface", "Instance"); 620 621 let surface = unsafe { 622 backends_map! { 623 let map = |inst| { 624 inst 625 .as_ref() 626 .and_then(|inst| inst.create_surface(handle).map_err(|e| { 627 log::warn!("Error: {:?}", e); 628 }).ok()) 629 }; 630 631 Surface { 632 #[cfg(vulkan)] 633 vulkan: map(&self.instance.vulkan), 634 #[cfg(metal)] 635 metal: map(&self.instance.metal), 636 #[cfg(dx12)] 637 dx12: map(&self.instance.dx12), 638 #[cfg(dx11)] 639 dx11: map(&self.instance.dx11), 640 #[cfg(gl)] 641 gl: map(&self.instance.gl), 642 } 643 } 644 }; 645 646 let mut token = Token::root(); 647 let id = self.surfaces.prepare(id_in).assign(surface, &mut token); 648 id.0 649 } 650 651 #[cfg(metal)] instance_create_surface_metal( &self, layer: *mut std::ffi::c_void, id_in: Input<G, SurfaceId>, ) -> SurfaceId652 pub fn instance_create_surface_metal( 653 &self, 654 layer: *mut std::ffi::c_void, 655 id_in: Input<G, SurfaceId>, 656 ) -> SurfaceId { 657 profiling::scope!("create_surface_metal", "Instance"); 658 659 let surface = Surface { 660 metal: self.instance.metal.as_ref().map(|inst| { 661 // we don't want to link to metal-rs for this 662 #[allow(clippy::transmute_ptr_to_ref)] 663 inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) 664 }), 665 }; 666 667 let mut token = Token::root(); 668 let id = self.surfaces.prepare(id_in).assign(surface, &mut token); 669 id.0 670 } 671 surface_drop(&self, id: SurfaceId)672 pub fn surface_drop(&self, id: SurfaceId) { 673 profiling::scope!("drop", "Surface"); 674 let mut token = Token::root(); 675 let (surface, _) = self.surfaces.unregister(id, &mut token); 676 self.instance.destroy_surface(surface.unwrap()); 677 } 678 enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId>679 pub fn enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId> { 680 profiling::scope!("enumerate_adapters", "Instance"); 681 682 let instance = &self.instance; 683 let mut token = Token::root(); 684 let mut adapters = Vec::new(); 685 686 backends_map! { 687 let map = |(instance_field, backend, backend_info, backend_hub)| { 688 if let Some(ref inst) = *instance_field { 689 let hub = backend_hub(self); 690 if let Some(id_backend) = inputs.find(backend) { 691 for raw in inst.enumerate_adapters() { 692 let adapter = Adapter::new(raw); 693 log::info!("Adapter {} {:?}", backend_info, adapter.raw.info); 694 let id = hub.adapters 695 .prepare(id_backend.clone()) 696 .assign(adapter, &mut token); 697 adapters.push(id.0); 698 } 699 } 700 } 701 }; 702 703 #[cfg(vulkan)] 704 map((&instance.vulkan, Backend::Vulkan, "Vulkan", backend::Vulkan::hub)), 705 #[cfg(metal)] 706 map((&instance.metal, Backend::Metal, "Metal", backend::Metal::hub)), 707 #[cfg(dx12)] 708 map((&instance.dx12, Backend::Dx12, "Dx12", backend::Dx12::hub)), 709 #[cfg(dx11)] 710 map((&instance.dx11, Backend::Dx11, "Dx11", backend::Dx11::hub)), 711 #[cfg(gl)] 712 map((&instance.gl, Backend::Gl, "GL", backend::Gl::hub)), 713 } 714 715 adapters 716 } 717 request_adapter( &self, desc: &RequestAdapterOptions, inputs: AdapterInputs<Input<G, AdapterId>>, ) -> Result<AdapterId, RequestAdapterError>718 pub fn request_adapter( 719 &self, 720 desc: &RequestAdapterOptions, 721 inputs: AdapterInputs<Input<G, AdapterId>>, 722 ) -> Result<AdapterId, RequestAdapterError> { 723 profiling::scope!("pick_adapter", "Instance"); 724 725 let instance = &self.instance; 726 let mut token = Token::root(); 727 let (surface_guard, mut token) = self.surfaces.read(&mut token); 728 let compatible_surface = desc 729 .compatible_surface 730 .map(|id| { 731 surface_guard 732 .get(id) 733 .map_err(|_| RequestAdapterError::InvalidSurface(id)) 734 }) 735 .transpose()?; 736 let mut device_types = Vec::new(); 737 738 let mut id_vulkan = inputs.find(Backend::Vulkan); 739 let mut id_metal = inputs.find(Backend::Metal); 740 let mut id_dx12 = inputs.find(Backend::Dx12); 741 let mut id_dx11 = inputs.find(Backend::Dx11); 742 let mut id_gl = inputs.find(Backend::Gl); 743 744 backends_map! { 745 let map = |(instance_backend, id_backend, surface_backend)| { 746 match *instance_backend { 747 Some(ref inst) if id_backend.is_some() => { 748 let mut adapters = inst.enumerate_adapters(); 749 if let Some(surface_backend) = compatible_surface.and_then(surface_backend) { 750 adapters.retain(|a| { 751 a.queue_families 752 .iter() 753 .find(|qf| qf.queue_type().supports_graphics()) 754 .map_or(false, |qf| surface_backend.supports_queue_family(qf)) 755 }); 756 } 757 device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone())); 758 adapters 759 } 760 _ => Vec::new(), 761 } 762 }; 763 764 // NB: The internal function definitions are a workaround for Rust 765 // being weird with lifetimes for closure literals... 766 #[cfg(vulkan)] 767 let adapters_vk = map((&instance.vulkan, &id_vulkan, { 768 fn surface_vulkan(surf: &Surface) -> Option<&GfxSurface<backend::Vulkan>> { 769 surf.vulkan.as_ref() 770 } 771 surface_vulkan 772 })); 773 #[cfg(metal)] 774 let adapters_mtl = map((&instance.metal, &id_metal, { 775 fn surface_metal(surf: &Surface) -> Option<&GfxSurface<backend::Metal>> { 776 surf.metal.as_ref() 777 } 778 surface_metal 779 })); 780 #[cfg(dx12)] 781 let adapters_dx12 = map((&instance.dx12, &id_dx12, { 782 fn surface_dx12(surf: &Surface) -> Option<&GfxSurface<backend::Dx12>> { 783 surf.dx12.as_ref() 784 } 785 surface_dx12 786 })); 787 #[cfg(dx11)] 788 let adapters_dx11 = map((&instance.dx11, &id_dx11, { 789 fn surface_dx11(surf: &Surface) -> Option<&GfxSurface<backend::Dx11>> { 790 surf.dx11.as_ref() 791 } 792 surface_dx11 793 })); 794 #[cfg(gl)] 795 let adapters_gl = map((&instance.gl, &id_gl, { 796 fn surface_gl(surf: &Surface) -> Option<&GfxSurface<backend::Gl>> { 797 surf.gl.as_ref() 798 } 799 surface_gl 800 })); 801 } 802 803 if device_types.is_empty() { 804 return Err(RequestAdapterError::NotFound); 805 } 806 807 let (mut integrated, mut discrete, mut virt, mut cpu, mut other) = 808 (None, None, None, None, None); 809 810 for (i, ty) in device_types.into_iter().enumerate() { 811 match ty { 812 hal::adapter::DeviceType::IntegratedGpu => { 813 integrated = integrated.or(Some(i)); 814 } 815 hal::adapter::DeviceType::DiscreteGpu => { 816 discrete = discrete.or(Some(i)); 817 } 818 hal::adapter::DeviceType::VirtualGpu => { 819 virt = virt.or(Some(i)); 820 } 821 hal::adapter::DeviceType::Cpu => { 822 cpu = cpu.or(Some(i)); 823 } 824 hal::adapter::DeviceType::Other => { 825 other = other.or(Some(i)); 826 } 827 } 828 } 829 830 let preferred_gpu = match desc.power_preference { 831 PowerPreference::LowPower => integrated.or(other).or(discrete).or(virt).or(cpu), 832 PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt).or(cpu), 833 }; 834 835 let mut selected = preferred_gpu.unwrap_or(0); 836 837 backends_map! { 838 let map = |(info_adapter, id_backend, mut adapters_backend, backend_hub)| { 839 if selected < adapters_backend.len() { 840 let adapter = Adapter::new(adapters_backend.swap_remove(selected)); 841 log::info!("Adapter {} {:?}", info_adapter, adapter.raw.info); 842 let id = backend_hub(self).adapters 843 .prepare(id_backend.take().unwrap()) 844 .assign(adapter, &mut token); 845 return Ok(id.0); 846 } 847 selected -= adapters_backend.len(); 848 }; 849 850 #[cfg(vulkan)] 851 map(("Vulkan", &mut id_vulkan, adapters_vk, backend::Vulkan::hub)), 852 #[cfg(metal)] 853 map(("Metal", &mut id_metal, adapters_mtl, backend::Metal::hub)), 854 #[cfg(dx12)] 855 map(("Dx12", &mut id_dx12, adapters_dx12, backend::Dx12::hub)), 856 #[cfg(dx11)] 857 map(("Dx11", &mut id_dx11, adapters_dx11, backend::Dx11::hub)), 858 #[cfg(gl)] 859 map(("GL", &mut id_gl, adapters_gl, backend::Gl::hub)), 860 } 861 862 let _ = ( 863 selected, 864 id_vulkan.take(), 865 id_metal.take(), 866 id_dx12.take(), 867 id_dx11.take(), 868 id_gl.take(), 869 ); 870 log::warn!("Some adapters are present, but enumerating them failed!"); 871 Err(RequestAdapterError::NotFound) 872 } 873 adapter_get_info<B: GfxBackend>( &self, adapter_id: AdapterId, ) -> Result<wgt::AdapterInfo, InvalidAdapter>874 pub fn adapter_get_info<B: GfxBackend>( 875 &self, 876 adapter_id: AdapterId, 877 ) -> Result<wgt::AdapterInfo, InvalidAdapter> { 878 let hub = B::hub(self); 879 let mut token = Token::root(); 880 let (adapter_guard, _) = hub.adapters.read(&mut token); 881 adapter_guard 882 .get(adapter_id) 883 .map(|adapter| conv::map_adapter_info(adapter.raw.info.clone(), adapter_id.backend())) 884 .map_err(|_| InvalidAdapter) 885 } 886 adapter_get_texture_format_features<B: GfxBackend>( &self, adapter_id: AdapterId, format: wgt::TextureFormat, ) -> Result<wgt::TextureFormatFeatures, InvalidAdapter>887 pub fn adapter_get_texture_format_features<B: GfxBackend>( 888 &self, 889 adapter_id: AdapterId, 890 format: wgt::TextureFormat, 891 ) -> Result<wgt::TextureFormatFeatures, InvalidAdapter> { 892 let hub = B::hub(self); 893 let mut token = Token::root(); 894 let (adapter_guard, _) = hub.adapters.read(&mut token); 895 adapter_guard 896 .get(adapter_id) 897 .map(|adapter| adapter.get_texture_format_features(format)) 898 .map_err(|_| InvalidAdapter) 899 } 900 adapter_features<B: GfxBackend>( &self, adapter_id: AdapterId, ) -> Result<wgt::Features, InvalidAdapter>901 pub fn adapter_features<B: GfxBackend>( 902 &self, 903 adapter_id: AdapterId, 904 ) -> Result<wgt::Features, InvalidAdapter> { 905 let hub = B::hub(self); 906 let mut token = Token::root(); 907 let (adapter_guard, _) = hub.adapters.read(&mut token); 908 adapter_guard 909 .get(adapter_id) 910 .map(|adapter| adapter.features) 911 .map_err(|_| InvalidAdapter) 912 } 913 adapter_limits<B: GfxBackend>( &self, adapter_id: AdapterId, ) -> Result<wgt::Limits, InvalidAdapter>914 pub fn adapter_limits<B: GfxBackend>( 915 &self, 916 adapter_id: AdapterId, 917 ) -> Result<wgt::Limits, InvalidAdapter> { 918 let hub = B::hub(self); 919 let mut token = Token::root(); 920 let (adapter_guard, _) = hub.adapters.read(&mut token); 921 adapter_guard 922 .get(adapter_id) 923 .map(|adapter| adapter.limits.clone()) 924 .map_err(|_| InvalidAdapter) 925 } 926 adapter_downlevel_properties<B: GfxBackend>( &self, adapter_id: AdapterId, ) -> Result<wgt::DownlevelProperties, InvalidAdapter>927 pub fn adapter_downlevel_properties<B: GfxBackend>( 928 &self, 929 adapter_id: AdapterId, 930 ) -> Result<wgt::DownlevelProperties, InvalidAdapter> { 931 let hub = B::hub(self); 932 let mut token = Token::root(); 933 let (adapter_guard, _) = hub.adapters.read(&mut token); 934 adapter_guard 935 .get(adapter_id) 936 .map(|adapter| adapter.downlevel) 937 .map_err(|_| InvalidAdapter) 938 } 939 adapter_drop<B: GfxBackend>(&self, adapter_id: AdapterId)940 pub fn adapter_drop<B: GfxBackend>(&self, adapter_id: AdapterId) { 941 profiling::scope!("drop", "Adapter"); 942 943 let hub = B::hub(self); 944 let mut token = Token::root(); 945 let (mut adapter_guard, _) = hub.adapters.write(&mut token); 946 947 let free = match adapter_guard.get_mut(adapter_id) { 948 Ok(adapter) => adapter.life_guard.ref_count.take().unwrap().load() == 1, 949 Err(_) => true, 950 }; 951 if free { 952 hub.adapters 953 .unregister_locked(adapter_id, &mut *adapter_guard); 954 } 955 } 956 } 957 958 impl<G: GlobalIdentityHandlerFactory> Global<G> { adapter_request_device<B: GfxBackend>( &self, adapter_id: AdapterId, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, id_in: Input<G, DeviceId>, ) -> (DeviceId, Option<RequestDeviceError>)959 pub fn adapter_request_device<B: GfxBackend>( 960 &self, 961 adapter_id: AdapterId, 962 desc: &DeviceDescriptor, 963 trace_path: Option<&std::path::Path>, 964 id_in: Input<G, DeviceId>, 965 ) -> (DeviceId, Option<RequestDeviceError>) { 966 profiling::scope!("request_device", "Adapter"); 967 968 let hub = B::hub(self); 969 let mut token = Token::root(); 970 let fid = hub.devices.prepare(id_in); 971 972 let error = loop { 973 let (adapter_guard, mut token) = hub.adapters.read(&mut token); 974 let adapter = match adapter_guard.get(adapter_id) { 975 Ok(adapter) => adapter, 976 Err(_) => break RequestDeviceError::InvalidAdapter, 977 }; 978 let device = match adapter.create_device(adapter_id, desc, trace_path) { 979 Ok(device) => device, 980 Err(e) => break e, 981 }; 982 let id = fid.assign(device, &mut token); 983 return (id.0, None); 984 }; 985 986 let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); 987 (id, Some(error)) 988 } 989 } 990