1use alloc::{borrow::ToOwned as _, boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
2use core::{ffi::CStr, marker::PhantomData};
3
4use ash::{ext, google, khr, vk};
5use wgpu_sync::Mutex;
6
7use crate::{vulkan::semaphore_list::SemaphoreList, AllocationSizes};
8
9use super::semaphore_list::SemaphoreListMode;
10
11fn depth_stencil_required_flags() -> vk::FormatFeatureFlags {
12 vk::FormatFeatureFlags::SAMPLED_IMAGE | vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT
13}
14
15const INDEXING_FEATURES: wgt::Features = wgt::Features::TEXTURE_BINDING_ARRAY
16 .union(wgt::Features::BUFFER_BINDING_ARRAY)
17 .union(wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY)
18 .union(wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING)
19 .union(wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING)
20 .union(wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS)
21 .union(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
22#[expect(rustdoc::private_intra_doc_links)]
23#[derive(Debug, Default)]
41pub struct PhysicalDeviceFeatures {
42 core: vk::PhysicalDeviceFeatures,
44
45 pub(super) descriptor_indexing:
47 Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT<'static>>,
48
49 timeline_semaphore: Option<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR<'static>>,
51
52 image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT<'static>>,
54
55 robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT<'static>>,
57
58 multiview: Option<vk::PhysicalDeviceMultiviewFeaturesKHR<'static>>,
60
61 sampler_ycbcr_conversion: Option<vk::PhysicalDeviceSamplerYcbcrConversionFeatures<'static>>,
63
64 astc_hdr: Option<vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT<'static>>,
66
67 shader_float16_int8: Option<vk::PhysicalDeviceShaderFloat16Int8Features<'static>>,
69
70 _16bit_storage: Option<vk::PhysicalDevice16BitStorageFeatures<'static>>,
72
73 acceleration_structure: Option<vk::PhysicalDeviceAccelerationStructureFeaturesKHR<'static>>,
75
76 buffer_device_address: Option<vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR<'static>>,
91
92 ray_query: Option<vk::PhysicalDeviceRayQueryFeaturesKHR<'static>>,
102
103 ray_tracing_pipeline: Option<vk::PhysicalDeviceRayTracingPipelineFeaturesKHR<'static>>,
105
106 zero_initialize_workgroup_memory:
109 Option<vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures<'static>>,
110 position_fetch: Option<vk::PhysicalDeviceRayTracingPositionFetchFeaturesKHR<'static>>,
111
112 shader_atomic_int64: Option<vk::PhysicalDeviceShaderAtomicInt64Features<'static>>,
114
115 shader_image_atomic_int64: Option<vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT<'static>>,
117
118 shader_atomic_float: Option<vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT<'static>>,
120
121 subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlFeatures<'static>>,
123
124 maintenance4: Option<vk::PhysicalDeviceMaintenance4FeaturesKHR<'static>>,
126
127 mesh_shader: Option<vk::PhysicalDeviceMeshShaderFeaturesEXT<'static>>,
129
130 shader_integer_dot_product:
132 Option<vk::PhysicalDeviceShaderIntegerDotProductFeaturesKHR<'static>>,
133
134 shader_barycentrics: Option<vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR<'static>>,
136
137 portability_subset: Option<vk::PhysicalDevicePortabilitySubsetFeaturesKHR<'static>>,
141
142 cooperative_matrix: Option<vk::PhysicalDeviceCooperativeMatrixFeaturesKHR<'static>>,
144
145 vulkan_memory_model: Option<vk::PhysicalDeviceVulkanMemoryModelFeaturesKHR<'static>>,
147
148 shader_draw_parameters: Option<vk::PhysicalDeviceShaderDrawParametersFeatures<'static>>,
149}
150
151impl PhysicalDeviceFeatures {
152 pub fn get_core(&self) -> vk::PhysicalDeviceFeatures {
153 self.core
154 }
155
156 pub fn add_to_device_create<'a>(
158 &'a mut self,
159 mut info: vk::DeviceCreateInfo<'a>,
160 ) -> vk::DeviceCreateInfo<'a> {
161 info = info.enabled_features(&self.core);
162 if let Some(ref mut feature) = self.descriptor_indexing {
163 info = info.push_next(feature);
164 }
165 if let Some(ref mut feature) = self.timeline_semaphore {
166 info = info.push_next(feature);
167 }
168 if let Some(ref mut feature) = self.image_robustness {
169 info = info.push_next(feature);
170 }
171 if let Some(ref mut feature) = self.robustness2 {
172 info = info.push_next(feature);
173 }
174 if let Some(ref mut feature) = self.multiview {
175 info = info.push_next(feature);
176 }
177 if let Some(ref mut feature) = self.astc_hdr {
178 info = info.push_next(feature);
179 }
180 if let Some(ref mut feature) = self.shader_float16_int8 {
181 info = info.push_next(feature);
182 }
183 if let Some(ref mut feature) = self._16bit_storage {
184 info = info.push_next(feature);
185 }
186 if let Some(ref mut feature) = self.zero_initialize_workgroup_memory {
187 info = info.push_next(feature);
188 }
189 if let Some(ref mut feature) = self.acceleration_structure {
190 info = info.push_next(feature);
191 }
192 if let Some(ref mut feature) = self.buffer_device_address {
193 info = info.push_next(feature);
194 }
195 if let Some(ref mut feature) = self.ray_query {
196 info = info.push_next(feature);
197 }
198 if let Some(ref mut feature) = self.ray_tracing_pipeline {
199 info = info.push_next(feature);
200 }
201 if let Some(ref mut feature) = self.shader_atomic_int64 {
202 info = info.push_next(feature);
203 }
204 if let Some(ref mut feature) = self.position_fetch {
205 info = info.push_next(feature);
206 }
207 if let Some(ref mut feature) = self.shader_image_atomic_int64 {
208 info = info.push_next(feature);
209 }
210 if let Some(ref mut feature) = self.shader_atomic_float {
211 info = info.push_next(feature);
212 }
213 if let Some(ref mut feature) = self.subgroup_size_control {
214 info = info.push_next(feature);
215 }
216 if let Some(ref mut feature) = self.maintenance4 {
217 info = info.push_next(feature);
218 }
219 if let Some(ref mut feature) = self.mesh_shader {
220 info = info.push_next(feature);
221 }
222 if let Some(ref mut feature) = self.shader_integer_dot_product {
223 info = info.push_next(feature);
224 }
225 if let Some(ref mut feature) = self.shader_barycentrics {
226 info = info.push_next(feature);
227 }
228 if let Some(ref mut feature) = self.portability_subset {
229 info = info.push_next(feature);
230 }
231 if let Some(ref mut feature) = self.cooperative_matrix {
232 info = info.push_next(feature);
233 }
234 if let Some(ref mut feature) = self.vulkan_memory_model {
235 info = info.push_next(feature);
236 }
237 if let Some(ref mut feature) = self.shader_draw_parameters {
238 info = info.push_next(feature);
239 }
240 info
241 }
242
243 fn supports_storage_input_output_16(&self) -> bool {
244 self._16bit_storage
245 .as_ref()
246 .map(|features| features.storage_input_output16 != 0)
247 .unwrap_or(false)
248 }
249
250 fn from_extensions_and_requested_features(
277 phd_capabilities: &PhysicalDeviceProperties,
278 phd_features: &PhysicalDeviceFeatures,
279 enabled_extensions: &[&'static CStr],
280 requested_features: wgt::Features,
281 downlevel_flags: wgt::DownlevelFlags,
282 private_caps: &super::PrivateCapabilities,
283 ) -> Self {
284 let device_api_version = phd_capabilities.device_api_version;
285 let needs_bindless = requested_features.intersects(
286 wgt::Features::TEXTURE_BINDING_ARRAY
287 | wgt::Features::BUFFER_BINDING_ARRAY
288 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
289 | wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
290 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
291 );
292 let needs_partially_bound =
293 requested_features.intersects(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
294
295 Self {
296 core: vk::PhysicalDeviceFeatures::default()
299 .robust_buffer_access(private_caps.robust_buffer_access)
300 .independent_blend(downlevel_flags.contains(wgt::DownlevelFlags::INDEPENDENT_BLEND))
301 .sample_rate_shading(
302 downlevel_flags.contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING),
303 )
304 .image_cube_array(
305 downlevel_flags.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES),
306 )
307 .draw_indirect_first_instance(
308 requested_features.contains(wgt::Features::INDIRECT_FIRST_INSTANCE),
309 )
310 .multi_draw_indirect(phd_features.core.multi_draw_indirect != 0)
312 .fill_mode_non_solid(requested_features.intersects(
313 wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT,
314 ))
315 .sampler_anisotropy(
319 downlevel_flags.contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING),
320 )
321 .texture_compression_etc2(
322 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ETC2),
323 )
324 .texture_compression_astc_ldr(
325 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC),
326 )
327 .texture_compression_bc(
328 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_BC),
329 )
331 .pipeline_statistics_query(
333 requested_features.contains(wgt::Features::PIPELINE_STATISTICS_QUERY),
334 )
335 .vertex_pipeline_stores_and_atomics(
336 requested_features.contains(wgt::Features::VERTEX_WRITABLE_STORAGE),
337 )
338 .fragment_stores_and_atomics(
339 downlevel_flags.contains(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE),
340 )
341 .shader_uniform_buffer_array_dynamic_indexing(
344 requested_features.contains(wgt::Features::BUFFER_BINDING_ARRAY),
345 )
346 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
347 wgt::Features::BUFFER_BINDING_ARRAY
348 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
349 ))
350 .shader_sampled_image_array_dynamic_indexing(
351 requested_features.contains(wgt::Features::TEXTURE_BINDING_ARRAY),
352 )
353 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
354 wgt::Features::TEXTURE_BINDING_ARRAY
355 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
356 ))
357 .shader_clip_distance(requested_features.contains(wgt::Features::CLIP_DISTANCES))
359 .shader_float64(requested_features.contains(wgt::Features::SHADER_F64))
361 .shader_int64(requested_features.contains(wgt::Features::SHADER_INT64))
362 .shader_int16(requested_features.contains(wgt::Features::SHADER_I16))
363 .geometry_shader(requested_features.contains(wgt::Features::PRIMITIVE_INDEX))
365 .depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL))
366 .dual_src_blend(requested_features.contains(wgt::Features::DUAL_SOURCE_BLENDING)),
367 descriptor_indexing: if requested_features.intersects(INDEXING_FEATURES) {
368 Some(
369 vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default()
370 .shader_sampled_image_array_non_uniform_indexing(needs_bindless)
371 .shader_storage_image_array_non_uniform_indexing(needs_bindless)
372 .shader_storage_buffer_array_non_uniform_indexing(needs_bindless)
373 .descriptor_binding_sampled_image_update_after_bind(needs_bindless)
374 .descriptor_binding_storage_image_update_after_bind(needs_bindless)
375 .descriptor_binding_storage_buffer_update_after_bind(needs_bindless)
376 .descriptor_binding_partially_bound(needs_partially_bound),
377 )
378 } else {
379 None
380 },
381 timeline_semaphore: if device_api_version >= vk::API_VERSION_1_2
382 || enabled_extensions.contains(&khr::timeline_semaphore::NAME)
383 {
384 Some(
385 vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default()
386 .timeline_semaphore(private_caps.timeline_semaphores),
387 )
388 } else {
389 None
390 },
391 image_robustness: if device_api_version >= vk::API_VERSION_1_3
392 || enabled_extensions.contains(&ext::image_robustness::NAME)
393 {
394 Some(
395 vk::PhysicalDeviceImageRobustnessFeaturesEXT::default()
396 .robust_image_access(private_caps.robust_image_access),
397 )
398 } else {
399 None
400 },
401 robustness2: if enabled_extensions.contains(&ext::robustness2::NAME) {
402 Some(
403 vk::PhysicalDeviceRobustness2FeaturesEXT::default()
404 .robust_buffer_access2(private_caps.robust_buffer_access2)
405 .robust_image_access2(private_caps.robust_image_access2),
406 )
407 } else {
408 None
409 },
410 multiview: if device_api_version >= vk::API_VERSION_1_1
411 || enabled_extensions.contains(&khr::multiview::NAME)
412 {
413 Some(
414 vk::PhysicalDeviceMultiviewFeatures::default()
415 .multiview(requested_features.contains(wgt::Features::MULTIVIEW)),
416 )
417 } else {
418 None
419 },
420 sampler_ycbcr_conversion: if device_api_version >= vk::API_VERSION_1_1
421 || enabled_extensions.contains(&khr::sampler_ycbcr_conversion::NAME)
422 {
423 Some(
424 vk::PhysicalDeviceSamplerYcbcrConversionFeatures::default(), )
426 } else {
427 None
428 },
429 astc_hdr: if enabled_extensions.contains(&ext::texture_compression_astc_hdr::NAME) {
430 Some(
431 vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::default()
432 .texture_compression_astc_hdr(true),
433 )
434 } else {
435 None
436 },
437 shader_float16_int8: match requested_features.contains(wgt::Features::SHADER_F16) {
438 shader_float16 if shader_float16 || private_caps.shader_int8 => Some(
439 vk::PhysicalDeviceShaderFloat16Int8Features::default()
440 .shader_float16(shader_float16)
441 .shader_int8(private_caps.shader_int8),
442 ),
443 _ => None,
444 },
445 _16bit_storage: if requested_features
446 .intersects(wgt::Features::SHADER_F16 | wgt::Features::SHADER_I16)
447 {
448 Some(
449 vk::PhysicalDevice16BitStorageFeatures::default()
450 .storage_buffer16_bit_access(true)
451 .storage_input_output16(phd_features.supports_storage_input_output_16())
452 .uniform_and_storage_buffer16_bit_access(true),
453 )
454 } else {
455 None
456 },
457 acceleration_structure: if enabled_extensions
458 .contains(&khr::acceleration_structure::NAME)
459 {
460 Some(
461 vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default()
462 .acceleration_structure(true)
463 .descriptor_binding_acceleration_structure_update_after_bind(
464 requested_features
465 .contains(wgt::Features::ACCELERATION_STRUCTURE_BINDING_ARRAY),
466 ),
467 )
468 } else {
469 None
470 },
471 buffer_device_address: if enabled_extensions.contains(&khr::buffer_device_address::NAME)
472 {
473 Some(
474 vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR::default()
475 .buffer_device_address(true),
476 )
477 } else {
478 None
479 },
480 ray_query: if enabled_extensions.contains(&khr::ray_query::NAME) {
481 Some(vk::PhysicalDeviceRayQueryFeaturesKHR::default().ray_query(true))
482 } else {
483 None
484 },
485 ray_tracing_pipeline: if enabled_extensions.contains(&khr::ray_tracing_pipeline::NAME) {
486 Some(
487 vk::PhysicalDeviceRayTracingPipelineFeaturesKHR::default()
488 .ray_tracing_pipeline(true),
489 )
490 } else {
491 None
492 },
493 zero_initialize_workgroup_memory: if device_api_version >= vk::API_VERSION_1_3
494 || enabled_extensions.contains(&khr::zero_initialize_workgroup_memory::NAME)
495 {
496 Some(
497 vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::default()
498 .shader_zero_initialize_workgroup_memory(
499 private_caps.zero_initialize_workgroup_memory,
500 ),
501 )
502 } else {
503 None
504 },
505 shader_atomic_int64: if device_api_version >= vk::API_VERSION_1_2
506 || enabled_extensions.contains(&khr::shader_atomic_int64::NAME)
507 {
508 let needed = requested_features.intersects(
509 wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS
510 | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX,
511 );
512 Some(
513 vk::PhysicalDeviceShaderAtomicInt64Features::default()
514 .shader_buffer_int64_atomics(needed)
515 .shader_shared_int64_atomics(needed),
516 )
517 } else {
518 None
519 },
520 shader_image_atomic_int64: if enabled_extensions
521 .contains(&ext::shader_image_atomic_int64::NAME)
522 {
523 let needed = requested_features.intersects(wgt::Features::TEXTURE_INT64_ATOMIC);
524 Some(
525 vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT::default()
526 .shader_image_int64_atomics(needed),
527 )
528 } else {
529 None
530 },
531 shader_atomic_float: if enabled_extensions.contains(&ext::shader_atomic_float::NAME) {
532 let needed = requested_features.contains(wgt::Features::SHADER_FLOAT32_ATOMIC);
533 Some(
534 vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT::default()
535 .shader_buffer_float32_atomics(needed)
536 .shader_buffer_float32_atomic_add(needed),
537 )
538 } else {
539 None
540 },
541 subgroup_size_control: if device_api_version >= vk::API_VERSION_1_3
542 || enabled_extensions.contains(&ext::subgroup_size_control::NAME)
543 {
544 Some(
545 vk::PhysicalDeviceSubgroupSizeControlFeatures::default()
546 .subgroup_size_control(true),
547 )
548 } else {
549 None
550 },
551 position_fetch: if enabled_extensions.contains(&khr::ray_tracing_position_fetch::NAME) {
552 Some(
553 vk::PhysicalDeviceRayTracingPositionFetchFeaturesKHR::default()
554 .ray_tracing_position_fetch(true),
555 )
556 } else {
557 None
558 },
559 mesh_shader: if enabled_extensions.contains(&ext::mesh_shader::NAME) {
560 let needed = requested_features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER);
561 let multiview_needed =
562 requested_features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW);
563 Some(
564 vk::PhysicalDeviceMeshShaderFeaturesEXT::default()
565 .mesh_shader(needed)
566 .task_shader(needed)
567 .multiview_mesh_shader(multiview_needed),
568 )
569 } else {
570 None
571 },
572 maintenance4: if device_api_version >= vk::API_VERSION_1_3
573 || enabled_extensions.contains(&khr::maintenance4::NAME)
574 {
575 let needed = requested_features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER);
576 Some(vk::PhysicalDeviceMaintenance4Features::default().maintenance4(needed))
577 } else {
578 None
579 },
580 shader_integer_dot_product: if device_api_version >= vk::API_VERSION_1_3
581 || enabled_extensions.contains(&khr::shader_integer_dot_product::NAME)
582 {
583 Some(
584 vk::PhysicalDeviceShaderIntegerDotProductFeaturesKHR::default()
585 .shader_integer_dot_product(private_caps.shader_integer_dot_product),
586 )
587 } else {
588 None
589 },
590 shader_barycentrics: if enabled_extensions
591 .contains(&khr::fragment_shader_barycentric::NAME)
592 {
593 let needed = requested_features.intersects(
594 wgt::Features::SHADER_BARYCENTRICS | wgt::Features::SHADER_PER_VERTEX,
595 );
596 Some(
597 vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR::default()
598 .fragment_shader_barycentric(needed),
599 )
600 } else {
601 None
602 },
603 portability_subset: if enabled_extensions.contains(&khr::portability_subset::NAME) {
604 let image_view_format_swizzle_needed =
605 requested_features.intersects(wgt::Features::TEXTURE_COMPONENT_SWIZZLE);
606 let multisample_array_needed =
607 requested_features.intersects(wgt::Features::MULTISAMPLE_ARRAY);
608
609 Some(
610 vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default()
611 .image_view_format_swizzle(image_view_format_swizzle_needed)
612 .multisample_array_image(multisample_array_needed),
613 )
614 } else {
615 None
616 },
617 cooperative_matrix: if enabled_extensions.contains(&khr::cooperative_matrix::NAME) {
618 let needed =
619 requested_features.contains(wgt::Features::EXPERIMENTAL_COOPERATIVE_MATRIX);
620 Some(
621 vk::PhysicalDeviceCooperativeMatrixFeaturesKHR::default()
622 .cooperative_matrix(needed),
623 )
624 } else {
625 None
626 },
627 vulkan_memory_model: if device_api_version >= vk::API_VERSION_1_2
628 || enabled_extensions.contains(&khr::vulkan_memory_model::NAME)
629 {
630 let needed =
631 requested_features.contains(wgt::Features::EXPERIMENTAL_COOPERATIVE_MATRIX);
632 Some(
633 vk::PhysicalDeviceVulkanMemoryModelFeaturesKHR::default()
634 .vulkan_memory_model(needed)
635 .vulkan_memory_model_device_scope(needed),
641 )
642 } else {
643 None
644 },
645 shader_draw_parameters: if device_api_version >= vk::API_VERSION_1_1 {
646 let needed = requested_features.contains(wgt::Features::SHADER_DRAW_INDEX);
647 Some(
648 vk::PhysicalDeviceShaderDrawParametersFeatures::default()
649 .shader_draw_parameters(needed),
650 )
651 } else {
652 None
653 },
654 }
655 }
656
657 fn to_wgpu(
666 &self,
667 instance: &ash::Instance,
668 phd: vk::PhysicalDevice,
669 caps: &PhysicalDeviceProperties,
670 queue_props: &vk::QueueFamilyProperties,
671 ) -> (wgt::Features, wgt::DownlevelFlags) {
672 use wgt::{DownlevelFlags as Df, Features as F};
673 let mut features = F::empty()
674 | F::MAPPABLE_PRIMARY_BUFFERS
675 | F::IMMEDIATES
676 | F::ADDRESS_MODE_CLAMP_TO_BORDER
677 | F::ADDRESS_MODE_CLAMP_TO_ZERO
678 | F::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
679 | F::CLEAR_TEXTURE
680 | F::PIPELINE_CACHE
681 | F::SHADER_EARLY_DEPTH_TEST
682 | F::TEXTURE_ATOMIC
683 | F::PASSTHROUGH_SHADERS
684 | F::MEMORY_DECORATION_COHERENT
685 | F::MEMORY_DECORATION_VOLATILE;
686
687 let mut dl_flags = Df::COMPUTE_SHADERS
688 | Df::BASE_VERTEX
689 | Df::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
690 | Df::COMPARISON_SAMPLERS
691 | Df::VERTEX_STORAGE
692 | Df::FRAGMENT_STORAGE
693 | Df::DEPTH_TEXTURE_AND_BUFFER_COPIES
694 | Df::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED
695 | Df::UNRESTRICTED_INDEX_BUFFER
696 | Df::INDIRECT_EXECUTION
697 | Df::VIEW_FORMATS
698 | Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES
699 | Df::NONBLOCKING_QUERY_RESOLVE
700 | Df::SHADER_F16_IN_F32
701 | Df::MSL2_1
702 | Df::LINEAR_INTERPOLATION;
703
704 dl_flags.set(
708 Df::READ_ONLY_DEPTH_STENCIL,
709 caps.device_api_version >= vk::API_VERSION_1_1
710 || caps.supports_extension(khr::maintenance2::NAME),
711 );
712
713 dl_flags.set(
714 Df::SURFACE_VIEW_FORMATS,
715 caps.supports_extension(khr::swapchain_mutable_format::NAME)
716 || !caps.supports_extension(khr::swapchain::NAME),
717 );
718 dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0);
719 dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0);
720 dl_flags.set(
721 Df::FRAGMENT_WRITABLE_STORAGE,
722 self.core.fragment_stores_and_atomics != 0,
723 );
724 dl_flags.set(Df::MULTISAMPLED_SHADING, self.core.sample_rate_shading != 0);
725 dl_flags.set(Df::INDEPENDENT_BLEND, self.core.independent_blend != 0);
726 dl_flags.set(
727 Df::FULL_DRAW_INDEX_UINT32,
728 self.core.full_draw_index_uint32 != 0,
729 );
730 dl_flags.set(Df::DEPTH_BIAS_CLAMP, self.core.depth_bias_clamp != 0);
731
732 features.set(
733 F::TIMESTAMP_QUERY
734 | F::TIMESTAMP_QUERY_INSIDE_ENCODERS
735 | F::TIMESTAMP_QUERY_INSIDE_PASSES,
736 queue_props.timestamp_valid_bits >= 36,
738 );
739 features.set(
740 F::INDIRECT_FIRST_INSTANCE,
741 self.core.draw_indirect_first_instance != 0,
742 );
743 features.set(F::POLYGON_MODE_LINE, self.core.fill_mode_non_solid != 0);
745 features.set(F::POLYGON_MODE_POINT, self.core.fill_mode_non_solid != 0);
746 features.set(
750 F::TEXTURE_COMPRESSION_ETC2,
751 self.core.texture_compression_etc2 != 0,
752 );
753 features.set(
754 F::TEXTURE_COMPRESSION_ASTC,
755 self.core.texture_compression_astc_ldr != 0,
756 );
757 features.set(
758 F::TEXTURE_COMPRESSION_BC,
759 self.core.texture_compression_bc != 0,
760 );
761 features.set(
762 F::TEXTURE_COMPRESSION_BC_SLICED_3D,
763 self.core.texture_compression_bc != 0, );
765 features.set(
766 F::PIPELINE_STATISTICS_QUERY,
767 self.core.pipeline_statistics_query != 0,
768 );
769 features.set(
770 F::VERTEX_WRITABLE_STORAGE,
771 self.core.vertex_pipeline_stores_and_atomics != 0,
772 );
773
774 features.set(F::SHADER_F64, self.core.shader_float64 != 0);
775 features.set(F::SHADER_INT64, self.core.shader_int64 != 0);
776 if let Some(ref bit16) = self._16bit_storage {
777 features.set(
778 F::SHADER_I16,
779 self.core.shader_int16 != 0
780 && bit16.storage_buffer16_bit_access != 0
781 && bit16.uniform_and_storage_buffer16_bit_access != 0,
782 );
783 }
784
785 features.set(F::PRIMITIVE_INDEX, self.core.geometry_shader != 0);
786
787 if let Some(ref shader_atomic_int64) = self.shader_atomic_int64 {
788 features.set(
789 F::SHADER_INT64_ATOMIC_ALL_OPS | F::SHADER_INT64_ATOMIC_MIN_MAX,
790 shader_atomic_int64.shader_buffer_int64_atomics != 0
791 && shader_atomic_int64.shader_shared_int64_atomics != 0,
792 );
793 }
794
795 if let Some(ref shader_image_atomic_int64) = self.shader_image_atomic_int64 {
796 features.set(
797 F::TEXTURE_INT64_ATOMIC,
798 shader_image_atomic_int64
799 .shader_image_int64_atomics(true)
800 .shader_image_int64_atomics
801 != 0,
802 );
803 }
804
805 if let Some(ref shader_atomic_float) = self.shader_atomic_float {
806 features.set(
807 F::SHADER_FLOAT32_ATOMIC,
808 shader_atomic_float.shader_buffer_float32_atomics != 0
809 && shader_atomic_float.shader_buffer_float32_atomic_add != 0,
810 );
811 }
812
813 if let Some(ref shader_barycentrics) = self.shader_barycentrics {
814 features.set(
815 F::SHADER_BARYCENTRICS | F::SHADER_PER_VERTEX,
816 shader_barycentrics.fragment_shader_barycentric != 0,
817 );
818 }
819
820 features.set(
823 F::MULTI_DRAW_INDIRECT_COUNT,
824 caps.supports_extension(khr::draw_indirect_count::NAME),
825 );
826 features.set(
827 F::CONSERVATIVE_RASTERIZATION,
828 caps.supports_extension(ext::conservative_rasterization::NAME),
829 );
830 features.set(
831 F::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN,
832 caps.supports_extension(khr::ray_tracing_position_fetch::NAME),
833 );
834
835 if let Some(ref descriptor_indexing) = self.descriptor_indexing {
836 let supports_descriptor_indexing =
845 descriptor_indexing.shader_sampled_image_array_non_uniform_indexing != 0
847 && descriptor_indexing.descriptor_binding_sampled_image_update_after_bind != 0
848 && descriptor_indexing.shader_storage_image_array_non_uniform_indexing != 0
850 && descriptor_indexing.descriptor_binding_storage_image_update_after_bind != 0
851 && descriptor_indexing.shader_storage_buffer_array_non_uniform_indexing != 0
853 && descriptor_indexing.descriptor_binding_storage_buffer_update_after_bind != 0;
854
855 let descriptor_indexing_features = F::BUFFER_BINDING_ARRAY
856 | F::TEXTURE_BINDING_ARRAY
857 | F::STORAGE_RESOURCE_BINDING_ARRAY
858 | F::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
859 | F::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING;
860
861 features.set(descriptor_indexing_features, supports_descriptor_indexing);
862
863 let supports_partially_bound =
864 descriptor_indexing.descriptor_binding_partially_bound != 0;
865
866 features.set(F::PARTIALLY_BOUND_BINDING_ARRAY, supports_partially_bound);
867 }
868
869 features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0);
870 features.set(F::DUAL_SOURCE_BLENDING, self.core.dual_src_blend != 0);
871 features.set(F::CLIP_DISTANCES, self.core.shader_clip_distance != 0);
872
873 if let Some(ref multiview) = self.multiview {
874 features.set(F::MULTIVIEW, multiview.multiview != 0);
875 features.set(F::SELECTIVE_MULTIVIEW, multiview.multiview != 0);
876 }
877
878 features.set(
879 F::TEXTURE_FORMAT_16BIT_NORM,
880 is_format_16bit_norm_supported(instance, phd),
881 );
882
883 if let Some(ref astc_hdr) = self.astc_hdr {
884 features.set(
885 F::TEXTURE_COMPRESSION_ASTC_HDR,
886 astc_hdr.texture_compression_astc_hdr != 0,
887 );
888 }
889
890 if self.core.texture_compression_astc_ldr != 0 {
891 features.set(
892 F::TEXTURE_COMPRESSION_ASTC_SLICED_3D,
893 supports_astc_3d(instance, phd),
894 );
895 }
896
897 if let (Some(ref f16_i8), Some(ref bit16)) = (self.shader_float16_int8, self._16bit_storage)
898 {
899 features.set(
902 F::SHADER_F16,
903 f16_i8.shader_float16 != 0
904 && bit16.storage_buffer16_bit_access != 0
905 && bit16.uniform_and_storage_buffer16_bit_access != 0,
906 );
907 }
908
909 if let Some(ref subgroup) = caps.subgroup {
910 if (caps.device_api_version >= vk::API_VERSION_1_3
911 || caps.supports_extension(ext::subgroup_size_control::NAME))
912 && subgroup.supported_operations.contains(
913 vk::SubgroupFeatureFlags::BASIC
914 | vk::SubgroupFeatureFlags::VOTE
915 | vk::SubgroupFeatureFlags::ARITHMETIC
916 | vk::SubgroupFeatureFlags::BALLOT
917 | vk::SubgroupFeatureFlags::SHUFFLE
918 | vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE
919 | vk::SubgroupFeatureFlags::QUAD,
920 )
921 {
922 features.set(
923 F::SUBGROUP,
924 subgroup
925 .supported_stages
926 .contains(vk::ShaderStageFlags::COMPUTE | vk::ShaderStageFlags::FRAGMENT),
927 );
928 features.set(
929 F::SUBGROUP_VERTEX,
930 subgroup
931 .supported_stages
932 .contains(vk::ShaderStageFlags::VERTEX),
933 );
934 features.insert(F::SUBGROUP_BARRIER);
935 }
936 }
937
938 let supports_depth_format = |format| {
939 supports_format(
940 instance,
941 phd,
942 format,
943 vk::ImageTiling::OPTIMAL,
944 depth_stencil_required_flags(),
945 )
946 };
947
948 let texture_s8 = supports_depth_format(vk::Format::S8_UINT);
949 let texture_d32 = supports_depth_format(vk::Format::D32_SFLOAT);
950 let texture_d24_s8 = supports_depth_format(vk::Format::D24_UNORM_S8_UINT);
951 let texture_d32_s8 = supports_depth_format(vk::Format::D32_SFLOAT_S8_UINT);
952
953 let stencil8 = texture_s8 || texture_d24_s8;
954 let depth24_plus_stencil8 = texture_d24_s8 || texture_d32_s8;
955
956 dl_flags.set(
957 Df::WEBGPU_TEXTURE_FORMAT_SUPPORT,
958 stencil8 && depth24_plus_stencil8 && texture_d32,
959 );
960
961 features.set(F::DEPTH32FLOAT_STENCIL8, texture_d32_s8);
962
963 let supports_acceleration_structures = caps
964 .supports_extension(khr::deferred_host_operations::NAME)
965 && caps.supports_extension(khr::acceleration_structure::NAME)
966 && caps.supports_extension(khr::buffer_device_address::NAME);
967
968 let supports_ray_query =
969 supports_acceleration_structures && caps.supports_extension(khr::ray_query::NAME);
970 let supports_acceleration_structure_binding_array = supports_ray_query
971 && self
972 .acceleration_structure
973 .as_ref()
974 .is_some_and(|features| {
975 features.descriptor_binding_acceleration_structure_update_after_bind != 0
976 });
977
978 features.set(
979 F::EXPERIMENTAL_RAY_QUERY
980 | F::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS,
983 supports_ray_query,
984 );
985
986 features.set(
991 F::ACCELERATION_STRUCTURE_BINDING_ARRAY,
992 supports_acceleration_structure_binding_array,
993 );
994
995 if supports_acceleration_structures
996 && caps.supports_extension(khr::ray_tracing_pipeline::NAME)
997 {
998 features.insert(
999 F::EXPERIMENTAL_RAY_TRACING_PIPELINES
1000 | F::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS,
1002 );
1003 }
1004
1005 let rg11b10ufloat_renderable = supports_format(
1006 instance,
1007 phd,
1008 vk::Format::B10G11R11_UFLOAT_PACK32,
1009 vk::ImageTiling::OPTIMAL,
1010 vk::FormatFeatureFlags::COLOR_ATTACHMENT
1011 | vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND,
1012 );
1013 features.set(F::RG11B10UFLOAT_RENDERABLE, rg11b10ufloat_renderable);
1014
1015 features.set(
1016 F::BGRA8UNORM_STORAGE,
1017 supports_bgra8unorm_storage(instance, phd, caps.device_api_version),
1018 );
1019
1020 features.set(
1021 F::FLOAT32_FILTERABLE,
1022 is_float32_filterable_supported(instance, phd),
1023 );
1024
1025 features.set(
1026 F::FLOAT32_BLENDABLE,
1027 is_float32_blendable_supported(instance, phd),
1028 );
1029
1030 if let Some(ref _sampler_ycbcr_conversion) = self.sampler_ycbcr_conversion {
1031 features.set(
1032 F::TEXTURE_FORMAT_NV12,
1033 supports_format(
1034 instance,
1035 phd,
1036 vk::Format::G8_B8R8_2PLANE_420_UNORM,
1037 vk::ImageTiling::OPTIMAL,
1038 vk::FormatFeatureFlags::SAMPLED_IMAGE
1039 | vk::FormatFeatureFlags::TRANSFER_SRC
1040 | vk::FormatFeatureFlags::TRANSFER_DST,
1041 ) && !caps.is_driver(vk::DriverId::MOLTENVK),
1042 );
1043 }
1044
1045 if let Some(ref _sampler_ycbcr_conversion) = self.sampler_ycbcr_conversion {
1046 features.set(
1047 F::TEXTURE_FORMAT_P010,
1048 supports_format(
1049 instance,
1050 phd,
1051 vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
1052 vk::ImageTiling::OPTIMAL,
1053 vk::FormatFeatureFlags::SAMPLED_IMAGE
1054 | vk::FormatFeatureFlags::TRANSFER_SRC
1055 | vk::FormatFeatureFlags::TRANSFER_DST,
1056 ) && !caps.is_driver(vk::DriverId::MOLTENVK),
1057 );
1058 }
1059
1060 features.set(
1061 F::VULKAN_GOOGLE_DISPLAY_TIMING,
1062 caps.supports_extension(google::display_timing::NAME),
1063 );
1064
1065 features.set(
1066 F::VULKAN_EXTERNAL_MEMORY_WIN32,
1067 caps.supports_extension(khr::external_memory_win32::NAME),
1068 );
1069 features.set(
1070 F::VULKAN_EXTERNAL_MEMORY_FD,
1071 caps.supports_extension(khr::external_memory_fd::NAME),
1072 );
1073 features.set(
1074 F::VULKAN_EXTERNAL_MEMORY_DMA_BUF,
1075 caps.supports_extension(khr::external_memory_fd::NAME)
1076 && caps.supports_extension(ext::external_memory_dma_buf::NAME)
1077 && caps.supports_extension(ext::image_drm_format_modifier::NAME),
1078 );
1079 features.set(
1080 F::EXPERIMENTAL_MESH_SHADER,
1081 caps.supports_extension(ext::mesh_shader::NAME),
1082 );
1083 features.set(
1084 F::EXPERIMENTAL_MESH_SHADER_POINTS,
1085 caps.supports_extension(ext::mesh_shader::NAME),
1086 );
1087 if let Some(ref mesh_shader) = self.mesh_shader {
1088 features.set(
1089 F::EXPERIMENTAL_MESH_SHADER_MULTIVIEW,
1090 mesh_shader.multiview_mesh_shader != 0,
1091 );
1092 }
1093
1094 features.set(
1096 F::TEXTURE_COMPONENT_SWIZZLE,
1097 self.portability_subset
1098 .map(|p| p.image_view_format_swizzle == vk::TRUE)
1099 .unwrap_or(true),
1100 );
1101 features.set(
1102 F::MULTISAMPLE_ARRAY,
1103 self.portability_subset
1104 .map(|p| p.multisample_array_image == vk::TRUE)
1105 .unwrap_or(true),
1106 );
1107
1108 features.set(
1113 F::EXPERIMENTAL_COOPERATIVE_MATRIX,
1114 !caps.cooperative_matrix_properties.is_empty()
1115 && self.vulkan_memory_model.is_some_and(|m| {
1116 m.vulkan_memory_model == vk::TRUE
1117 && m.vulkan_memory_model_device_scope == vk::TRUE
1118 }),
1119 );
1120
1121 features.set(
1122 F::SHADER_DRAW_INDEX,
1123 self.shader_draw_parameters
1124 .is_some_and(|a| a.shader_draw_parameters != 0)
1125 || caps.supports_extension(c"VK_KHR_shader_draw_parameters"),
1126 );
1127
1128 features.set(
1129 F::DEBUG_PRINTF,
1130 caps.device_api_version >= vk::API_VERSION_1_3
1131 || caps.supports_extension(khr::shader_non_semantic_info::NAME),
1132 );
1133
1134 (features, dl_flags)
1135 }
1136}
1137
1138#[derive(Default, Debug)]
1159pub struct PhysicalDeviceProperties {
1160 supported_extensions: Vec<vk::ExtensionProperties>,
1163
1164 properties: vk::PhysicalDeviceProperties,
1167
1168 maintenance_3: Option<vk::PhysicalDeviceMaintenance3Properties<'static>>,
1171
1172 maintenance_4: Option<vk::PhysicalDeviceMaintenance4Properties<'static>>,
1175
1176 maintenance_5: Option<vk::PhysicalDeviceMaintenance5PropertiesKHR<'static>>,
1179
1180 descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingPropertiesEXT<'static>>,
1183
1184 acceleration_structure: Option<vk::PhysicalDeviceAccelerationStructurePropertiesKHR<'static>>,
1187
1188 ray_tracing_pipeline: Option<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR<'static>>,
1191
1192 driver: Option<vk::PhysicalDeviceDriverPropertiesKHR<'static>>,
1195
1196 subgroup: Option<vk::PhysicalDeviceSubgroupProperties<'static>>,
1198
1199 subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlProperties<'static>>,
1202
1203 robustness2: Option<vk::PhysicalDeviceRobustness2PropertiesEXT<'static>>,
1206
1207 mesh_shader: Option<vk::PhysicalDeviceMeshShaderPropertiesEXT<'static>>,
1210
1211 multiview: Option<vk::PhysicalDeviceMultiviewPropertiesKHR<'static>>,
1214
1215 pci_bus_info: Option<vk::PhysicalDevicePCIBusInfoPropertiesEXT<'static>>,
1217
1218 device_api_version: u32,
1224
1225 cooperative_matrix_properties: Vec<wgt::CooperativeMatrixProperties>,
1229}
1230
1231impl PhysicalDeviceProperties {
1232 pub fn properties(&self) -> vk::PhysicalDeviceProperties {
1233 self.properties
1234 }
1235
1236 pub fn supports_extension(&self, extension: &CStr) -> bool {
1237 self.supported_extensions
1238 .iter()
1239 .any(|ep| ep.extension_name_as_c_str() == Ok(extension))
1240 }
1241
1242 pub fn is_driver(&self, id: vk::DriverId) -> bool {
1243 self.driver.is_some_and(|driver| driver.driver_id == id)
1244 }
1245
1246 fn get_required_extensions(&self, requested_features: wgt::Features) -> Vec<&'static CStr> {
1248 let mut extensions = Vec::new();
1249
1250 extensions.push(khr::swapchain::NAME);
1255
1256 if self.device_api_version < vk::API_VERSION_1_1 {
1257 extensions.push(khr::maintenance1::NAME);
1259
1260 if self.supports_extension(khr::maintenance2::NAME) {
1262 extensions.push(khr::maintenance2::NAME);
1263 }
1264
1265 if self.supports_extension(khr::maintenance3::NAME) {
1267 extensions.push(khr::maintenance3::NAME);
1268 }
1269
1270 extensions.push(khr::storage_buffer_storage_class::NAME);
1272
1273 if requested_features.contains(wgt::Features::MULTIVIEW) {
1275 extensions.push(khr::multiview::NAME);
1276 }
1277
1278 if requested_features.contains(wgt::Features::TEXTURE_FORMAT_NV12) {
1280 extensions.push(khr::sampler_ycbcr_conversion::NAME);
1281 }
1282
1283 if requested_features.intersects(wgt::Features::SHADER_F16 | wgt::Features::SHADER_I16)
1285 {
1286 extensions.push(khr::_16bit_storage::NAME);
1291 }
1292
1293 if requested_features.contains(wgt::Features::SHADER_DRAW_INDEX) {
1294 extensions.push(khr::shader_draw_parameters::NAME);
1295 }
1296 }
1297
1298 if self.device_api_version < vk::API_VERSION_1_2 {
1299 if self.supports_extension(khr::image_format_list::NAME) {
1301 extensions.push(khr::image_format_list::NAME);
1302 }
1303
1304 if self.supports_extension(khr::driver_properties::NAME) {
1306 extensions.push(khr::driver_properties::NAME);
1307 }
1308
1309 if self.supports_extension(khr::timeline_semaphore::NAME) {
1311 extensions.push(khr::timeline_semaphore::NAME);
1312 }
1313
1314 if requested_features.intersects(INDEXING_FEATURES) {
1316 extensions.push(ext::descriptor_indexing::NAME);
1317 }
1318
1319 if requested_features.contains(wgt::Features::SHADER_F16)
1323 || self.supports_extension(khr::shader_float16_int8::NAME)
1324 {
1325 extensions.push(khr::shader_float16_int8::NAME);
1326 }
1327
1328 if requested_features.intersects(
1330 wgt::Features::EXPERIMENTAL_MESH_SHADER
1331 | wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES,
1332 ) {
1333 extensions.push(khr::spirv_1_4::NAME);
1334 }
1335
1336 }
1339
1340 if self.device_api_version < vk::API_VERSION_1_3 {
1341 if self.supports_extension(khr::maintenance4::NAME) {
1343 extensions.push(khr::maintenance4::NAME);
1344 }
1345
1346 if self.supports_extension(ext::image_robustness::NAME) {
1348 extensions.push(ext::image_robustness::NAME);
1349 }
1350
1351 if requested_features.contains(wgt::Features::SUBGROUP) {
1353 extensions.push(ext::subgroup_size_control::NAME);
1354 }
1355
1356 if self.supports_extension(khr::shader_integer_dot_product::NAME) {
1358 extensions.push(khr::shader_integer_dot_product::NAME);
1359 }
1360
1361 if self.device_api_version >= vk::API_VERSION_1_2
1369 && self.supports_extension(khr::dynamic_rendering::NAME)
1370 {
1371 extensions.push(khr::dynamic_rendering::NAME);
1372 }
1373
1374 if self.supports_extension(khr::load_store_op_none::NAME) {
1376 extensions.push(khr::load_store_op_none::NAME);
1377 }
1378
1379 if self.supports_extension(ash::qcom::render_pass_store_ops::NAME) {
1381 extensions.push(ash::qcom::render_pass_store_ops::NAME);
1382 }
1383
1384 if self.supports_extension(ext::load_store_op_none::NAME) {
1386 extensions.push(ext::load_store_op_none::NAME);
1387 }
1388
1389 if requested_features.contains(wgt::Features::DEBUG_PRINTF) {
1391 extensions.push(khr::shader_non_semantic_info::NAME);
1392 }
1393 }
1394
1395 if self.supports_extension(khr::swapchain_mutable_format::NAME) {
1397 extensions.push(khr::swapchain_mutable_format::NAME);
1398 }
1399
1400 if self.supports_extension(ext::robustness2::NAME) {
1402 extensions.push(ext::robustness2::NAME);
1403 }
1404
1405 if self.supports_extension(khr::external_memory_win32::NAME) {
1407 extensions.push(khr::external_memory_win32::NAME);
1408 }
1409
1410 if self.supports_extension(khr::external_memory_fd::NAME) {
1412 extensions.push(khr::external_memory_fd::NAME);
1413 }
1414
1415 if self.supports_extension(ext::external_memory_dma_buf::NAME) {
1417 extensions.push(ext::external_memory_dma_buf::NAME);
1418 }
1419
1420 if self.supports_extension(ext::image_drm_format_modifier::NAME) {
1422 extensions.push(ext::image_drm_format_modifier::NAME);
1423 }
1424
1425 if self.supports_extension(ext::memory_budget::NAME) {
1427 extensions.push(ext::memory_budget::NAME);
1428 } else {
1429 log::debug!("VK_EXT_memory_budget is not available.")
1430 }
1431
1432 if requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT_COUNT) {
1436 extensions.push(khr::draw_indirect_count::NAME);
1437 }
1438
1439 if requested_features.intersects(
1441 wgt::Features::EXPERIMENTAL_RAY_QUERY
1442 | wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES,
1443 ) {
1444 extensions.push(khr::deferred_host_operations::NAME);
1445 extensions.push(khr::acceleration_structure::NAME);
1446 extensions.push(khr::buffer_device_address::NAME);
1447 }
1448
1449 if requested_features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY) {
1451 extensions.push(khr::ray_query::NAME);
1452 }
1453
1454 if requested_features.contains(wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES) {
1456 extensions.push(khr::ray_tracing_pipeline::NAME);
1457 }
1458
1459 if requested_features.contains(wgt::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN) {
1460 extensions.push(khr::ray_tracing_position_fetch::NAME)
1461 }
1462
1463 if requested_features.contains(wgt::Features::CONSERVATIVE_RASTERIZATION) {
1465 extensions.push(ext::conservative_rasterization::NAME);
1466 }
1467
1468 #[cfg(target_vendor = "apple")]
1470 extensions.push(khr::portability_subset::NAME);
1471
1472 if requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR) {
1474 extensions.push(ext::texture_compression_astc_hdr::NAME);
1475 }
1476
1477 if requested_features.intersects(
1479 wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX,
1480 ) {
1481 extensions.push(khr::shader_atomic_int64::NAME);
1482 }
1483
1484 if requested_features.intersects(wgt::Features::TEXTURE_INT64_ATOMIC) {
1486 extensions.push(ext::shader_image_atomic_int64::NAME);
1487 }
1488
1489 if requested_features.contains(wgt::Features::SHADER_FLOAT32_ATOMIC) {
1491 extensions.push(ext::shader_atomic_float::NAME);
1492 }
1493
1494 if requested_features.contains(wgt::Features::VULKAN_GOOGLE_DISPLAY_TIMING) {
1496 extensions.push(google::display_timing::NAME);
1497 }
1498
1499 if requested_features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER) {
1500 extensions.push(ext::mesh_shader::NAME);
1501 }
1502
1503 if requested_features
1506 .intersects(wgt::Features::SHADER_BARYCENTRICS | wgt::Features::SHADER_PER_VERTEX)
1507 {
1508 extensions.push(khr::fragment_shader_barycentric::NAME);
1509 }
1510
1511 if requested_features.contains(wgt::Features::EXPERIMENTAL_COOPERATIVE_MATRIX) {
1513 extensions.push(khr::cooperative_matrix::NAME);
1514 }
1515
1516 extensions
1517 }
1518
1519 fn to_wgpu_limits(&self) -> wgt::Limits {
1520 let limits = &self.properties.limits;
1521
1522 let (
1524 mut max_task_workgroup_total_count,
1525 mut max_task_workgroups_per_dimension,
1526 mut max_mesh_workgroup_total_count,
1527 mut max_mesh_workgroups_per_dimension,
1528 ) = Default::default();
1529 let (
1530 mut max_task_invocations_per_workgroup,
1531 mut max_task_invocations_per_dimension,
1532 mut max_mesh_invocations_per_workgroup,
1533 mut max_mesh_invocations_per_dimension,
1534 mut max_task_payload_size,
1535 mut max_mesh_output_vertices,
1536 mut max_mesh_output_primitives,
1537 mut max_mesh_output_layers,
1538 mut max_mesh_multiview_view_count,
1539 ) = Default::default();
1540 if let Some(m) = self.mesh_shader {
1541 max_task_workgroup_total_count = m.max_task_work_group_total_count;
1542 max_task_workgroups_per_dimension =
1543 m.max_task_work_group_count.into_iter().min().unwrap();
1544 max_mesh_workgroup_total_count = m.max_mesh_work_group_total_count;
1545 max_mesh_workgroups_per_dimension =
1546 m.max_mesh_work_group_count.into_iter().min().unwrap();
1547 max_task_invocations_per_workgroup = m.max_task_work_group_invocations;
1548 max_task_invocations_per_dimension =
1549 m.max_task_work_group_size.into_iter().min().unwrap();
1550 max_mesh_invocations_per_workgroup = m.max_mesh_work_group_invocations;
1551 max_mesh_invocations_per_dimension =
1552 m.max_mesh_work_group_size.into_iter().min().unwrap();
1553 max_task_payload_size = m.max_task_payload_size;
1554 max_mesh_output_vertices = m.max_mesh_output_vertices;
1555 max_mesh_output_primitives = m.max_mesh_output_primitives;
1556 max_mesh_output_layers = m.max_mesh_output_layers;
1557 max_mesh_multiview_view_count = m.max_mesh_multiview_view_count;
1558 }
1559
1560 let max_memory_allocation_size = self
1561 .maintenance_3
1562 .map(|maintenance_3| maintenance_3.max_memory_allocation_size)
1563 .unwrap_or(u64::MAX);
1564 let max_buffer_size = self
1565 .maintenance_4
1566 .map(|maintenance_4| maintenance_4.max_buffer_size)
1567 .unwrap_or(u64::MAX);
1568 let max_buffer_size = max_buffer_size.min(max_memory_allocation_size);
1569
1570 let is_nvidia = self.properties.vendor_id == crate::auxil::db::nvidia::VENDOR;
1573 let max_buffer_size_cap =
1574 if (cfg!(target_os = "linux") || cfg!(target_os = "android")) && !is_nvidia {
1575 i32::MAX as u64
1576 } else {
1577 1u64 << 52
1578 };
1579
1580 let max_buffer_size = max_buffer_size.min(max_buffer_size_cap);
1581
1582 let mut max_binding_array_elements = 0;
1583 let mut max_sampler_binding_array_elements = 0;
1584 if let Some(ref descriptor_indexing) = self.descriptor_indexing {
1585 max_binding_array_elements = descriptor_indexing
1586 .max_descriptor_set_update_after_bind_sampled_images
1587 .min(descriptor_indexing.max_descriptor_set_update_after_bind_storage_images)
1588 .min(descriptor_indexing.max_descriptor_set_update_after_bind_storage_buffers)
1589 .min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_sampled_images)
1590 .min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_storage_images)
1591 .min(
1592 descriptor_indexing.max_per_stage_descriptor_update_after_bind_storage_buffers,
1593 );
1594
1595 max_sampler_binding_array_elements = descriptor_indexing
1596 .max_descriptor_set_update_after_bind_samplers
1597 .min(descriptor_indexing.max_per_stage_descriptor_update_after_bind_samplers);
1598 }
1599
1600 const MAX_SHADER_STAGES_PER_PIPELINE: u32 = 2;
1601
1602 let mut max_storage_textures_per_shader_stage = limits
1615 .max_per_stage_descriptor_storage_images
1616 .min(limits.max_descriptor_set_storage_images / MAX_SHADER_STAGES_PER_PIPELINE);
1617 let mut max_storage_buffers_per_shader_stage = limits
1618 .max_per_stage_descriptor_storage_buffers
1619 .min(limits.max_descriptor_set_storage_buffers / MAX_SHADER_STAGES_PER_PIPELINE);
1620 let mut max_color_attachments = limits
1621 .max_color_attachments
1622 .min(limits.max_fragment_output_attachments);
1623
1624 let ignore_max_fragment_combined_output_resources_by_device = [
1625 crate::auxil::db::intel::VENDOR,
1626 crate::auxil::db::nvidia::VENDOR,
1627 crate::auxil::db::amd::VENDOR,
1628 crate::auxil::db::imgtec::VENDOR,
1629 ]
1630 .contains(&self.properties.vendor_id);
1631 let ignore_max_fragment_combined_output_resources_by_driver =
1632 self.is_driver(vk::DriverId::MESA_AGXV);
1633 let ignore_max_fragment_combined_output_resources =
1634 ignore_max_fragment_combined_output_resources_by_device
1635 || ignore_max_fragment_combined_output_resources_by_driver;
1636
1637 if !ignore_max_fragment_combined_output_resources {
1638 crate::auxil::cap_limits_to_be_under_the_sum_limit(
1639 [
1640 &mut max_storage_textures_per_shader_stage,
1641 &mut max_storage_buffers_per_shader_stage,
1642 &mut max_color_attachments,
1643 ],
1644 limits.max_fragment_combined_output_resources,
1645 );
1646 }
1647
1648 let mut max_sampled_textures_per_shader_stage = limits
1659 .max_per_stage_descriptor_sampled_images
1660 .min(limits.max_descriptor_set_sampled_images / MAX_SHADER_STAGES_PER_PIPELINE);
1661 let mut max_uniform_buffers_per_shader_stage = limits
1662 .max_per_stage_descriptor_uniform_buffers
1663 .min(limits.max_descriptor_set_uniform_buffers / MAX_SHADER_STAGES_PER_PIPELINE);
1664
1665 crate::auxil::cap_limits_to_be_under_the_sum_limit(
1666 [
1667 &mut max_sampled_textures_per_shader_stage,
1668 &mut max_uniform_buffers_per_shader_stage,
1669 &mut max_storage_textures_per_shader_stage,
1670 &mut max_storage_buffers_per_shader_stage,
1671 &mut max_color_attachments,
1672 ],
1673 limits.max_per_stage_resources,
1674 );
1675
1676 let mut max_blas_geometry_count = 0;
1678 let mut max_blas_primitive_count = 0;
1679 let mut max_tlas_instance_count = 0;
1680 let mut max_acceleration_structures_per_shader_stage = 0;
1681 if let Some(properties) = self.acceleration_structure {
1682 max_blas_geometry_count = properties.max_geometry_count as u32;
1683 max_blas_primitive_count = properties.max_primitive_count as u32;
1684 max_tlas_instance_count = properties.max_instance_count as u32;
1685 max_acceleration_structures_per_shader_stage = properties
1686 .max_per_stage_descriptor_acceleration_structures
1687 .min(
1688 properties.max_descriptor_set_acceleration_structures
1689 / MAX_SHADER_STAGES_PER_PIPELINE,
1690 );
1691 }
1692
1693 let max_per_set_descriptors = self
1707 .maintenance_3
1708 .map(|maintenance_3| maintenance_3.max_per_set_descriptors)
1709 .unwrap_or(256);
1713
1714 let mut max_samplers_per_shader_stage = limits
1715 .max_per_stage_descriptor_samplers
1716 .min(limits.max_descriptor_set_samplers / MAX_SHADER_STAGES_PER_PIPELINE);
1717
1718 crate::auxil::cap_limits_to_be_under_the_sum_limit(
1719 [
1720 &mut max_sampled_textures_per_shader_stage,
1721 &mut max_uniform_buffers_per_shader_stage,
1722 &mut max_storage_textures_per_shader_stage,
1723 &mut max_storage_buffers_per_shader_stage,
1724 &mut max_samplers_per_shader_stage,
1725 &mut max_acceleration_structures_per_shader_stage,
1726 ],
1727 max_per_set_descriptors / MAX_SHADER_STAGES_PER_PIPELINE,
1728 );
1729
1730 let max_bindings_per_bind_group = 1000.max(max_per_set_descriptors);
1735
1736 let max_color_attachment_bytes_per_sample =
1742 max_color_attachments * wgt::TextureFormat::MAX_TARGET_PIXEL_BYTE_COST;
1743
1744 let mut max_ray_dispatch_count = 0;
1745 let mut max_ray_recursion_depth = 0;
1746
1747 if let Some(properties) = self.ray_tracing_pipeline {
1748 max_ray_dispatch_count = properties.max_ray_dispatch_invocation_count;
1749 max_ray_recursion_depth = properties.max_ray_recursion_depth;
1750 }
1751
1752 let max_multiview_view_count = self
1753 .multiview
1754 .map(|a| a.max_multiview_view_count.min(32))
1755 .unwrap_or(0);
1756
1757 crate::auxil::adjust_raw_limits(wgt::Limits {
1758 max_texture_dimension_1d: limits.max_image_dimension1_d,
1763 max_texture_dimension_2d: limits
1764 .max_image_dimension2_d
1765 .min(limits.max_image_dimension_cube)
1766 .min(limits.max_framebuffer_width)
1767 .min(limits.max_framebuffer_height),
1768 max_texture_dimension_3d: limits.max_image_dimension3_d,
1769 max_texture_array_layers: limits.max_image_array_layers,
1770 max_bind_groups: limits.max_bound_descriptor_sets,
1771 max_bind_groups_plus_vertex_buffers: u32::MAX,
1773 max_bindings_per_bind_group,
1774 max_dynamic_uniform_buffers_per_pipeline_layout: limits
1775 .max_descriptor_set_uniform_buffers_dynamic,
1776 max_dynamic_storage_buffers_per_pipeline_layout: limits
1777 .max_descriptor_set_storage_buffers_dynamic,
1778 max_samplers_per_shader_stage,
1779 max_sampled_textures_per_shader_stage,
1780 max_storage_buffers_per_shader_stage,
1781 max_storage_buffers_in_vertex_stage: 0,
1782 max_storage_buffers_in_fragment_stage: 0,
1783 max_storage_textures_per_shader_stage,
1784 max_storage_textures_in_vertex_stage: 0,
1785 max_storage_textures_in_fragment_stage: 0,
1786 max_uniform_buffers_per_shader_stage,
1787 max_vertex_buffers: limits.max_vertex_input_bindings,
1788 max_buffer_size,
1789 max_uniform_buffer_binding_size: limits
1790 .max_uniform_buffer_range
1791 .min(crate::auxil::MAX_I32_BINDING_SIZE)
1792 .into(),
1793 max_storage_buffer_binding_size: limits
1794 .max_storage_buffer_range
1795 .min(crate::auxil::MAX_I32_BINDING_SIZE)
1796 .into(),
1797 min_uniform_buffer_offset_alignment: limits.min_uniform_buffer_offset_alignment as u32,
1798 min_storage_buffer_offset_alignment: limits.min_storage_buffer_offset_alignment as u32,
1799 max_vertex_attributes: limits.max_vertex_input_attributes,
1800 max_vertex_buffer_array_stride: limits.max_vertex_input_binding_stride,
1801 max_inter_stage_shader_variables: limits
1802 .max_vertex_output_components
1803 .min(limits.max_fragment_input_components)
1804 / 4
1805 - 1, max_color_attachments,
1807 max_color_attachment_bytes_per_sample,
1808 max_compute_workgroup_storage_size: limits.max_compute_shared_memory_size,
1809 max_compute_invocations_per_workgroup: limits.max_compute_work_group_invocations,
1810 max_compute_workgroup_size_x: limits.max_compute_work_group_size[0],
1811 max_compute_workgroup_size_y: limits.max_compute_work_group_size[1],
1812 max_compute_workgroup_size_z: limits.max_compute_work_group_size[2],
1813 max_compute_workgroups_per_dimension: limits.max_compute_work_group_count[0]
1814 .min(limits.max_compute_work_group_count[1])
1815 .min(limits.max_compute_work_group_count[2]),
1816 max_immediate_size: limits.max_push_constants_size,
1817 max_non_sampler_bindings: u32::MAX,
1821
1822 max_binding_array_elements_per_shader_stage: max_binding_array_elements,
1823 max_binding_array_sampler_elements_per_shader_stage: max_sampler_binding_array_elements,
1824 max_binding_array_acceleration_structure_elements_per_shader_stage: if self
1825 .descriptor_indexing
1826 .is_some()
1827 {
1828 max_acceleration_structures_per_shader_stage
1829 } else {
1830 0
1831 },
1832
1833 max_task_workgroup_total_count,
1834 max_task_workgroups_per_dimension,
1835 max_mesh_workgroup_total_count,
1836 max_mesh_workgroups_per_dimension,
1837
1838 max_task_invocations_per_workgroup,
1839 max_task_invocations_per_dimension,
1840
1841 max_mesh_invocations_per_workgroup,
1842 max_mesh_invocations_per_dimension,
1843
1844 max_task_payload_size,
1845 max_mesh_output_vertices,
1846 max_mesh_output_primitives,
1847 max_mesh_output_layers,
1848 max_mesh_multiview_view_count,
1849
1850 max_blas_primitive_count,
1851 max_blas_geometry_count,
1852 max_tlas_instance_count,
1853 max_acceleration_structures_per_shader_stage,
1854 max_buffers_and_acceleration_structures_per_shader_stage: u32::MAX,
1855
1856 max_multiview_view_count,
1857
1858 max_ray_dispatch_count,
1859 max_ray_recursion_depth,
1860 })
1861 }
1862
1863 fn to_hal_alignments(&self, using_robustness2: bool) -> crate::Alignments {
1878 let limits = &self.properties.limits;
1879 crate::Alignments {
1880 buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
1881 .unwrap(),
1882 buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
1883 .unwrap(),
1884 uniform_bounds_check_alignment: {
1885 let alignment = if using_robustness2 {
1886 self.robustness2
1887 .unwrap() .robust_uniform_buffer_access_size_alignment
1889 } else {
1890 1
1892 };
1893 wgt::BufferSize::new(alignment).unwrap()
1894 },
1895 raw_tlas_instance_size: 64,
1896 ray_tracing_scratch_buffer_alignment: self.acceleration_structure.map_or(
1897 0,
1898 |acceleration_structure| {
1899 acceleration_structure.min_acceleration_structure_scratch_offset_alignment
1900 },
1901 ),
1902 ray_tracing_pipeline_group_data_size: self
1903 .ray_tracing_pipeline
1904 .map_or(0, |ray_tracing_pipeline| {
1905 ray_tracing_pipeline.shader_group_handle_size
1906 }),
1907 ray_tracing_pipeline_group_data_alignment: self
1908 .ray_tracing_pipeline
1909 .map_or(0, |ray_tracing_pipeline| {
1910 ray_tracing_pipeline.shader_group_handle_alignment
1911 }),
1912 ray_tracing_pipeline_data_offset_alignment: self
1913 .ray_tracing_pipeline
1914 .map_or(0, |ray_tracing_pipeline| {
1915 ray_tracing_pipeline.shader_group_base_alignment
1916 }),
1917 }
1918 }
1919}
1920
1921impl super::InstanceShared {
1922 fn inspect(
1923 &self,
1924 phd: vk::PhysicalDevice,
1925 ) -> (PhysicalDeviceProperties, PhysicalDeviceFeatures) {
1926 let capabilities = {
1927 let mut capabilities = PhysicalDeviceProperties::default();
1928 capabilities.supported_extensions =
1929 unsafe { self.raw.enumerate_device_extension_properties(phd).unwrap() };
1930 capabilities.properties = unsafe { self.raw.get_physical_device_properties(phd) };
1931 capabilities.device_api_version = capabilities.properties.api_version;
1932
1933 let supports_multiview = capabilities.device_api_version >= vk::API_VERSION_1_1
1934 || capabilities.supports_extension(khr::multiview::NAME);
1935
1936 if let Some(ref get_device_properties) = self.get_physical_device_properties {
1937 let supports_maintenance3 = capabilities.device_api_version >= vk::API_VERSION_1_1
1939 || capabilities.supports_extension(khr::maintenance3::NAME);
1940 let supports_maintenance4 = capabilities.device_api_version >= vk::API_VERSION_1_3
1941 || capabilities.supports_extension(khr::maintenance4::NAME);
1942 let supports_maintenance5 = capabilities.device_api_version
1943 >= vk::make_api_version(0, 1, 4, 0) || capabilities.supports_extension(khr::maintenance5::NAME);
1945 let supports_descriptor_indexing = capabilities.device_api_version
1946 >= vk::API_VERSION_1_2
1947 || capabilities.supports_extension(ext::descriptor_indexing::NAME);
1948 let supports_driver_properties = capabilities.device_api_version
1949 >= vk::API_VERSION_1_2
1950 || capabilities.supports_extension(khr::driver_properties::NAME);
1951 let supports_subgroup_size_control = capabilities.device_api_version
1952 >= vk::API_VERSION_1_3
1953 || capabilities.supports_extension(ext::subgroup_size_control::NAME);
1954 let supports_robustness2 = capabilities.supports_extension(ext::robustness2::NAME);
1955 let supports_pci_bus_info =
1956 capabilities.supports_extension(ext::pci_bus_info::NAME);
1957
1958 let supports_acceleration_structure =
1959 capabilities.supports_extension(khr::acceleration_structure::NAME);
1960
1961 let supports_ray_tracing_pipeline =
1962 capabilities.supports_extension(khr::ray_tracing_pipeline::NAME);
1963
1964 let supports_mesh_shader = capabilities.supports_extension(ext::mesh_shader::NAME);
1965
1966 let mut properties2 = vk::PhysicalDeviceProperties2KHR::default();
1967 if supports_maintenance3 {
1968 let next = capabilities
1969 .maintenance_3
1970 .insert(vk::PhysicalDeviceMaintenance3Properties::default());
1971 properties2 = properties2.push_next(next);
1972 }
1973
1974 if supports_maintenance4 {
1975 let next = capabilities
1976 .maintenance_4
1977 .insert(vk::PhysicalDeviceMaintenance4Properties::default());
1978 properties2 = properties2.push_next(next);
1979 }
1980
1981 if supports_maintenance5 {
1982 let next = capabilities
1983 .maintenance_5
1984 .insert(vk::PhysicalDeviceMaintenance5PropertiesKHR::default());
1985 properties2 = properties2.push_next(next);
1986 }
1987
1988 if supports_descriptor_indexing {
1989 let next = capabilities
1990 .descriptor_indexing
1991 .insert(vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::default());
1992 properties2 = properties2.push_next(next);
1993 }
1994
1995 if supports_acceleration_structure {
1996 let next = capabilities
1997 .acceleration_structure
1998 .insert(vk::PhysicalDeviceAccelerationStructurePropertiesKHR::default());
1999 properties2 = properties2.push_next(next);
2000 }
2001
2002 if supports_ray_tracing_pipeline {
2003 let next = capabilities
2004 .ray_tracing_pipeline
2005 .insert(vk::PhysicalDeviceRayTracingPipelinePropertiesKHR::default());
2006 properties2 = properties2.push_next(next);
2007 }
2008
2009 if supports_driver_properties {
2010 let next = capabilities
2011 .driver
2012 .insert(vk::PhysicalDeviceDriverPropertiesKHR::default());
2013 properties2 = properties2.push_next(next);
2014 }
2015
2016 if capabilities.device_api_version >= vk::API_VERSION_1_1 {
2017 let next = capabilities
2018 .subgroup
2019 .insert(vk::PhysicalDeviceSubgroupProperties::default());
2020 properties2 = properties2.push_next(next);
2021 }
2022
2023 if supports_subgroup_size_control {
2024 let next = capabilities
2025 .subgroup_size_control
2026 .insert(vk::PhysicalDeviceSubgroupSizeControlProperties::default());
2027 properties2 = properties2.push_next(next);
2028 }
2029
2030 if supports_robustness2 {
2031 let next = capabilities
2032 .robustness2
2033 .insert(vk::PhysicalDeviceRobustness2PropertiesEXT::default());
2034 properties2 = properties2.push_next(next);
2035 }
2036
2037 if supports_pci_bus_info {
2038 let next = capabilities
2039 .pci_bus_info
2040 .insert(vk::PhysicalDevicePCIBusInfoPropertiesEXT::default());
2041 properties2 = properties2.push_next(next);
2042 }
2043
2044 if supports_mesh_shader {
2045 let next = capabilities
2046 .mesh_shader
2047 .insert(vk::PhysicalDeviceMeshShaderPropertiesEXT::default());
2048 properties2 = properties2.push_next(next);
2049 }
2050
2051 if supports_multiview {
2052 let next = capabilities
2053 .multiview
2054 .insert(vk::PhysicalDeviceMultiviewProperties::default());
2055 properties2 = properties2.push_next(next);
2056 }
2057
2058 unsafe {
2059 get_device_properties.get_physical_device_properties2(phd, &mut properties2)
2060 };
2061
2062 if capabilities.supports_extension(khr::cooperative_matrix::NAME) {
2064 let coop_matrix =
2065 khr::cooperative_matrix::Instance::new(&self.entry, &self.raw);
2066 capabilities.cooperative_matrix_properties =
2067 query_cooperative_matrix_properties(&coop_matrix, phd);
2068 }
2069
2070 if is_intel_igpu_outdated_for_robustness2(&capabilities) {
2072 capabilities
2073 .supported_extensions
2074 .retain(|&x| x.extension_name_as_c_str() != Ok(ext::robustness2::NAME));
2075 capabilities.robustness2 = None;
2076 }
2077
2078 if capabilities.is_driver(vk::DriverId::MESA_RADV) {
2082 capabilities
2083 .supported_extensions
2084 .retain(|&x| x.extension_name_as_c_str() != Ok(ext::memory_budget::NAME));
2085 }
2086 };
2087 capabilities
2088 };
2089
2090 let mut features = PhysicalDeviceFeatures::default();
2091 features.core = if let Some(ref get_device_properties) = self.get_physical_device_properties
2092 {
2093 let core = vk::PhysicalDeviceFeatures::default();
2094 let mut features2 = vk::PhysicalDeviceFeatures2KHR::default().features(core);
2095
2096 if capabilities.device_api_version >= vk::API_VERSION_1_1
2098 || capabilities.supports_extension(khr::multiview::NAME)
2099 {
2100 let next = features
2101 .multiview
2102 .insert(vk::PhysicalDeviceMultiviewFeatures::default());
2103 features2 = features2.push_next(next);
2104 }
2105
2106 if capabilities.device_api_version >= vk::API_VERSION_1_1
2108 || capabilities.supports_extension(khr::sampler_ycbcr_conversion::NAME)
2109 {
2110 let next = features
2111 .sampler_ycbcr_conversion
2112 .insert(vk::PhysicalDeviceSamplerYcbcrConversionFeatures::default());
2113 features2 = features2.push_next(next);
2114 }
2115
2116 if capabilities.supports_extension(ext::descriptor_indexing::NAME) {
2117 let next = features
2118 .descriptor_indexing
2119 .insert(vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default());
2120 features2 = features2.push_next(next);
2121 }
2122
2123 if capabilities.supports_extension(khr::timeline_semaphore::NAME) {
2126 let next = features
2127 .timeline_semaphore
2128 .insert(vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default());
2129 features2 = features2.push_next(next);
2130 }
2131
2132 if capabilities.device_api_version >= vk::API_VERSION_1_2
2135 || capabilities.supports_extension(khr::shader_atomic_int64::NAME)
2136 {
2137 let next = features
2138 .shader_atomic_int64
2139 .insert(vk::PhysicalDeviceShaderAtomicInt64Features::default());
2140 features2 = features2.push_next(next);
2141 }
2142
2143 if capabilities.supports_extension(ext::shader_image_atomic_int64::NAME) {
2144 let next = features
2145 .shader_image_atomic_int64
2146 .insert(vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT::default());
2147 features2 = features2.push_next(next);
2148 }
2149 if capabilities.supports_extension(ext::shader_atomic_float::NAME) {
2150 let next = features
2151 .shader_atomic_float
2152 .insert(vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT::default());
2153 features2 = features2.push_next(next);
2154 }
2155 if capabilities.supports_extension(ext::image_robustness::NAME) {
2156 let next = features
2157 .image_robustness
2158 .insert(vk::PhysicalDeviceImageRobustnessFeaturesEXT::default());
2159 features2 = features2.push_next(next);
2160 }
2161 if capabilities.supports_extension(ext::robustness2::NAME) {
2162 let next = features
2163 .robustness2
2164 .insert(vk::PhysicalDeviceRobustness2FeaturesEXT::default());
2165 features2 = features2.push_next(next);
2166 }
2167 if capabilities.supports_extension(ext::texture_compression_astc_hdr::NAME) {
2168 let next = features
2169 .astc_hdr
2170 .insert(vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::default());
2171 features2 = features2.push_next(next);
2172 }
2173
2174 if capabilities.device_api_version >= vk::API_VERSION_1_2
2176 || capabilities.supports_extension(khr::shader_float16_int8::NAME)
2177 {
2178 let next = features
2179 .shader_float16_int8
2180 .insert(vk::PhysicalDeviceShaderFloat16Int8FeaturesKHR::default());
2181 features2 = features2.push_next(next);
2182 }
2183
2184 if capabilities.supports_extension(khr::_16bit_storage::NAME) {
2185 let next = features
2186 ._16bit_storage
2187 .insert(vk::PhysicalDevice16BitStorageFeaturesKHR::default());
2188 features2 = features2.push_next(next);
2189 }
2190 if capabilities.supports_extension(khr::acceleration_structure::NAME) {
2191 let next = features
2192 .acceleration_structure
2193 .insert(vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default());
2194 features2 = features2.push_next(next);
2195 }
2196
2197 if capabilities.supports_extension(khr::ray_tracing_position_fetch::NAME) {
2198 let next = features
2199 .position_fetch
2200 .insert(vk::PhysicalDeviceRayTracingPositionFetchFeaturesKHR::default());
2201 features2 = features2.push_next(next);
2202 }
2203
2204 if capabilities.device_api_version >= vk::API_VERSION_1_3
2206 || capabilities.supports_extension(khr::maintenance4::NAME)
2207 {
2208 let next = features
2209 .maintenance4
2210 .insert(vk::PhysicalDeviceMaintenance4Features::default());
2211 features2 = features2.push_next(next);
2212 }
2213
2214 if capabilities.device_api_version >= vk::API_VERSION_1_3
2216 || capabilities.supports_extension(khr::zero_initialize_workgroup_memory::NAME)
2217 {
2218 let next = features
2219 .zero_initialize_workgroup_memory
2220 .insert(vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::default());
2221 features2 = features2.push_next(next);
2222 }
2223
2224 if capabilities.device_api_version >= vk::API_VERSION_1_3
2226 || capabilities.supports_extension(ext::subgroup_size_control::NAME)
2227 {
2228 let next = features
2229 .subgroup_size_control
2230 .insert(vk::PhysicalDeviceSubgroupSizeControlFeatures::default());
2231 features2 = features2.push_next(next);
2232 }
2233
2234 if capabilities.supports_extension(ext::mesh_shader::NAME) {
2235 let next = features
2236 .mesh_shader
2237 .insert(vk::PhysicalDeviceMeshShaderFeaturesEXT::default());
2238 features2 = features2.push_next(next);
2239 }
2240
2241 if capabilities.device_api_version >= vk::API_VERSION_1_3
2243 || capabilities.supports_extension(khr::shader_integer_dot_product::NAME)
2244 {
2245 let next = features
2246 .shader_integer_dot_product
2247 .insert(vk::PhysicalDeviceShaderIntegerDotProductFeatures::default());
2248 features2 = features2.push_next(next);
2249 }
2250
2251 if capabilities.supports_extension(khr::fragment_shader_barycentric::NAME) {
2252 let next = features
2253 .shader_barycentrics
2254 .insert(vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR::default());
2255 features2 = features2.push_next(next);
2256 }
2257
2258 if capabilities.supports_extension(khr::portability_subset::NAME) {
2259 let next = features
2260 .portability_subset
2261 .insert(vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default());
2262 features2 = features2.push_next(next);
2263 }
2264
2265 if capabilities.supports_extension(khr::cooperative_matrix::NAME) {
2266 let next = features
2267 .cooperative_matrix
2268 .insert(vk::PhysicalDeviceCooperativeMatrixFeaturesKHR::default());
2269 features2 = features2.push_next(next);
2270 }
2271
2272 if capabilities.device_api_version >= vk::API_VERSION_1_2
2273 || capabilities.supports_extension(khr::vulkan_memory_model::NAME)
2274 {
2275 let next = features
2276 .vulkan_memory_model
2277 .insert(vk::PhysicalDeviceVulkanMemoryModelFeaturesKHR::default());
2278 features2 = features2.push_next(next);
2279 }
2280
2281 if capabilities.device_api_version >= vk::API_VERSION_1_1 {
2282 let next = features
2283 .shader_draw_parameters
2284 .insert(vk::PhysicalDeviceShaderDrawParametersFeatures::default());
2285 features2 = features2.push_next(next);
2286 }
2287
2288 unsafe { get_device_properties.get_physical_device_features2(phd, &mut features2) };
2289 features2.features
2290 } else {
2291 unsafe { self.raw.get_physical_device_features(phd) }
2292 };
2293
2294 (capabilities, features)
2295 }
2296}
2297
2298impl super::Instance {
2299 pub fn expose_adapter(
2300 &self,
2301 phd: vk::PhysicalDevice,
2302 ) -> Option<crate::ExposedAdapter<super::Api>> {
2303 use crate::auxil::db;
2304
2305 let (phd_capabilities, phd_features) = self.shared.inspect(phd);
2306
2307 let mem_properties = {
2308 profiling::scope!("vkGetPhysicalDeviceMemoryProperties");
2309 unsafe { self.shared.raw.get_physical_device_memory_properties(phd) }
2310 };
2311 let memory_types = &mem_properties.memory_types_as_slice();
2312 let supports_lazily_allocated = memory_types.iter().any(|mem| {
2313 mem.property_flags
2314 .contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED)
2315 });
2316
2317 let device_type = match phd_capabilities.properties.device_type {
2318 vk::PhysicalDeviceType::OTHER => wgt::DeviceType::Other,
2319 vk::PhysicalDeviceType::INTEGRATED_GPU => wgt::DeviceType::IntegratedGpu,
2320 vk::PhysicalDeviceType::DISCRETE_GPU => wgt::DeviceType::DiscreteGpu,
2321 vk::PhysicalDeviceType::VIRTUAL_GPU => wgt::DeviceType::VirtualGpu,
2322 vk::PhysicalDeviceType::CPU => wgt::DeviceType::Cpu,
2323 _ => wgt::DeviceType::Other,
2324 };
2325 let info = wgt::AdapterInfo {
2326 name: {
2327 phd_capabilities
2328 .properties
2329 .device_name_as_c_str()
2330 .ok()
2331 .and_then(|name| name.to_str().ok())
2332 .unwrap_or("?")
2333 .to_owned()
2334 },
2335 vendor: phd_capabilities.properties.vendor_id,
2336 device: phd_capabilities.properties.device_id,
2337 device_pci_bus_id: phd_capabilities
2338 .pci_bus_info
2339 .filter(|info| info.pci_bus != 0 || info.pci_device != 0)
2340 .map(|info| {
2341 format!(
2342 "{:04x}:{:02x}:{:02x}.{}",
2343 info.pci_domain, info.pci_bus, info.pci_device, info.pci_function
2344 )
2345 })
2346 .unwrap_or_default(),
2347 driver: {
2348 phd_capabilities
2349 .driver
2350 .as_ref()
2351 .and_then(|driver| driver.driver_name_as_c_str().ok())
2352 .and_then(|name| name.to_str().ok())
2353 .unwrap_or("?")
2354 .to_owned()
2355 },
2356 driver_info: {
2357 phd_capabilities
2358 .driver
2359 .as_ref()
2360 .and_then(|driver| driver.driver_info_as_c_str().ok())
2361 .and_then(|name| name.to_str().ok())
2362 .unwrap_or("?")
2363 .to_owned()
2364 },
2365 subgroup_min_size: phd_capabilities
2366 .subgroup_size_control
2367 .map(|subgroup_size| subgroup_size.min_subgroup_size)
2368 .unwrap_or(wgt::MINIMUM_SUBGROUP_MIN_SIZE),
2369 subgroup_max_size: phd_capabilities
2370 .subgroup_size_control
2371 .map(|subgroup_size| subgroup_size.max_subgroup_size)
2372 .unwrap_or(wgt::MAXIMUM_SUBGROUP_MAX_SIZE),
2373 transient_saves_memory: Some(supports_lazily_allocated),
2374 ..wgt::AdapterInfo::new(device_type, wgt::Backend::Vulkan)
2375 };
2376 let mut workarounds = super::Workarounds::empty();
2377 {
2378 workarounds |= super::Workarounds::SEPARATE_ENTRY_POINTS;
2380 workarounds.set(
2381 super::Workarounds::EMPTY_RESOLVE_ATTACHMENT_LISTS,
2382 phd_capabilities.properties.vendor_id == db::qualcomm::VENDOR,
2383 );
2384 workarounds.set(
2385 super::Workarounds::FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16,
2386 phd_capabilities.properties.vendor_id == db::nvidia::VENDOR,
2387 );
2388 };
2389
2390 if let Some(driver) = phd_capabilities.driver {
2391 if driver.conformance_version.major == 0 {
2392 if driver.driver_id == vk::DriverId::MOLTENVK {
2393 log::debug!("Adapter is not Vulkan compliant, but is MoltenVK, continuing");
2394 } else if self
2395 .shared
2396 .flags
2397 .contains(wgt::InstanceFlags::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER)
2398 {
2399 log::debug!("Adapter is not Vulkan compliant: {}", info.name);
2400 } else {
2401 log::debug!(
2402 "Adapter is not Vulkan compliant, hiding adapter: {}",
2403 info.name
2404 );
2405 return None;
2406 }
2407 }
2408 }
2409 if phd_capabilities.device_api_version == vk::API_VERSION_1_0
2410 && !phd_capabilities.supports_extension(khr::storage_buffer_storage_class::NAME)
2411 {
2412 log::debug!(
2413 "SPIR-V storage buffer class is not supported, hiding adapter: {}",
2414 info.name
2415 );
2416 return None;
2417 }
2418 if !phd_capabilities.supports_extension(khr::maintenance1::NAME)
2419 && phd_capabilities.device_api_version < vk::API_VERSION_1_1
2420 {
2421 log::debug!(
2422 "VK_KHR_maintenance1 is not supported, hiding adapter: {}",
2423 info.name
2424 );
2425 return None;
2426 }
2427
2428 let queue_families = unsafe {
2429 self.shared
2430 .raw
2431 .get_physical_device_queue_family_properties(phd)
2432 };
2433 let queue_family_properties = queue_families.first()?;
2434 let queue_flags = queue_family_properties.queue_flags;
2435 if !queue_flags.contains(vk::QueueFlags::GRAPHICS) {
2436 log::debug!("The first queue only exposes {queue_flags:?}");
2437 return None;
2438 }
2439
2440 let (available_features, mut downlevel_flags) = phd_features.to_wgpu(
2441 &self.shared.raw,
2442 phd,
2443 &phd_capabilities,
2444 queue_family_properties,
2445 );
2446
2447 if phd_capabilities.is_driver(vk::DriverId::MESA_LLVMPIPE) {
2448 downlevel_flags.set(
2451 wgt::DownlevelFlags::SHADER_F16_IN_F32,
2452 available_features.contains(wgt::Features::SHADER_F16),
2453 );
2454 }
2455
2456 downlevel_flags.set(
2457 wgt::DownlevelFlags::TEXTURE_COMPRESSION,
2458 available_features.contains(wgt::Features::TEXTURE_COMPRESSION_BC)
2459 || available_features.contains(
2460 wgt::Features::TEXTURE_COMPRESSION_ETC2
2461 | wgt::Features::TEXTURE_COMPRESSION_ASTC,
2462 ),
2463 );
2464
2465 let has_robust_buffer_access2 = phd_features
2466 .robustness2
2467 .as_ref()
2468 .map(|r| r.robust_buffer_access2 == 1)
2469 .unwrap_or_default();
2470
2471 let alignments = phd_capabilities.to_hal_alignments(has_robust_buffer_access2);
2472
2473 let private_caps = super::PrivateCapabilities {
2474 image_view_usage: phd_capabilities.device_api_version >= vk::API_VERSION_1_1
2475 || phd_capabilities.supports_extension(khr::maintenance2::NAME),
2476 timeline_semaphores: match phd_features.timeline_semaphore {
2477 Some(features) => features.timeline_semaphore == vk::TRUE,
2478 None => phd_features
2479 .timeline_semaphore
2480 .is_some_and(|ext| ext.timeline_semaphore != 0),
2481 },
2482 texture_d24: supports_format(
2483 &self.shared.raw,
2484 phd,
2485 vk::Format::X8_D24_UNORM_PACK32,
2486 vk::ImageTiling::OPTIMAL,
2487 depth_stencil_required_flags(),
2488 ),
2489 texture_d24_s8: supports_format(
2490 &self.shared.raw,
2491 phd,
2492 vk::Format::D24_UNORM_S8_UINT,
2493 vk::ImageTiling::OPTIMAL,
2494 depth_stencil_required_flags(),
2495 ),
2496 texture_s8: supports_format(
2497 &self.shared.raw,
2498 phd,
2499 vk::Format::S8_UINT,
2500 vk::ImageTiling::OPTIMAL,
2501 depth_stencil_required_flags(),
2502 ),
2503 multi_draw_indirect: phd_features.core.multi_draw_indirect != 0,
2504 max_draw_indirect_count: phd_capabilities.properties.limits.max_draw_indirect_count,
2505 non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1,
2506 can_present: true,
2507 robust_buffer_access: phd_features.core.robust_buffer_access != 0,
2509 robust_image_access: phd_features
2510 .robustness2
2511 .is_some_and(|f| f.robust_image_access2 != 0)
2512 || phd_features
2513 .image_robustness
2514 .is_some_and(|ext| ext.robust_image_access != 0),
2515 robust_buffer_access2: has_robust_buffer_access2,
2516 robust_image_access2: phd_features
2517 .robustness2
2518 .as_ref()
2519 .map(|r| r.robust_image_access2 == 1)
2520 .unwrap_or_default(),
2521 zero_initialize_workgroup_memory: phd_features
2522 .zero_initialize_workgroup_memory
2523 .is_some_and(|ext| ext.shader_zero_initialize_workgroup_memory == vk::TRUE),
2524 image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2
2525 || phd_capabilities.supports_extension(khr::image_format_list::NAME),
2526 maximum_samplers: phd_capabilities
2527 .properties
2528 .limits
2529 .max_sampler_allocation_count,
2530 shader_integer_dot_product: phd_features
2531 .shader_integer_dot_product
2532 .is_some_and(|ext| ext.shader_integer_dot_product != 0),
2533 shader_int8: phd_features
2534 .shader_float16_int8
2535 .is_some_and(|features| features.shader_int8 != 0),
2536 multiview_instance_index_limit: phd_capabilities
2537 .multiview
2538 .map(|a| a.max_multiview_instance_index)
2539 .unwrap_or(0),
2540 scratch_buffer_alignment: alignments.ray_tracing_scratch_buffer_alignment,
2541 depth_stencil_swizzle_one_support: phd_capabilities
2542 .maintenance_5
2543 .map(|maintenance_5| maintenance_5.depth_stencil_swizzle_one_support == vk::TRUE)
2544 .unwrap_or(false),
2545 ray_tracing_pipeline_group_data_size: alignments.ray_tracing_pipeline_group_data_size,
2546 store_op_none: phd_capabilities.device_api_version >= vk::API_VERSION_1_3
2547 || (phd_capabilities.device_api_version >= vk::API_VERSION_1_2
2548 && phd_capabilities.supports_extension(khr::dynamic_rendering::NAME))
2549 || phd_capabilities.supports_extension(khr::load_store_op_none::NAME)
2550 || phd_capabilities.supports_extension(ash::qcom::render_pass_store_ops::NAME)
2551 || phd_capabilities.supports_extension(ext::load_store_op_none::NAME),
2552 };
2553 let capabilities = crate::Capabilities {
2554 limits: phd_capabilities.to_wgpu_limits(),
2555 alignments,
2556 downlevel: wgt::DownlevelCapabilities {
2557 flags: downlevel_flags,
2558 limits: wgt::DownlevelLimits {},
2559 shader_model: wgt::ShaderModel::Sm5, },
2561 cooperative_matrix_properties: phd_capabilities.cooperative_matrix_properties.clone(),
2562 };
2563
2564 let adapter = super::Adapter {
2565 raw: phd,
2566 instance: Arc::clone(&self.shared),
2567 known_memory_flags: vk::MemoryPropertyFlags::DEVICE_LOCAL
2569 | vk::MemoryPropertyFlags::HOST_VISIBLE
2570 | vk::MemoryPropertyFlags::HOST_COHERENT
2571 | vk::MemoryPropertyFlags::HOST_CACHED
2572 | vk::MemoryPropertyFlags::LAZILY_ALLOCATED,
2573 phd_capabilities,
2574 phd_features,
2575 downlevel_flags,
2576 private_caps,
2577 workarounds,
2578 };
2579
2580 Some(crate::ExposedAdapter {
2581 adapter,
2582 info,
2583 features: available_features,
2584 capabilities,
2585 })
2586 }
2587}
2588
2589impl super::Adapter {
2590 pub fn raw_physical_device(&self) -> vk::PhysicalDevice {
2591 self.raw
2592 }
2593
2594 pub fn get_physical_device_features(&self) -> &PhysicalDeviceFeatures {
2595 &self.phd_features
2596 }
2597
2598 pub fn physical_device_capabilities(&self) -> &PhysicalDeviceProperties {
2599 &self.phd_capabilities
2600 }
2601
2602 pub fn shared_instance(&self) -> &super::InstanceShared {
2603 &self.instance
2604 }
2605
2606 pub fn required_device_extensions(&self, features: wgt::Features) -> Vec<&'static CStr> {
2607 let (supported_extensions, unsupported_extensions) = self
2608 .phd_capabilities
2609 .get_required_extensions(features)
2610 .iter()
2611 .partition::<Vec<&CStr>, _>(|&&extension| {
2612 self.phd_capabilities.supports_extension(extension)
2613 });
2614
2615 if !unsupported_extensions.is_empty() {
2616 log::debug!("Missing extensions: {unsupported_extensions:?}");
2617 }
2618
2619 log::debug!("Supported extensions: {supported_extensions:?}");
2620 supported_extensions
2621 }
2622
2623 pub fn physical_device_features(
2638 &self,
2639 enabled_extensions: &[&'static CStr],
2640 features: wgt::Features,
2641 ) -> PhysicalDeviceFeatures {
2642 PhysicalDeviceFeatures::from_extensions_and_requested_features(
2643 &self.phd_capabilities,
2644 &self.phd_features,
2645 enabled_extensions,
2646 features,
2647 self.downlevel_flags,
2648 &self.private_caps,
2649 )
2650 }
2651
2652 #[allow(clippy::too_many_arguments)]
2660 pub unsafe fn device_from_raw(
2661 &self,
2662 raw_device: ash::Device,
2663 drop_callback: Option<crate::DropCallback>,
2664 enabled_extensions: &[&'static CStr],
2665 features: wgt::Features,
2666 limits: &wgt::Limits,
2667 memory_hints: &wgt::MemoryHints,
2668 family_index: u32,
2669 queue_index: u32,
2670 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
2671 let mem_properties = {
2672 profiling::scope!("vkGetPhysicalDeviceMemoryProperties");
2673 unsafe {
2674 self.instance
2675 .raw
2676 .get_physical_device_memory_properties(self.raw)
2677 }
2678 };
2679 let queue_flags = unsafe {
2680 self.instance
2681 .raw
2682 .get_physical_device_queue_family_properties(self.raw)
2683 .get(family_index as usize)
2684 .map(|queue_family_properties| queue_family_properties.queue_flags)
2685 .ok_or(crate::DeviceError::Unexpected)?
2686 };
2687 let memory_types = &mem_properties.memory_types_as_slice();
2688 let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| {
2689 if self.known_memory_flags.contains(mem.property_flags) {
2690 u | (1 << i)
2691 } else {
2692 u
2693 }
2694 });
2695
2696 let debug_utils_fn = if self.instance.extensions.contains(&ext::debug_utils::NAME) {
2700 Some(ext::debug_utils::Device::new(
2701 &self.instance.raw,
2702 &raw_device,
2703 ))
2704 } else {
2705 None
2706 };
2707 let indirect_count_fn = if enabled_extensions.contains(&khr::draw_indirect_count::NAME) {
2708 Some(khr::draw_indirect_count::Device::new(
2709 &self.instance.raw,
2710 &raw_device,
2711 ))
2712 } else {
2713 None
2714 };
2715 let timeline_semaphore_fn = if enabled_extensions.contains(&khr::timeline_semaphore::NAME) {
2716 Some(super::ExtensionFn::Extension(
2717 khr::timeline_semaphore::Device::new(&self.instance.raw, &raw_device),
2718 ))
2719 } else if self.phd_capabilities.device_api_version >= vk::API_VERSION_1_2 {
2720 Some(super::ExtensionFn::Promoted)
2721 } else {
2722 None
2723 };
2724 let ray_tracing_fns = if enabled_extensions.contains(&khr::acceleration_structure::NAME)
2725 && enabled_extensions.contains(&khr::buffer_device_address::NAME)
2726 {
2727 Some(super::RayTracingDeviceExtensionFunctions {
2728 acceleration_structure: khr::acceleration_structure::Device::new(
2729 &self.instance.raw,
2730 &raw_device,
2731 ),
2732 buffer_device_address: khr::buffer_device_address::Device::new(
2733 &self.instance.raw,
2734 &raw_device,
2735 ),
2736 })
2737 } else {
2738 None
2739 };
2740 let ray_tracing_pipeline_fns =
2741 if enabled_extensions.contains(&khr::ray_tracing_pipeline::NAME) {
2742 Some(khr::ray_tracing_pipeline::Device::new(
2743 &self.instance.raw,
2744 &raw_device,
2745 ))
2746 } else {
2747 None
2748 };
2749 let mesh_shading_fns = if enabled_extensions.contains(&ext::mesh_shader::NAME) {
2750 Some(ext::mesh_shader::Device::new(
2751 &self.instance.raw,
2752 &raw_device,
2753 ))
2754 } else {
2755 None
2756 };
2757 let external_memory_fd_fn = if enabled_extensions.contains(&khr::external_memory_fd::NAME) {
2758 Some(khr::external_memory_fd::Device::new(
2759 &self.instance.raw,
2760 &raw_device,
2761 ))
2762 } else {
2763 None
2764 };
2765
2766 let naga_options = {
2767 use naga::back::spv;
2768
2769 let mut capabilities = vec![
2772 spv::Capability::Shader,
2773 spv::Capability::Matrix,
2774 spv::Capability::Sampled1D,
2775 spv::Capability::Image1D,
2776 spv::Capability::ImageQuery,
2777 spv::Capability::DerivativeControl,
2778 spv::Capability::StorageImageExtendedFormats,
2779 ];
2780
2781 if self
2782 .downlevel_flags
2783 .contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES)
2784 {
2785 capabilities.push(spv::Capability::SampledCubeArray);
2786 }
2787
2788 if self
2789 .downlevel_flags
2790 .contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING)
2791 {
2792 capabilities.push(spv::Capability::SampleRateShading);
2793 }
2794
2795 if features.contains(wgt::Features::MULTIVIEW) {
2796 capabilities.push(spv::Capability::MultiView);
2797 }
2798
2799 if features.contains(wgt::Features::PRIMITIVE_INDEX) {
2800 capabilities.push(spv::Capability::Geometry);
2801 }
2802
2803 if features.intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX) {
2804 capabilities.push(spv::Capability::GroupNonUniform);
2805 capabilities.push(spv::Capability::GroupNonUniformVote);
2806 capabilities.push(spv::Capability::GroupNonUniformArithmetic);
2807 capabilities.push(spv::Capability::GroupNonUniformBallot);
2808 capabilities.push(spv::Capability::GroupNonUniformShuffle);
2809 capabilities.push(spv::Capability::GroupNonUniformShuffleRelative);
2810 capabilities.push(spv::Capability::GroupNonUniformQuad);
2811 }
2812
2813 if features.intersects(
2814 wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
2815 | wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
2816 | wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS,
2817 ) {
2818 capabilities.push(spv::Capability::ShaderNonUniform);
2819 }
2820 if features.contains(wgt::Features::BGRA8UNORM_STORAGE) {
2821 capabilities.push(spv::Capability::StorageImageWriteWithoutFormat);
2822 }
2823
2824 if features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY) {
2825 capabilities.push(spv::Capability::RayQueryKHR);
2826 }
2827
2828 if features.contains(wgt::Features::SHADER_INT64) {
2829 capabilities.push(spv::Capability::Int64);
2830 }
2831
2832 if features.contains(wgt::Features::SHADER_F16) {
2833 capabilities.push(spv::Capability::Float16);
2834 }
2835
2836 if features.contains(wgt::Features::SHADER_I16) {
2837 capabilities.push(spv::Capability::Int16);
2838 }
2839
2840 if features.intersects(
2841 wgt::Features::SHADER_INT64_ATOMIC_ALL_OPS
2842 | wgt::Features::SHADER_INT64_ATOMIC_MIN_MAX
2843 | wgt::Features::TEXTURE_INT64_ATOMIC,
2844 ) {
2845 capabilities.push(spv::Capability::Int64Atomics);
2846 }
2847
2848 if features.intersects(wgt::Features::TEXTURE_INT64_ATOMIC) {
2849 capabilities.push(spv::Capability::Int64ImageEXT);
2850 }
2851
2852 if features.contains(wgt::Features::SHADER_FLOAT32_ATOMIC) {
2853 capabilities.push(spv::Capability::AtomicFloat32AddEXT);
2854 }
2855
2856 if features.contains(wgt::Features::CLIP_DISTANCES) {
2857 capabilities.push(spv::Capability::ClipDistance);
2858 }
2859
2860 if features
2862 .intersects(wgt::Features::SHADER_BARYCENTRICS | wgt::Features::SHADER_PER_VERTEX)
2863 {
2864 capabilities.push(spv::Capability::FragmentBarycentricKHR);
2865 }
2866
2867 if features.contains(wgt::Features::SHADER_DRAW_INDEX) {
2868 capabilities.push(spv::Capability::DrawParameters);
2869 }
2870
2871 let mut flags = spv::WriterFlags::empty();
2872 flags.set(
2873 spv::WriterFlags::DEBUG,
2874 self.instance.flags.contains(wgt::InstanceFlags::DEBUG),
2875 );
2876 flags.set(
2877 spv::WriterFlags::LABEL_VARYINGS,
2878 self.phd_capabilities.properties.vendor_id != crate::auxil::db::qualcomm::VENDOR,
2879 );
2880 flags.set(
2881 spv::WriterFlags::FORCE_POINT_SIZE,
2882 true, );
2887 flags.set(
2888 spv::WriterFlags::PRINT_ON_RAY_QUERY_INITIALIZATION_FAIL
2889 | spv::WriterFlags::PRINT_ON_TRACE_RAYS_FAIL,
2890 self.instance.flags.contains(wgt::InstanceFlags::DEBUG)
2891 && (self.instance.instance_api_version >= vk::API_VERSION_1_3
2892 || enabled_extensions.contains(&khr::shader_non_semantic_info::NAME)),
2893 );
2894 if features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY) {
2895 capabilities.push(spv::Capability::RayQueryKHR);
2896 }
2897 if features.contains(wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES) {
2898 capabilities.push(spv::Capability::RayTracingKHR);
2899 }
2900 if features.contains(wgt::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN) {
2901 capabilities.push(spv::Capability::RayQueryPositionFetchKHR)
2902 }
2903 if features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER) {
2904 capabilities.push(spv::Capability::MeshShadingEXT);
2905 }
2906 if features.contains(wgt::Features::EXPERIMENTAL_COOPERATIVE_MATRIX) {
2907 capabilities.push(spv::Capability::CooperativeMatrixKHR);
2908 capabilities.push(spv::Capability::VulkanMemoryModel);
2910 }
2911 if self.private_caps.shader_integer_dot_product {
2912 capabilities.extend(&[
2914 spv::Capability::DotProductInputAllKHR,
2915 spv::Capability::DotProductInput4x8BitKHR,
2916 spv::Capability::DotProductInput4x8BitPackedKHR,
2917 spv::Capability::DotProductKHR,
2918 ]);
2919 }
2920 if self.private_caps.shader_int8 {
2921 capabilities.extend(&[spv::Capability::Int8]);
2923 }
2924 spv::Options {
2925 lang_version: {
2926 let version = match self.phd_capabilities.device_api_version {
2929 vk::API_VERSION_1_0..vk::API_VERSION_1_1 => (1, 0),
2930 vk::API_VERSION_1_1..vk::API_VERSION_1_2 => (1, 3),
2931 vk::API_VERSION_1_2..vk::API_VERSION_1_3 => (1, 5),
2932 vk::API_VERSION_1_3.. => (1, 6),
2933 _ => unreachable!(),
2934 };
2935 if enabled_extensions.contains(&khr::spirv_1_4::NAME) {
2938 version.max((1, 4))
2939 } else {
2940 version
2941 }
2942 },
2943 flags,
2944 capabilities: Some(capabilities.iter().cloned().collect()),
2945 bounds_check_policies: naga::proc::BoundsCheckPolicies {
2946 index: naga::proc::BoundsCheckPolicy::Restrict,
2947 buffer: if self.private_caps.robust_buffer_access2 {
2948 naga::proc::BoundsCheckPolicy::Unchecked
2949 } else {
2950 naga::proc::BoundsCheckPolicy::Restrict
2951 },
2952 image_load: if self.private_caps.robust_image_access {
2953 naga::proc::BoundsCheckPolicy::Unchecked
2954 } else {
2955 naga::proc::BoundsCheckPolicy::Restrict
2956 },
2957 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
2959 },
2960 zero_initialize_workgroup_memory: if self
2961 .private_caps
2962 .zero_initialize_workgroup_memory
2963 {
2964 spv::ZeroInitializeWorkgroupMemoryMode::Native
2965 } else {
2966 spv::ZeroInitializeWorkgroupMemoryMode::Polyfill
2967 },
2968 force_loop_bounding: true,
2969 ray_query_initialization_tracking: true,
2970 use_storage_input_output_16: features.contains(wgt::Features::SHADER_F16)
2971 && self.phd_features.supports_storage_input_output_16(),
2972 fake_missing_bindings: false,
2973 binding_map: BTreeMap::default(),
2975 debug_info: None,
2976 task_dispatch_limits: Some(naga::back::TaskDispatchLimits {
2977 max_mesh_workgroups_per_dim: limits.max_mesh_workgroups_per_dimension,
2978 max_mesh_workgroups_total: limits.max_mesh_workgroup_total_count,
2979 }),
2980 mesh_shader_primitive_indices_clamp: true,
2981 trace_ray_argument_validation: true,
2982 emit_int_div_checks: true,
2983 }
2984 };
2985
2986 let raw_queue = {
2987 profiling::scope!("vkGetDeviceQueue");
2988 unsafe { raw_device.get_device_queue(family_index, queue_index) }
2989 };
2990
2991 let driver_version = self
2992 .phd_capabilities
2993 .properties
2994 .driver_version
2995 .to_be_bytes();
2996 #[rustfmt::skip]
2997 let pipeline_cache_validation_key = [
2998 driver_version[0], driver_version[1], driver_version[2], driver_version[3],
2999 0, 0, 0, 0,
3000 0, 0, 0, 0,
3001 0, 0, 0, 0,
3002 ];
3003
3004 let drop_guard = crate::DropGuard::from_option(drop_callback);
3005
3006 let empty_descriptor_set_layout = unsafe {
3007 raw_device
3008 .create_descriptor_set_layout(&vk::DescriptorSetLayoutCreateInfo::default(), None)
3009 .map_err(super::map_host_device_oom_err)?
3010 };
3011
3012 let shared = Arc::new(super::DeviceShared {
3013 raw: raw_device,
3014 family_index,
3015 queue_flags,
3016 queue_index,
3017 raw_queue,
3018 drop_guard,
3019 instance: Arc::clone(&self.instance),
3020 physical_device: self.raw,
3021 enabled_extensions: enabled_extensions.into(),
3022 extension_fns: super::DeviceExtensionFunctions {
3023 debug_utils: debug_utils_fn,
3024 draw_indirect_count: indirect_count_fn,
3025 timeline_semaphore: timeline_semaphore_fn,
3026 ray_tracing: ray_tracing_fns,
3027 ray_tracing_pipelines: ray_tracing_pipeline_fns,
3028 mesh_shading: mesh_shading_fns,
3029 external_memory_fd: external_memory_fd_fn,
3030 },
3031 pipeline_cache_validation_key,
3032 vendor_id: self.phd_capabilities.properties.vendor_id,
3033 timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
3034 private_caps: self.private_caps.clone(),
3035 features,
3036 workarounds: self.workarounds,
3037 render_passes: Mutex::new(Default::default()),
3038 sampler_cache: Mutex::new(super::sampler::SamplerCache::new(
3039 self.private_caps.maximum_samplers,
3040 )),
3041 memory_allocations_counter: Default::default(),
3042
3043 texture_identity_factory: super::ResourceIdentityFactory::new(),
3044 texture_view_identity_factory: super::ResourceIdentityFactory::new(),
3045 empty_descriptor_set_layout,
3046 });
3047
3048 let relay_semaphores = super::RelaySemaphores::new(&shared)?;
3049
3050 let queue = super::Queue {
3051 raw: raw_queue,
3052 device: Arc::clone(&shared),
3053 family_index,
3054 relay_semaphores: Mutex::new(relay_semaphores),
3055 signal_semaphores: Mutex::new(SemaphoreList::new(SemaphoreListMode::Signal)),
3056 wait_semaphores: Mutex::new(SemaphoreList::new(SemaphoreListMode::Wait)),
3057 next_submit_chain: Mutex::new(None),
3058 };
3059
3060 let allocation_sizes = AllocationSizes::from_memory_hints(memory_hints).into();
3061
3062 let buffer_device_address = enabled_extensions.contains(&khr::buffer_device_address::NAME);
3063
3064 let mem_allocator =
3065 gpu_allocator::vulkan::Allocator::new(&gpu_allocator::vulkan::AllocatorCreateDesc {
3066 instance: self.instance.raw.clone(),
3067 device: shared.raw.clone(),
3068 physical_device: self.raw,
3069 debug_settings: Default::default(),
3070 buffer_device_address,
3071 allocation_sizes,
3072 })?;
3073
3074 let desc_allocator = super::descriptor::DescriptorAllocator::new(
3075 if let Some(di) = self.phd_capabilities.descriptor_indexing {
3076 di.max_update_after_bind_descriptors_in_all_pools
3077 } else {
3078 0
3079 },
3080 );
3081
3082 let device = super::Device {
3083 shared,
3084 mem_allocator: Mutex::new(mem_allocator),
3085 desc_allocator: Mutex::new(desc_allocator),
3086 valid_ash_memory_types,
3087 naga_options,
3088 #[cfg(feature = "renderdoc")]
3089 render_doc: Default::default(),
3090 counters: Default::default(),
3091 };
3092
3093 Ok(crate::OpenDevice { device, queue })
3094 }
3095
3096 pub fn texture_format_as_raw(&self, texture_format: wgt::TextureFormat) -> vk::Format {
3097 self.private_caps.map_texture_format(texture_format)
3098 }
3099
3100 pub unsafe fn open_with_callback<'a>(
3105 &self,
3106 features: wgt::Features,
3107 limits: &wgt::Limits,
3108 memory_hints: &wgt::MemoryHints,
3109 callback: Option<Box<super::CreateDeviceCallback<'a>>>,
3110 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
3111 let mut enabled_extensions = self.required_device_extensions(features);
3112 let mut enabled_phd_features = self.physical_device_features(&enabled_extensions, features);
3113
3114 let default_family_index = 0;
3115 let mut family_infos = vec![vk::DeviceQueueCreateInfo::default()
3116 .queue_family_index(default_family_index)
3117 .queue_priorities(&[1.0])];
3118
3119 let mut pre_info = vk::DeviceCreateInfo::default();
3120
3121 if let Some(callback) = callback {
3122 callback(super::CreateDeviceCallbackArgs {
3123 extensions: &mut enabled_extensions,
3124 device_features: &mut enabled_phd_features,
3125 queue_create_infos: &mut family_infos,
3126 create_info: &mut pre_info,
3127 _phantom: PhantomData,
3128 })
3129 }
3130
3131 let str_pointers = enabled_extensions
3132 .iter()
3133 .map(|&s| {
3134 s.as_ptr()
3136 })
3137 .collect::<Vec<_>>();
3138
3139 let pre_info = pre_info
3140 .queue_create_infos(&family_infos)
3141 .enabled_extension_names(&str_pointers);
3142 let info = enabled_phd_features.add_to_device_create(pre_info);
3143 let raw_device = {
3144 profiling::scope!("vkCreateDevice");
3145 unsafe {
3146 self.instance
3147 .raw
3148 .create_device(self.raw, &info, None)
3149 .map_err(map_err)?
3150 }
3151 };
3152 fn map_err(err: vk::Result) -> crate::DeviceError {
3153 match err {
3154 vk::Result::ERROR_TOO_MANY_OBJECTS => crate::DeviceError::OutOfMemory,
3155 vk::Result::ERROR_INITIALIZATION_FAILED => crate::DeviceError::Lost,
3156 vk::Result::ERROR_EXTENSION_NOT_PRESENT | vk::Result::ERROR_FEATURE_NOT_PRESENT => {
3157 crate::hal_usage_error(err)
3158 }
3159 other => super::map_host_device_oom_and_lost_err(other),
3160 }
3161 }
3162
3163 unsafe {
3164 self.device_from_raw(
3165 raw_device,
3166 None,
3167 &enabled_extensions,
3168 features,
3169 limits,
3170 memory_hints,
3171 family_infos[0].queue_family_index,
3172 0,
3173 )
3174 }
3175 }
3176}
3177
3178impl crate::Adapter for super::Adapter {
3179 type A = super::Api;
3180
3181 unsafe fn open(
3182 &self,
3183 features: wgt::Features,
3184 limits: &wgt::Limits,
3185 memory_hints: &wgt::MemoryHints,
3186 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
3187 unsafe { self.open_with_callback(features, limits, memory_hints, None) }
3188 }
3189
3190 unsafe fn texture_format_capabilities(
3191 &self,
3192 format: wgt::TextureFormat,
3193 ) -> crate::TextureFormatCapabilities {
3194 use crate::TextureFormatCapabilities as Tfc;
3195
3196 let vk_format = self.private_caps.map_texture_format(format);
3197 let properties = unsafe {
3198 self.instance
3199 .raw
3200 .get_physical_device_format_properties(self.raw, vk_format)
3201 };
3202 let features = properties.optimal_tiling_features;
3203
3204 let mut flags = Tfc::empty();
3205 flags.set(
3206 Tfc::SAMPLED,
3207 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE),
3208 );
3209 flags.set(
3210 Tfc::SAMPLED_LINEAR,
3211 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR),
3212 );
3213 flags.set(
3218 Tfc::STORAGE_READ_WRITE
3219 | Tfc::STORAGE_WRITE_ONLY
3220 | Tfc::STORAGE_READ_ONLY
3221 | Tfc::STORAGE_ATOMIC,
3222 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE),
3223 );
3224 flags.set(
3225 Tfc::STORAGE_ATOMIC,
3226 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC),
3227 );
3228 flags.set(
3229 Tfc::COLOR_ATTACHMENT,
3230 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT),
3231 );
3232 flags.set(
3233 Tfc::COLOR_ATTACHMENT_BLEND,
3234 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND),
3235 );
3236 flags.set(
3237 Tfc::DEPTH_STENCIL_ATTACHMENT,
3238 features.contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT),
3239 );
3240 flags.set(
3241 Tfc::COPY_SRC,
3242 features.intersects(vk::FormatFeatureFlags::TRANSFER_SRC),
3243 );
3244 flags.set(
3245 Tfc::COPY_DST,
3246 features.intersects(vk::FormatFeatureFlags::TRANSFER_DST),
3247 );
3248 flags.set(
3249 Tfc::STORAGE_ATOMIC,
3250 features.intersects(vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC),
3251 );
3252 flags.set(Tfc::MULTISAMPLE_RESOLVE, !format.is_compressed());
3254
3255 let format_aspect = crate::FormatAspects::from(format);
3257 let limits = self.phd_capabilities.properties.limits;
3258
3259 let sample_flags = if format_aspect.contains(crate::FormatAspects::DEPTH) {
3260 limits
3261 .framebuffer_depth_sample_counts
3262 .min(limits.sampled_image_depth_sample_counts)
3263 } else if format_aspect.contains(crate::FormatAspects::STENCIL) {
3264 limits
3265 .framebuffer_stencil_sample_counts
3266 .min(limits.sampled_image_stencil_sample_counts)
3267 } else {
3268 let first_aspect = format_aspect
3269 .iter()
3270 .next()
3271 .expect("All texture should at least one aspect")
3272 .map();
3273
3274 assert_ne!(first_aspect, wgt::TextureAspect::DepthOnly);
3276 assert_ne!(first_aspect, wgt::TextureAspect::StencilOnly);
3277
3278 match format.sample_type(Some(first_aspect), None).unwrap() {
3279 wgt::TextureSampleType::Float { .. } => limits
3280 .framebuffer_color_sample_counts
3281 .min(limits.sampled_image_color_sample_counts),
3282 wgt::TextureSampleType::Sint | wgt::TextureSampleType::Uint => {
3283 limits.sampled_image_integer_sample_counts
3284 }
3285 _ => unreachable!(),
3286 }
3287 };
3288
3289 flags.set(
3290 Tfc::MULTISAMPLE_X2,
3291 sample_flags.contains(vk::SampleCountFlags::TYPE_2),
3292 );
3293 flags.set(
3294 Tfc::MULTISAMPLE_X4,
3295 sample_flags.contains(vk::SampleCountFlags::TYPE_4),
3296 );
3297 flags.set(
3298 Tfc::MULTISAMPLE_X8,
3299 sample_flags.contains(vk::SampleCountFlags::TYPE_8),
3300 );
3301 flags.set(
3302 Tfc::MULTISAMPLE_X16,
3303 sample_flags.contains(vk::SampleCountFlags::TYPE_16),
3304 );
3305
3306 flags
3307 }
3308
3309 unsafe fn surface_capabilities(
3310 &self,
3311 surface: &super::Surface,
3312 ) -> Option<crate::SurfaceCapabilities> {
3313 surface.inner.surface_capabilities(self)
3314 }
3315
3316 unsafe fn surface_display_hdr_info(
3317 &self,
3318 surface: &super::Surface,
3319 ) -> Option<wgt::DisplayHdrInfo> {
3320 surface.inner.display_hdr_info()
3323 }
3324
3325 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
3326 #[cfg(unix)]
3331 {
3332 let mut timespec = libc::timespec::default();
3333 unsafe {
3334 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut timespec);
3335 }
3336
3337 wgt::PresentationTimestamp(
3338 timespec.tv_sec as u128 * 1_000_000_000 + timespec.tv_nsec as u128,
3339 )
3340 }
3341 #[cfg(not(unix))]
3342 {
3343 wgt::PresentationTimestamp::INVALID_TIMESTAMP
3344 }
3345 }
3346
3347 fn get_ordered_buffer_usages(&self) -> wgt::BufferUses {
3348 wgt::BufferUses::INCLUSIVE | wgt::BufferUses::MAP_WRITE
3349 }
3350
3351 fn get_ordered_texture_usages(&self) -> wgt::TextureUses {
3356 wgt::TextureUses::INCLUSIVE
3357 }
3358}
3359
3360fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
3361 [
3362 vk::Format::R16_UNORM,
3363 vk::Format::R16_SNORM,
3364 vk::Format::R16G16_UNORM,
3365 vk::Format::R16G16_SNORM,
3366 vk::Format::R16G16B16A16_UNORM,
3367 vk::Format::R16G16B16A16_SNORM,
3368 ]
3369 .into_iter()
3370 .all(|format| {
3371 supports_format(
3372 instance,
3373 phd,
3374 format,
3375 vk::ImageTiling::OPTIMAL,
3376 vk::FormatFeatureFlags::SAMPLED_IMAGE
3377 | vk::FormatFeatureFlags::STORAGE_IMAGE
3378 | vk::FormatFeatureFlags::TRANSFER_SRC
3379 | vk::FormatFeatureFlags::TRANSFER_DST,
3380 )
3381 })
3382}
3383
3384fn is_float32_filterable_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
3385 [
3386 vk::Format::R32_SFLOAT,
3387 vk::Format::R32G32_SFLOAT,
3388 vk::Format::R32G32B32A32_SFLOAT,
3389 ]
3390 .into_iter()
3391 .all(|format| {
3392 supports_format(
3393 instance,
3394 phd,
3395 format,
3396 vk::ImageTiling::OPTIMAL,
3397 vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR,
3398 )
3399 })
3400}
3401
3402fn is_float32_blendable_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
3403 [
3404 vk::Format::R32_SFLOAT,
3405 vk::Format::R32G32_SFLOAT,
3406 vk::Format::R32G32B32A32_SFLOAT,
3407 ]
3408 .into_iter()
3409 .all(|format| {
3410 supports_format(
3411 instance,
3412 phd,
3413 format,
3414 vk::ImageTiling::OPTIMAL,
3415 vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND,
3416 )
3417 })
3418}
3419
3420fn supports_format(
3421 instance: &ash::Instance,
3422 phd: vk::PhysicalDevice,
3423 format: vk::Format,
3424 tiling: vk::ImageTiling,
3425 features: vk::FormatFeatureFlags,
3426) -> bool {
3427 let properties = unsafe { instance.get_physical_device_format_properties(phd, format) };
3428 match tiling {
3429 vk::ImageTiling::LINEAR => properties.linear_tiling_features.contains(features),
3430 vk::ImageTiling::OPTIMAL => properties.optimal_tiling_features.contains(features),
3431 _ => false,
3432 }
3433}
3434
3435fn supports_astc_3d(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
3436 [
3437 vk::Format::ASTC_4X4_UNORM_BLOCK,
3438 vk::Format::ASTC_4X4_SRGB_BLOCK,
3439 vk::Format::ASTC_5X4_UNORM_BLOCK,
3440 vk::Format::ASTC_5X4_SRGB_BLOCK,
3441 vk::Format::ASTC_5X5_UNORM_BLOCK,
3442 vk::Format::ASTC_5X5_SRGB_BLOCK,
3443 vk::Format::ASTC_6X5_UNORM_BLOCK,
3444 vk::Format::ASTC_6X5_SRGB_BLOCK,
3445 vk::Format::ASTC_6X6_UNORM_BLOCK,
3446 vk::Format::ASTC_6X6_SRGB_BLOCK,
3447 vk::Format::ASTC_8X5_UNORM_BLOCK,
3448 vk::Format::ASTC_8X5_SRGB_BLOCK,
3449 vk::Format::ASTC_8X6_UNORM_BLOCK,
3450 vk::Format::ASTC_8X6_SRGB_BLOCK,
3451 vk::Format::ASTC_8X8_UNORM_BLOCK,
3452 vk::Format::ASTC_8X8_SRGB_BLOCK,
3453 vk::Format::ASTC_10X5_UNORM_BLOCK,
3454 vk::Format::ASTC_10X5_SRGB_BLOCK,
3455 vk::Format::ASTC_10X6_UNORM_BLOCK,
3456 vk::Format::ASTC_10X6_SRGB_BLOCK,
3457 vk::Format::ASTC_10X8_UNORM_BLOCK,
3458 vk::Format::ASTC_10X8_SRGB_BLOCK,
3459 vk::Format::ASTC_10X10_UNORM_BLOCK,
3460 vk::Format::ASTC_10X10_SRGB_BLOCK,
3461 vk::Format::ASTC_12X10_UNORM_BLOCK,
3462 vk::Format::ASTC_12X10_SRGB_BLOCK,
3463 vk::Format::ASTC_12X12_UNORM_BLOCK,
3464 vk::Format::ASTC_12X12_SRGB_BLOCK,
3465 ]
3466 .into_iter()
3467 .all(|format| {
3468 unsafe {
3469 instance.get_physical_device_image_format_properties(
3470 phd,
3471 format,
3472 vk::ImageType::TYPE_3D,
3473 vk::ImageTiling::OPTIMAL,
3474 vk::ImageUsageFlags::SAMPLED,
3475 vk::ImageCreateFlags::empty(),
3476 )
3477 }
3478 .is_ok()
3479 })
3480}
3481
3482fn supports_bgra8unorm_storage(
3483 instance: &ash::Instance,
3484 phd: vk::PhysicalDevice,
3485 device_api_version: u32,
3486) -> bool {
3487 if device_api_version < vk::API_VERSION_1_3 {
3493 return false;
3494 }
3495
3496 unsafe {
3497 let mut properties3 = vk::FormatProperties3::default();
3498 let mut properties2 = vk::FormatProperties2::default().push_next(&mut properties3);
3499
3500 instance.get_physical_device_format_properties2(
3501 phd,
3502 vk::Format::B8G8R8A8_UNORM,
3503 &mut properties2,
3504 );
3505
3506 let features2 = properties2.format_properties.optimal_tiling_features;
3507 let features3 = properties3.optimal_tiling_features;
3508
3509 features2.contains(vk::FormatFeatureFlags::STORAGE_IMAGE)
3510 && features3.contains(vk::FormatFeatureFlags2::STORAGE_WRITE_WITHOUT_FORMAT)
3511 }
3512}
3513
3514fn is_intel_igpu_outdated_for_robustness2(capabilities: &PhysicalDeviceProperties) -> bool {
3518 const DRIVER_VERSION_WORKING: u32 = (101 << 14) | 2115; let props = &capabilities.properties;
3521
3522 let is_outdated = props.vendor_id == crate::auxil::db::intel::VENDOR
3523 && props.device_type == vk::PhysicalDeviceType::INTEGRATED_GPU
3524 && props.driver_version < DRIVER_VERSION_WORKING
3525 && capabilities.is_driver(vk::DriverId::INTEL_PROPRIETARY_WINDOWS);
3526
3527 if is_outdated {
3528 log::debug!(
3529 "Disabling robustBufferAccess2 and robustImageAccess2: IntegratedGpu Intel Driver is outdated. Found with version 0x{:X}, less than the known good version 0x{:X} (31.0.101.2115)",
3530 props.driver_version,
3531 DRIVER_VERSION_WORKING
3532 );
3533 }
3534 is_outdated
3535}
3536
3537fn map_vk_component_type(ty: vk::ComponentTypeKHR) -> Option<wgt::CooperativeScalarType> {
3539 match ty {
3540 vk::ComponentTypeKHR::FLOAT16 => Some(wgt::CooperativeScalarType::F16),
3541 vk::ComponentTypeKHR::FLOAT32 => Some(wgt::CooperativeScalarType::F32),
3542 vk::ComponentTypeKHR::SINT32 => Some(wgt::CooperativeScalarType::I32),
3543 vk::ComponentTypeKHR::UINT32 => Some(wgt::CooperativeScalarType::U32),
3544 _ => None,
3545 }
3546}
3547
3548fn map_vk_cooperative_size(size: u32) -> Option<u32> {
3550 match size {
3551 8 | 16 => Some(size),
3552 _ => None,
3553 }
3554}
3555
3556fn query_cooperative_matrix_properties(
3558 coop_matrix: &khr::cooperative_matrix::Instance,
3559 phd: vk::PhysicalDevice,
3560) -> Vec<wgt::CooperativeMatrixProperties> {
3561 let vk_properties =
3562 match unsafe { coop_matrix.get_physical_device_cooperative_matrix_properties(phd) } {
3563 Ok(props) => props,
3564 Err(e) => {
3565 log::warn!("Failed to query cooperative matrix properties: {e:?}");
3566 return Vec::new();
3567 }
3568 };
3569
3570 log::debug!(
3571 "Vulkan reports {} cooperative matrix configurations",
3572 vk_properties.len()
3573 );
3574
3575 let mut result = Vec::new();
3576 for prop in &vk_properties {
3577 log::debug!(
3578 " Vulkan coop matrix: M={} N={} K={} A={:?} B={:?} C={:?} Result={:?} scope={:?} saturating={}",
3579 prop.m_size,
3580 prop.n_size,
3581 prop.k_size,
3582 prop.a_type,
3583 prop.b_type,
3584 prop.c_type,
3585 prop.result_type,
3586 prop.scope,
3587 prop.saturating_accumulation
3588 );
3589
3590 if prop.scope != vk::ScopeKHR::SUBGROUP {
3592 log::debug!(" Skipped: scope is not SUBGROUP");
3593 continue;
3594 }
3595
3596 let m_size = match map_vk_cooperative_size(prop.m_size) {
3598 Some(s) => s,
3599 None => {
3600 log::debug!(" Skipped: M size {} not supported", prop.m_size);
3601 continue;
3602 }
3603 };
3604 let n_size = match map_vk_cooperative_size(prop.n_size) {
3605 Some(s) => s,
3606 None => {
3607 log::debug!(" Skipped: N size {} not supported", prop.n_size);
3608 continue;
3609 }
3610 };
3611 let k_size = match map_vk_cooperative_size(prop.k_size) {
3612 Some(s) => s,
3613 None => {
3614 log::debug!(" Skipped: K size {} not supported", prop.k_size);
3615 continue;
3616 }
3617 };
3618
3619 let ab_type = match map_vk_component_type(prop.a_type) {
3621 Some(t) if Some(t) == map_vk_component_type(prop.b_type) => t,
3622 _ => {
3623 log::debug!(
3624 " Skipped: A/B types {:?}/{:?} not supported or don't match",
3625 prop.a_type,
3626 prop.b_type
3627 );
3628 continue;
3629 }
3630 };
3631 let cr_type = match map_vk_component_type(prop.c_type) {
3632 Some(t) if Some(t) == map_vk_component_type(prop.result_type) => t,
3633 _ => {
3634 log::debug!(
3635 " Skipped: C/Result types {:?}/{:?} not supported or don't match",
3636 prop.c_type,
3637 prop.result_type
3638 );
3639 continue;
3640 }
3641 };
3642
3643 log::debug!(" Accepted!");
3644 result.push(wgt::CooperativeMatrixProperties {
3645 m_size,
3646 n_size,
3647 k_size,
3648 ab_type,
3649 cr_type,
3650 saturating_accumulation: prop.saturating_accumulation != 0,
3651 });
3652 }
3653
3654 log::debug!(
3655 "Found {} cooperative matrix configurations supported by wgpu",
3656 result.len()
3657 );
3658 result
3659}