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