1use super::conv;
2
3use ash::{extensions::khr, vk};
4use parking_lot::Mutex;
5
6use std::{collections::BTreeMap, ffi::CStr, sync::Arc};
7
8fn depth_stencil_required_flags() -> vk::FormatFeatureFlags {
9 vk::FormatFeatureFlags::SAMPLED_IMAGE | vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT
10}
11
12fn indexing_features() -> wgt::Features {
14 wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
15 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
16 | wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY
17}
18
19#[derive(Debug, Default)]
37pub struct PhysicalDeviceFeatures {
38 core: vk::PhysicalDeviceFeatures,
40
41 pub(super) descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
43
44 imageless_framebuffer: Option<vk::PhysicalDeviceImagelessFramebufferFeaturesKHR>,
46
47 timeline_semaphore: Option<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>,
49
50 image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
52
53 robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT>,
55
56 multiview: Option<vk::PhysicalDeviceMultiviewFeaturesKHR>,
58
59 sampler_ycbcr_conversion: Option<vk::PhysicalDeviceSamplerYcbcrConversionFeatures>,
61
62 astc_hdr: Option<vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT>,
64
65 shader_float16: Option<(
69 vk::PhysicalDeviceShaderFloat16Int8Features,
70 vk::PhysicalDevice16BitStorageFeatures,
71 )>,
72
73 acceleration_structure: Option<vk::PhysicalDeviceAccelerationStructureFeaturesKHR>,
75
76 buffer_device_address: Option<vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR>,
91
92 ray_query: Option<vk::PhysicalDeviceRayQueryFeaturesKHR>,
102
103 zero_initialize_workgroup_memory:
106 Option<vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures>,
107
108 subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlFeatures>,
110}
111
112unsafe impl Send for PhysicalDeviceFeatures {}
114unsafe impl Sync for PhysicalDeviceFeatures {}
115
116impl PhysicalDeviceFeatures {
117 pub fn add_to_device_create_builder<'a>(
119 &'a mut self,
120 mut info: vk::DeviceCreateInfoBuilder<'a>,
121 ) -> vk::DeviceCreateInfoBuilder<'a> {
122 info = info.enabled_features(&self.core);
123 if let Some(ref mut feature) = self.descriptor_indexing {
124 info = info.push_next(feature);
125 }
126 if let Some(ref mut feature) = self.imageless_framebuffer {
127 info = info.push_next(feature);
128 }
129 if let Some(ref mut feature) = self.timeline_semaphore {
130 info = info.push_next(feature);
131 }
132 if let Some(ref mut feature) = self.image_robustness {
133 info = info.push_next(feature);
134 }
135 if let Some(ref mut feature) = self.robustness2 {
136 info = info.push_next(feature);
137 }
138 if let Some(ref mut feature) = self.astc_hdr {
139 info = info.push_next(feature);
140 }
141 if let Some((ref mut f16_i8_feature, ref mut _16bit_feature)) = self.shader_float16 {
142 info = info.push_next(f16_i8_feature);
143 info = info.push_next(_16bit_feature);
144 }
145 if let Some(ref mut feature) = self.zero_initialize_workgroup_memory {
146 info = info.push_next(feature);
147 }
148 if let Some(ref mut feature) = self.acceleration_structure {
149 info = info.push_next(feature);
150 }
151 if let Some(ref mut feature) = self.buffer_device_address {
152 info = info.push_next(feature);
153 }
154 if let Some(ref mut feature) = self.ray_query {
155 info = info.push_next(feature);
156 }
157 if let Some(ref mut feature) = self.subgroup_size_control {
158 info = info.push_next(feature);
159 }
160 info
161 }
162
163 fn from_extensions_and_requested_features(
191 device_api_version: u32,
192 enabled_extensions: &[&'static CStr],
193 requested_features: wgt::Features,
194 downlevel_flags: wgt::DownlevelFlags,
195 private_caps: &super::PrivateCapabilities,
196 ) -> Self {
197 let needs_sampled_image_non_uniform = requested_features.contains(
198 wgt::Features::TEXTURE_BINDING_ARRAY
199 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
200 );
201 let needs_storage_buffer_non_uniform = requested_features.contains(
202 wgt::Features::BUFFER_BINDING_ARRAY
203 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
204 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
205 );
206 let needs_uniform_buffer_non_uniform = requested_features.contains(
207 wgt::Features::TEXTURE_BINDING_ARRAY
208 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
209 );
210 let needs_storage_image_non_uniform = requested_features.contains(
211 wgt::Features::TEXTURE_BINDING_ARRAY
212 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
213 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
214 );
215 let needs_partially_bound =
216 requested_features.intersects(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
217
218 Self {
219 core: vk::PhysicalDeviceFeatures::builder()
222 .robust_buffer_access(private_caps.robust_buffer_access)
223 .independent_blend(downlevel_flags.contains(wgt::DownlevelFlags::INDEPENDENT_BLEND))
224 .sample_rate_shading(
225 downlevel_flags.contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING),
226 )
227 .image_cube_array(
228 downlevel_flags.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES),
229 )
230 .draw_indirect_first_instance(
231 requested_features.contains(wgt::Features::INDIRECT_FIRST_INSTANCE),
232 )
233 .multi_draw_indirect(
235 requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT),
236 )
237 .fill_mode_non_solid(requested_features.intersects(
238 wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT,
239 ))
240 .sampler_anisotropy(
244 downlevel_flags.contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING),
245 )
246 .texture_compression_etc2(
247 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ETC2),
248 )
249 .texture_compression_astc_ldr(
250 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC),
251 )
252 .texture_compression_bc(
253 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_BC),
254 )
255 .pipeline_statistics_query(
257 requested_features.contains(wgt::Features::PIPELINE_STATISTICS_QUERY),
258 )
259 .vertex_pipeline_stores_and_atomics(
260 requested_features.contains(wgt::Features::VERTEX_WRITABLE_STORAGE),
261 )
262 .fragment_stores_and_atomics(
263 downlevel_flags.contains(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE),
264 )
265 .shader_uniform_buffer_array_dynamic_indexing(
268 requested_features.contains(wgt::Features::BUFFER_BINDING_ARRAY),
269 )
270 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
271 wgt::Features::BUFFER_BINDING_ARRAY
272 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
273 ))
274 .shader_sampled_image_array_dynamic_indexing(
275 requested_features.contains(wgt::Features::TEXTURE_BINDING_ARRAY),
276 )
277 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
278 wgt::Features::TEXTURE_BINDING_ARRAY
279 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
280 ))
281 .shader_float64(requested_features.contains(wgt::Features::SHADER_F64))
285 .shader_int64(requested_features.contains(wgt::Features::SHADER_INT64))
286 .shader_int16(requested_features.contains(wgt::Features::SHADER_I16))
287 .geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX))
289 .depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL))
290 .dual_src_blend(requested_features.contains(wgt::Features::DUAL_SOURCE_BLENDING))
291 .build(),
292 descriptor_indexing: if requested_features.intersects(indexing_features()) {
293 Some(
294 vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::builder()
295 .shader_sampled_image_array_non_uniform_indexing(
296 needs_sampled_image_non_uniform,
297 )
298 .shader_storage_image_array_non_uniform_indexing(
299 needs_storage_image_non_uniform,
300 )
301 .shader_uniform_buffer_array_non_uniform_indexing(
302 needs_uniform_buffer_non_uniform,
303 )
304 .shader_storage_buffer_array_non_uniform_indexing(
305 needs_storage_buffer_non_uniform,
306 )
307 .descriptor_binding_partially_bound(needs_partially_bound)
308 .build(),
309 )
310 } else {
311 None
312 },
313 imageless_framebuffer: if device_api_version >= vk::API_VERSION_1_2
314 || enabled_extensions.contains(&vk::KhrImagelessFramebufferFn::name())
315 {
316 Some(
317 vk::PhysicalDeviceImagelessFramebufferFeaturesKHR::builder()
318 .imageless_framebuffer(private_caps.imageless_framebuffers)
319 .build(),
320 )
321 } else {
322 None
323 },
324 timeline_semaphore: if device_api_version >= vk::API_VERSION_1_2
325 || enabled_extensions.contains(&vk::KhrTimelineSemaphoreFn::name())
326 {
327 Some(
328 vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::builder()
329 .timeline_semaphore(private_caps.timeline_semaphores)
330 .build(),
331 )
332 } else {
333 None
334 },
335 image_robustness: if device_api_version >= vk::API_VERSION_1_3
336 || enabled_extensions.contains(&vk::ExtImageRobustnessFn::name())
337 {
338 Some(
339 vk::PhysicalDeviceImageRobustnessFeaturesEXT::builder()
340 .robust_image_access(private_caps.robust_image_access)
341 .build(),
342 )
343 } else {
344 None
345 },
346 robustness2: if enabled_extensions.contains(&vk::ExtRobustness2Fn::name()) {
347 Some(
351 vk::PhysicalDeviceRobustness2FeaturesEXT::builder()
352 .robust_buffer_access2(private_caps.robust_buffer_access2)
353 .robust_image_access2(private_caps.robust_image_access2)
354 .build(),
355 )
356 } else {
357 None
358 },
359 multiview: if device_api_version >= vk::API_VERSION_1_1
360 || enabled_extensions.contains(&vk::KhrMultiviewFn::name())
361 {
362 Some(
363 vk::PhysicalDeviceMultiviewFeatures::builder()
364 .multiview(requested_features.contains(wgt::Features::MULTIVIEW))
365 .build(),
366 )
367 } else {
368 None
369 },
370 sampler_ycbcr_conversion: if device_api_version >= vk::API_VERSION_1_1
371 || enabled_extensions.contains(&vk::KhrSamplerYcbcrConversionFn::name())
372 {
373 Some(
374 vk::PhysicalDeviceSamplerYcbcrConversionFeatures::builder()
375 .build(),
377 )
378 } else {
379 None
380 },
381 astc_hdr: if enabled_extensions.contains(&vk::ExtTextureCompressionAstcHdrFn::name()) {
382 Some(
383 vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::builder()
384 .texture_compression_astc_hdr(true)
385 .build(),
386 )
387 } else {
388 None
389 },
390 shader_float16: if requested_features.contains(wgt::Features::SHADER_F16) {
391 Some((
392 vk::PhysicalDeviceShaderFloat16Int8Features::builder()
393 .shader_float16(true)
394 .build(),
395 vk::PhysicalDevice16BitStorageFeatures::builder()
396 .storage_buffer16_bit_access(true)
397 .uniform_and_storage_buffer16_bit_access(true)
398 .build(),
399 ))
400 } else {
401 None
402 },
403 acceleration_structure: if enabled_extensions
404 .contains(&vk::KhrAccelerationStructureFn::name())
405 {
406 Some(
407 vk::PhysicalDeviceAccelerationStructureFeaturesKHR::builder()
408 .acceleration_structure(true)
409 .build(),
410 )
411 } else {
412 None
413 },
414 buffer_device_address: if enabled_extensions
415 .contains(&vk::KhrBufferDeviceAddressFn::name())
416 {
417 Some(
418 vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR::builder()
419 .buffer_device_address(true)
420 .build(),
421 )
422 } else {
423 None
424 },
425 ray_query: if enabled_extensions.contains(&vk::KhrRayQueryFn::name()) {
426 Some(
427 vk::PhysicalDeviceRayQueryFeaturesKHR::builder()
428 .ray_query(true)
429 .build(),
430 )
431 } else {
432 None
433 },
434 zero_initialize_workgroup_memory: if device_api_version >= vk::API_VERSION_1_3
435 || enabled_extensions.contains(&vk::KhrZeroInitializeWorkgroupMemoryFn::name())
436 {
437 Some(
438 vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::builder()
439 .shader_zero_initialize_workgroup_memory(
440 private_caps.zero_initialize_workgroup_memory,
441 )
442 .build(),
443 )
444 } else {
445 None
446 },
447 subgroup_size_control: if device_api_version >= vk::API_VERSION_1_3
448 || enabled_extensions.contains(&vk::ExtSubgroupSizeControlFn::name())
449 {
450 Some(
451 vk::PhysicalDeviceSubgroupSizeControlFeatures::builder()
452 .subgroup_size_control(true)
453 .build(),
454 )
455 } else {
456 None
457 },
458 }
459 }
460
461 fn to_wgpu(
470 &self,
471 instance: &ash::Instance,
472 phd: vk::PhysicalDevice,
473 caps: &PhysicalDeviceProperties,
474 ) -> (wgt::Features, wgt::DownlevelFlags) {
475 use crate::auxil::db;
476 use wgt::{DownlevelFlags as Df, Features as F};
477 let mut features = F::empty()
478 | F::SPIRV_SHADER_PASSTHROUGH
479 | F::MAPPABLE_PRIMARY_BUFFERS
480 | F::PUSH_CONSTANTS
481 | F::ADDRESS_MODE_CLAMP_TO_BORDER
482 | F::ADDRESS_MODE_CLAMP_TO_ZERO
483 | F::TIMESTAMP_QUERY
484 | F::TIMESTAMP_QUERY_INSIDE_ENCODERS
485 | F::TIMESTAMP_QUERY_INSIDE_PASSES
486 | F::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
487 | F::CLEAR_TEXTURE;
488
489 let mut dl_flags = Df::COMPUTE_SHADERS
490 | Df::BASE_VERTEX
491 | Df::READ_ONLY_DEPTH_STENCIL
492 | Df::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
493 | Df::COMPARISON_SAMPLERS
494 | Df::VERTEX_STORAGE
495 | Df::FRAGMENT_STORAGE
496 | Df::DEPTH_TEXTURE_AND_BUFFER_COPIES
497 | Df::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED
498 | Df::UNRESTRICTED_INDEX_BUFFER
499 | Df::INDIRECT_EXECUTION
500 | Df::VIEW_FORMATS
501 | Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES
502 | Df::NONBLOCKING_QUERY_RESOLVE
503 | Df::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW;
504
505 dl_flags.set(
506 Df::SURFACE_VIEW_FORMATS,
507 caps.supports_extension(vk::KhrSwapchainMutableFormatFn::name()),
508 );
509 dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0);
510 dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0);
511 dl_flags.set(
512 Df::FRAGMENT_WRITABLE_STORAGE,
513 self.core.fragment_stores_and_atomics != 0,
514 );
515 dl_flags.set(Df::MULTISAMPLED_SHADING, self.core.sample_rate_shading != 0);
516 dl_flags.set(Df::INDEPENDENT_BLEND, self.core.independent_blend != 0);
517 dl_flags.set(
518 Df::FULL_DRAW_INDEX_UINT32,
519 self.core.full_draw_index_uint32 != 0,
520 );
521 dl_flags.set(Df::DEPTH_BIAS_CLAMP, self.core.depth_bias_clamp != 0);
522
523 features.set(
524 F::INDIRECT_FIRST_INSTANCE,
525 self.core.draw_indirect_first_instance != 0,
526 );
527 features.set(F::MULTI_DRAW_INDIRECT, self.core.multi_draw_indirect != 0);
529 features.set(F::POLYGON_MODE_LINE, self.core.fill_mode_non_solid != 0);
530 features.set(F::POLYGON_MODE_POINT, self.core.fill_mode_non_solid != 0);
531 features.set(
535 F::TEXTURE_COMPRESSION_ETC2,
536 self.core.texture_compression_etc2 != 0,
537 );
538 features.set(
539 F::TEXTURE_COMPRESSION_ASTC,
540 self.core.texture_compression_astc_ldr != 0,
541 );
542 features.set(
543 F::TEXTURE_COMPRESSION_BC,
544 self.core.texture_compression_bc != 0,
545 );
546 features.set(
547 F::PIPELINE_STATISTICS_QUERY,
548 self.core.pipeline_statistics_query != 0,
549 );
550 features.set(
551 F::VERTEX_WRITABLE_STORAGE,
552 self.core.vertex_pipeline_stores_and_atomics != 0,
553 );
554 features.set(
557 F::BUFFER_BINDING_ARRAY,
558 self.core.shader_uniform_buffer_array_dynamic_indexing != 0,
559 );
560 features.set(
561 F::TEXTURE_BINDING_ARRAY,
562 self.core.shader_sampled_image_array_dynamic_indexing != 0,
563 );
564 features.set(F::SHADER_PRIMITIVE_INDEX, self.core.geometry_shader != 0);
565 if Self::all_features_supported(
566 &features,
567 &[
568 (
569 F::BUFFER_BINDING_ARRAY,
570 self.core.shader_storage_buffer_array_dynamic_indexing,
571 ),
572 (
573 F::TEXTURE_BINDING_ARRAY,
574 self.core.shader_storage_image_array_dynamic_indexing,
575 ),
576 ],
577 ) {
578 features.insert(F::STORAGE_RESOURCE_BINDING_ARRAY);
579 }
580 features.set(F::SHADER_F64, self.core.shader_float64 != 0);
584 features.set(F::SHADER_INT64, self.core.shader_int64 != 0);
585 features.set(F::SHADER_I16, self.core.shader_int16 != 0);
586
587 features.set(
590 F::MULTI_DRAW_INDIRECT_COUNT,
591 caps.supports_extension(vk::KhrDrawIndirectCountFn::name()),
592 );
593 features.set(
594 F::CONSERVATIVE_RASTERIZATION,
595 caps.supports_extension(vk::ExtConservativeRasterizationFn::name()),
596 );
597
598 let intel_windows = caps.properties.vendor_id == db::intel::VENDOR && cfg!(windows);
599
600 if let Some(ref descriptor_indexing) = self.descriptor_indexing {
601 const STORAGE: F = F::STORAGE_RESOURCE_BINDING_ARRAY;
602 if Self::all_features_supported(
603 &features,
604 &[
605 (
606 F::TEXTURE_BINDING_ARRAY,
607 descriptor_indexing.shader_sampled_image_array_non_uniform_indexing,
608 ),
609 (
610 F::BUFFER_BINDING_ARRAY | STORAGE,
611 descriptor_indexing.shader_storage_buffer_array_non_uniform_indexing,
612 ),
613 ],
614 ) {
615 features.insert(F::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING);
616 }
617 if Self::all_features_supported(
618 &features,
619 &[
620 (
621 F::BUFFER_BINDING_ARRAY,
622 descriptor_indexing.shader_uniform_buffer_array_non_uniform_indexing,
623 ),
624 (
625 F::TEXTURE_BINDING_ARRAY | STORAGE,
626 descriptor_indexing.shader_storage_image_array_non_uniform_indexing,
627 ),
628 ],
629 ) {
630 features.insert(F::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING);
631 }
632 if descriptor_indexing.descriptor_binding_partially_bound != 0 && !intel_windows {
633 features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
634 }
635 }
636
637 features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0);
638 features.set(F::DUAL_SOURCE_BLENDING, self.core.dual_src_blend != 0);
639
640 if let Some(ref multiview) = self.multiview {
641 features.set(F::MULTIVIEW, multiview.multiview != 0);
642 }
643
644 features.set(
645 F::TEXTURE_FORMAT_16BIT_NORM,
646 is_format_16bit_norm_supported(instance, phd),
647 );
648
649 if let Some(ref astc_hdr) = self.astc_hdr {
650 features.set(
651 F::TEXTURE_COMPRESSION_ASTC_HDR,
652 astc_hdr.texture_compression_astc_hdr != 0,
653 );
654 }
655
656 if let Some((ref f16_i8, ref bit16)) = self.shader_float16 {
657 features.set(
658 F::SHADER_F16,
659 f16_i8.shader_float16 != 0
660 && bit16.storage_buffer16_bit_access != 0
661 && bit16.uniform_and_storage_buffer16_bit_access != 0,
662 );
663 }
664
665 if let Some(ref subgroup) = caps.subgroup {
666 if (caps.device_api_version >= vk::API_VERSION_1_3
667 || caps.supports_extension(vk::ExtSubgroupSizeControlFn::name()))
668 && subgroup.supported_operations.contains(
669 vk::SubgroupFeatureFlags::BASIC
670 | vk::SubgroupFeatureFlags::VOTE
671 | vk::SubgroupFeatureFlags::ARITHMETIC
672 | vk::SubgroupFeatureFlags::BALLOT
673 | vk::SubgroupFeatureFlags::SHUFFLE
674 | vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE,
675 )
676 {
677 features.set(
678 F::SUBGROUP,
679 subgroup
680 .supported_stages
681 .contains(vk::ShaderStageFlags::COMPUTE | vk::ShaderStageFlags::FRAGMENT),
682 );
683 features.set(
684 F::SUBGROUP_VERTEX,
685 subgroup
686 .supported_stages
687 .contains(vk::ShaderStageFlags::VERTEX),
688 );
689 features.insert(F::SUBGROUP_BARRIER);
690 }
691 }
692
693 let supports_depth_format = |format| {
694 supports_format(
695 instance,
696 phd,
697 format,
698 vk::ImageTiling::OPTIMAL,
699 depth_stencil_required_flags(),
700 )
701 };
702
703 let texture_s8 = supports_depth_format(vk::Format::S8_UINT);
704 let texture_d32 = supports_depth_format(vk::Format::D32_SFLOAT);
705 let texture_d24_s8 = supports_depth_format(vk::Format::D24_UNORM_S8_UINT);
706 let texture_d32_s8 = supports_depth_format(vk::Format::D32_SFLOAT_S8_UINT);
707
708 let stencil8 = texture_s8 || texture_d24_s8;
709 let depth24_plus_stencil8 = texture_d24_s8 || texture_d32_s8;
710
711 dl_flags.set(
712 Df::WEBGPU_TEXTURE_FORMAT_SUPPORT,
713 stencil8 && depth24_plus_stencil8 && texture_d32,
714 );
715
716 features.set(F::DEPTH32FLOAT_STENCIL8, texture_d32_s8);
717
718 features.set(
719 F::RAY_TRACING_ACCELERATION_STRUCTURE,
720 caps.supports_extension(vk::KhrDeferredHostOperationsFn::name())
721 && caps.supports_extension(vk::KhrAccelerationStructureFn::name())
722 && caps.supports_extension(vk::KhrBufferDeviceAddressFn::name()),
723 );
724
725 features.set(
726 F::RAY_QUERY,
727 caps.supports_extension(vk::KhrRayQueryFn::name()),
728 );
729
730 let rg11b10ufloat_renderable = supports_format(
731 instance,
732 phd,
733 vk::Format::B10G11R11_UFLOAT_PACK32,
734 vk::ImageTiling::OPTIMAL,
735 vk::FormatFeatureFlags::COLOR_ATTACHMENT
736 | vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND,
737 );
738 features.set(F::RG11B10UFLOAT_RENDERABLE, rg11b10ufloat_renderable);
739 features.set(F::SHADER_UNUSED_VERTEX_OUTPUT, true);
740
741 features.set(
742 F::BGRA8UNORM_STORAGE,
743 supports_bgra8unorm_storage(instance, phd, caps.device_api_version),
744 );
745
746 features.set(
747 F::FLOAT32_FILTERABLE,
748 is_float32_filterable_supported(instance, phd),
749 );
750
751 if let Some(ref _sampler_ycbcr_conversion) = self.sampler_ycbcr_conversion {
752 features.set(
753 F::TEXTURE_FORMAT_NV12,
754 supports_format(
755 instance,
756 phd,
757 vk::Format::G8_B8R8_2PLANE_420_UNORM,
758 vk::ImageTiling::OPTIMAL,
759 vk::FormatFeatureFlags::SAMPLED_IMAGE
760 | vk::FormatFeatureFlags::TRANSFER_SRC
761 | vk::FormatFeatureFlags::TRANSFER_DST,
762 ) && !caps
763 .driver
764 .map(|driver| driver.driver_id == vk::DriverId::MOLTENVK)
765 .unwrap_or_default(),
766 );
767 }
768
769 (features, dl_flags)
770 }
771
772 fn all_features_supported(
773 features: &wgt::Features,
774 implications: &[(wgt::Features, vk::Bool32)],
775 ) -> bool {
776 implications
777 .iter()
778 .all(|&(flag, support)| !features.contains(flag) || support != 0)
779 }
780}
781
782#[derive(Default, Debug)]
803pub struct PhysicalDeviceProperties {
804 supported_extensions: Vec<vk::ExtensionProperties>,
807
808 properties: vk::PhysicalDeviceProperties,
811
812 maintenance_3: Option<vk::PhysicalDeviceMaintenance3Properties>,
815
816 descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingPropertiesEXT>,
819
820 acceleration_structure: Option<vk::PhysicalDeviceAccelerationStructurePropertiesKHR>,
823
824 driver: Option<vk::PhysicalDeviceDriverPropertiesKHR>,
827
828 subgroup: Option<vk::PhysicalDeviceSubgroupProperties>,
830
831 subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlProperties>,
834
835 device_api_version: u32,
841}
842
843unsafe impl Send for PhysicalDeviceProperties {}
845unsafe impl Sync for PhysicalDeviceProperties {}
846
847impl PhysicalDeviceProperties {
848 pub fn properties(&self) -> vk::PhysicalDeviceProperties {
849 self.properties
850 }
851
852 pub fn supports_extension(&self, extension: &CStr) -> bool {
853 use crate::auxil::cstr_from_bytes_until_nul;
854 self.supported_extensions
855 .iter()
856 .any(|ep| cstr_from_bytes_until_nul(&ep.extension_name) == Some(extension))
857 }
858
859 fn get_required_extensions(&self, requested_features: wgt::Features) -> Vec<&'static CStr> {
861 let mut extensions = Vec::new();
862
863 extensions.push(vk::KhrSwapchainFn::name());
868
869 if self.device_api_version < vk::API_VERSION_1_1 {
870 if self.supports_extension(vk::KhrMaintenance1Fn::name()) {
872 extensions.push(vk::KhrMaintenance1Fn::name());
873 } else {
874 extensions.push(vk::AmdNegativeViewportHeightFn::name());
876 }
877
878 if self.supports_extension(vk::KhrMaintenance2Fn::name()) {
880 extensions.push(vk::KhrMaintenance2Fn::name());
881 }
882
883 if self.supports_extension(vk::KhrMaintenance3Fn::name()) {
885 extensions.push(vk::KhrMaintenance3Fn::name());
886 }
887
888 extensions.push(vk::KhrStorageBufferStorageClassFn::name());
890
891 if requested_features.contains(wgt::Features::MULTIVIEW) {
893 extensions.push(vk::KhrMultiviewFn::name());
894 }
895
896 if requested_features.contains(wgt::Features::TEXTURE_FORMAT_NV12) {
898 extensions.push(vk::KhrSamplerYcbcrConversionFn::name());
899 }
900 }
901
902 if self.device_api_version < vk::API_VERSION_1_2 {
903 if self.supports_extension(vk::KhrImageFormatListFn::name()) {
905 extensions.push(vk::KhrImageFormatListFn::name());
906 }
907
908 if self.supports_extension(vk::KhrImagelessFramebufferFn::name()) {
910 extensions.push(vk::KhrImagelessFramebufferFn::name());
911 if self.device_api_version < vk::API_VERSION_1_1 {
913 extensions.push(vk::KhrMaintenance2Fn::name());
914 }
915 }
916
917 if self.supports_extension(vk::KhrDriverPropertiesFn::name()) {
919 extensions.push(vk::KhrDriverPropertiesFn::name());
920 }
921
922 if self.supports_extension(vk::KhrTimelineSemaphoreFn::name()) {
924 extensions.push(vk::KhrTimelineSemaphoreFn::name());
925 }
926
927 if requested_features.intersects(indexing_features()) {
929 extensions.push(vk::ExtDescriptorIndexingFn::name());
930 }
931
932 if requested_features.contains(wgt::Features::SHADER_F16) {
934 extensions.push(vk::KhrShaderFloat16Int8Fn::name());
935 if self.device_api_version < vk::API_VERSION_1_1 {
937 extensions.push(vk::Khr16bitStorageFn::name());
938 }
939 }
940
941 }
944
945 if self.device_api_version < vk::API_VERSION_1_3 {
946 if self.supports_extension(vk::ExtImageRobustnessFn::name()) {
948 extensions.push(vk::ExtImageRobustnessFn::name());
949 }
950
951 if requested_features.contains(wgt::Features::SUBGROUP) {
953 extensions.push(vk::ExtSubgroupSizeControlFn::name());
954 }
955 }
956
957 if self.supports_extension(vk::KhrSwapchainMutableFormatFn::name()) {
959 extensions.push(vk::KhrSwapchainMutableFormatFn::name());
960 }
961
962 if self.supports_extension(vk::ExtRobustness2Fn::name()) {
964 extensions.push(vk::ExtRobustness2Fn::name());
965 }
966
967 if requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT_COUNT) {
971 extensions.push(vk::KhrDrawIndirectCountFn::name());
972 }
973
974 if requested_features.contains(wgt::Features::RAY_TRACING_ACCELERATION_STRUCTURE) {
976 extensions.push(vk::KhrDeferredHostOperationsFn::name());
977 extensions.push(vk::KhrAccelerationStructureFn::name());
978 extensions.push(vk::KhrBufferDeviceAddressFn::name());
979 }
980
981 if requested_features.contains(wgt::Features::RAY_QUERY) {
983 extensions.push(vk::KhrRayQueryFn::name());
984 }
985
986 if requested_features.contains(wgt::Features::CONSERVATIVE_RASTERIZATION) {
988 extensions.push(vk::ExtConservativeRasterizationFn::name());
989 }
990
991 #[cfg(any(target_os = "macos", target_os = "ios"))]
993 extensions.push(vk::KhrPortabilitySubsetFn::name());
994
995 if requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR) {
997 extensions.push(vk::ExtTextureCompressionAstcHdrFn::name());
998 }
999
1000 extensions
1001 }
1002
1003 fn to_wgpu_limits(&self) -> wgt::Limits {
1004 let limits = &self.properties.limits;
1005
1006 let max_compute_workgroup_sizes = limits.max_compute_work_group_size;
1007 let max_compute_workgroups_per_dimension = limits.max_compute_work_group_count[0]
1008 .min(limits.max_compute_work_group_count[1])
1009 .min(limits.max_compute_work_group_count[2]);
1010
1011 let is_nvidia = self.properties.vendor_id == crate::auxil::db::nvidia::VENDOR;
1013 let max_buffer_size =
1014 if (cfg!(target_os = "linux") || cfg!(target_os = "android")) && !is_nvidia {
1015 i32::MAX as u64
1016 } else {
1017 u64::MAX
1018 };
1019
1020 let max_color_attachment_bytes_per_sample = 32;
1024
1025 wgt::Limits {
1026 max_texture_dimension_1d: limits.max_image_dimension1_d,
1027 max_texture_dimension_2d: limits.max_image_dimension2_d,
1028 max_texture_dimension_3d: limits.max_image_dimension3_d,
1029 max_texture_array_layers: limits.max_image_array_layers,
1030 max_bind_groups: limits
1031 .max_bound_descriptor_sets
1032 .min(crate::MAX_BIND_GROUPS as u32),
1033 max_bindings_per_bind_group: wgt::Limits::default().max_bindings_per_bind_group,
1034 max_dynamic_uniform_buffers_per_pipeline_layout: limits
1035 .max_descriptor_set_uniform_buffers_dynamic,
1036 max_dynamic_storage_buffers_per_pipeline_layout: limits
1037 .max_descriptor_set_storage_buffers_dynamic,
1038 max_sampled_textures_per_shader_stage: limits.max_per_stage_descriptor_sampled_images,
1039 max_samplers_per_shader_stage: limits.max_per_stage_descriptor_samplers,
1040 max_storage_buffers_per_shader_stage: limits.max_per_stage_descriptor_storage_buffers,
1041 max_storage_textures_per_shader_stage: limits.max_per_stage_descriptor_storage_images,
1042 max_uniform_buffers_per_shader_stage: limits.max_per_stage_descriptor_uniform_buffers,
1043 max_uniform_buffer_binding_size: limits
1044 .max_uniform_buffer_range
1045 .min(crate::auxil::MAX_I32_BINDING_SIZE),
1046 max_storage_buffer_binding_size: limits
1047 .max_storage_buffer_range
1048 .min(crate::auxil::MAX_I32_BINDING_SIZE),
1049 max_vertex_buffers: limits
1050 .max_vertex_input_bindings
1051 .min(crate::MAX_VERTEX_BUFFERS as u32),
1052 max_vertex_attributes: limits.max_vertex_input_attributes,
1053 max_vertex_buffer_array_stride: limits.max_vertex_input_binding_stride,
1054 min_subgroup_size: self
1055 .subgroup_size_control
1056 .map(|subgroup_size| subgroup_size.min_subgroup_size)
1057 .unwrap_or(0),
1058 max_subgroup_size: self
1059 .subgroup_size_control
1060 .map(|subgroup_size| subgroup_size.max_subgroup_size)
1061 .unwrap_or(0),
1062 max_push_constant_size: limits.max_push_constants_size,
1063 min_uniform_buffer_offset_alignment: limits.min_uniform_buffer_offset_alignment as u32,
1064 min_storage_buffer_offset_alignment: limits.min_storage_buffer_offset_alignment as u32,
1065 max_inter_stage_shader_components: limits
1066 .max_vertex_output_components
1067 .min(limits.max_fragment_input_components),
1068 max_color_attachments: limits
1069 .max_color_attachments
1070 .min(crate::MAX_COLOR_ATTACHMENTS as u32),
1071 max_color_attachment_bytes_per_sample,
1072 max_compute_workgroup_storage_size: limits.max_compute_shared_memory_size,
1073 max_compute_invocations_per_workgroup: limits.max_compute_work_group_invocations,
1074 max_compute_workgroup_size_x: max_compute_workgroup_sizes[0],
1075 max_compute_workgroup_size_y: max_compute_workgroup_sizes[1],
1076 max_compute_workgroup_size_z: max_compute_workgroup_sizes[2],
1077 max_compute_workgroups_per_dimension,
1078 max_buffer_size,
1079 max_non_sampler_bindings: std::u32::MAX,
1080 }
1081 }
1082
1083 fn to_hal_alignments(&self) -> crate::Alignments {
1084 let limits = &self.properties.limits;
1085 crate::Alignments {
1086 buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
1087 .unwrap(),
1088 buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
1089 .unwrap(),
1090 }
1091 }
1092}
1093
1094impl super::InstanceShared {
1095 #[allow(trivial_casts)] fn inspect(
1097 &self,
1098 phd: vk::PhysicalDevice,
1099 ) -> (PhysicalDeviceProperties, PhysicalDeviceFeatures) {
1100 let capabilities = {
1101 let mut capabilities = PhysicalDeviceProperties::default();
1102 capabilities.supported_extensions =
1103 unsafe { self.raw.enumerate_device_extension_properties(phd).unwrap() };
1104 capabilities.properties = unsafe { self.raw.get_physical_device_properties(phd) };
1105 capabilities.device_api_version = capabilities.properties.api_version;
1106
1107 if let Some(ref get_device_properties) = self.get_physical_device_properties {
1108 let supports_maintenance3 = capabilities.device_api_version >= vk::API_VERSION_1_1
1110 || capabilities.supports_extension(vk::KhrMaintenance3Fn::name());
1111 let supports_descriptor_indexing = capabilities.device_api_version
1112 >= vk::API_VERSION_1_2
1113 || capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name());
1114 let supports_driver_properties = capabilities.device_api_version
1115 >= vk::API_VERSION_1_2
1116 || capabilities.supports_extension(vk::KhrDriverPropertiesFn::name());
1117 let supports_subgroup_size_control = capabilities.device_api_version
1118 >= vk::API_VERSION_1_3
1119 || capabilities.supports_extension(vk::ExtSubgroupSizeControlFn::name());
1120
1121 let supports_acceleration_structure =
1122 capabilities.supports_extension(vk::KhrAccelerationStructureFn::name());
1123
1124 let mut builder = vk::PhysicalDeviceProperties2KHR::builder();
1125 if supports_maintenance3 {
1126 let next = capabilities
1127 .maintenance_3
1128 .insert(vk::PhysicalDeviceMaintenance3Properties::default());
1129 builder = builder.push_next(next);
1130 }
1131
1132 if supports_descriptor_indexing {
1133 let next = capabilities
1134 .descriptor_indexing
1135 .insert(vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::default());
1136 builder = builder.push_next(next);
1137 }
1138
1139 if supports_acceleration_structure {
1140 let next = capabilities
1141 .acceleration_structure
1142 .insert(vk::PhysicalDeviceAccelerationStructurePropertiesKHR::default());
1143 builder = builder.push_next(next);
1144 }
1145
1146 if supports_driver_properties {
1147 let next = capabilities
1148 .driver
1149 .insert(vk::PhysicalDeviceDriverPropertiesKHR::default());
1150 builder = builder.push_next(next);
1151 }
1152
1153 if capabilities.device_api_version >= vk::API_VERSION_1_1 {
1154 let next = capabilities
1155 .subgroup
1156 .insert(vk::PhysicalDeviceSubgroupProperties::default());
1157 builder = builder.push_next(next);
1158 }
1159
1160 if supports_subgroup_size_control {
1161 let next = capabilities
1162 .subgroup_size_control
1163 .insert(vk::PhysicalDeviceSubgroupSizeControlProperties::default());
1164 builder = builder.push_next(next);
1165 }
1166
1167 let mut properties2 = builder.build();
1168 unsafe {
1169 get_device_properties.get_physical_device_properties2(phd, &mut properties2);
1170 }
1171
1172 if is_intel_igpu_outdated_for_robustness2(
1173 capabilities.properties,
1174 capabilities.driver,
1175 ) {
1176 use crate::auxil::cstr_from_bytes_until_nul;
1177 capabilities.supported_extensions.retain(|&x| {
1178 cstr_from_bytes_until_nul(&x.extension_name)
1179 != Some(vk::ExtRobustness2Fn::name())
1180 });
1181 }
1182 };
1183 capabilities
1184 };
1185
1186 let mut features = PhysicalDeviceFeatures::default();
1187 features.core = if let Some(ref get_device_properties) = self.get_physical_device_properties
1188 {
1189 let core = vk::PhysicalDeviceFeatures::default();
1190 let mut builder = vk::PhysicalDeviceFeatures2KHR::builder().features(core);
1191
1192 if capabilities.device_api_version >= vk::API_VERSION_1_1
1194 || capabilities.supports_extension(vk::KhrMultiviewFn::name())
1195 {
1196 let next = features
1197 .multiview
1198 .insert(vk::PhysicalDeviceMultiviewFeatures::default());
1199 builder = builder.push_next(next);
1200 }
1201
1202 if capabilities.device_api_version >= vk::API_VERSION_1_1
1204 || capabilities.supports_extension(vk::KhrSamplerYcbcrConversionFn::name())
1205 {
1206 let next = features
1207 .sampler_ycbcr_conversion
1208 .insert(vk::PhysicalDeviceSamplerYcbcrConversionFeatures::default());
1209 builder = builder.push_next(next);
1210 }
1211
1212 if capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name()) {
1213 let next = features
1214 .descriptor_indexing
1215 .insert(vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default());
1216 builder = builder.push_next(next);
1217 }
1218
1219 if capabilities.supports_extension(vk::KhrImagelessFramebufferFn::name()) {
1222 let next = features
1223 .imageless_framebuffer
1224 .insert(vk::PhysicalDeviceImagelessFramebufferFeaturesKHR::default());
1225 builder = builder.push_next(next);
1226 }
1227
1228 if capabilities.supports_extension(vk::KhrTimelineSemaphoreFn::name()) {
1231 let next = features
1232 .timeline_semaphore
1233 .insert(vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default());
1234 builder = builder.push_next(next);
1235 }
1236
1237 if capabilities.supports_extension(vk::ExtImageRobustnessFn::name()) {
1238 let next = features
1239 .image_robustness
1240 .insert(vk::PhysicalDeviceImageRobustnessFeaturesEXT::default());
1241 builder = builder.push_next(next);
1242 }
1243 if capabilities.supports_extension(vk::ExtRobustness2Fn::name()) {
1244 let next = features
1245 .robustness2
1246 .insert(vk::PhysicalDeviceRobustness2FeaturesEXT::default());
1247 builder = builder.push_next(next);
1248 }
1249 if capabilities.supports_extension(vk::ExtTextureCompressionAstcHdrFn::name()) {
1250 let next = features
1251 .astc_hdr
1252 .insert(vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::default());
1253 builder = builder.push_next(next);
1254 }
1255 if capabilities.supports_extension(vk::KhrShaderFloat16Int8Fn::name())
1256 && capabilities.supports_extension(vk::Khr16bitStorageFn::name())
1257 {
1258 let next = features.shader_float16.insert((
1259 vk::PhysicalDeviceShaderFloat16Int8FeaturesKHR::default(),
1260 vk::PhysicalDevice16BitStorageFeaturesKHR::default(),
1261 ));
1262 builder = builder.push_next(&mut next.0);
1263 builder = builder.push_next(&mut next.1);
1264 }
1265 if capabilities.supports_extension(vk::KhrAccelerationStructureFn::name()) {
1266 let next = features
1267 .acceleration_structure
1268 .insert(vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default());
1269 builder = builder.push_next(next);
1270 }
1271
1272 if capabilities.device_api_version >= vk::API_VERSION_1_3
1274 || capabilities.supports_extension(vk::KhrZeroInitializeWorkgroupMemoryFn::name())
1275 {
1276 let next = features
1277 .zero_initialize_workgroup_memory
1278 .insert(vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::default());
1279 builder = builder.push_next(next);
1280 }
1281
1282 if capabilities.device_api_version >= vk::API_VERSION_1_3
1284 || capabilities.supports_extension(vk::ExtSubgroupSizeControlFn::name())
1285 {
1286 let next = features
1287 .subgroup_size_control
1288 .insert(vk::PhysicalDeviceSubgroupSizeControlFeatures::default());
1289 builder = builder.push_next(next);
1290 }
1291
1292 let mut features2 = builder.build();
1293 unsafe {
1294 get_device_properties.get_physical_device_features2(phd, &mut features2);
1295 }
1296 features2.features
1297 } else {
1298 unsafe { self.raw.get_physical_device_features(phd) }
1299 };
1300
1301 (capabilities, features)
1302 }
1303}
1304
1305impl super::Instance {
1306 pub fn expose_adapter(
1307 &self,
1308 phd: vk::PhysicalDevice,
1309 ) -> Option<crate::ExposedAdapter<super::Api>> {
1310 use crate::auxil::cstr_from_bytes_until_nul;
1311 use crate::auxil::db;
1312
1313 let (phd_capabilities, phd_features) = self.shared.inspect(phd);
1314
1315 let info = wgt::AdapterInfo {
1316 name: {
1317 cstr_from_bytes_until_nul(&phd_capabilities.properties.device_name)
1318 .and_then(|info| info.to_str().ok())
1319 .unwrap_or("?")
1320 .to_owned()
1321 },
1322 vendor: phd_capabilities.properties.vendor_id,
1323 device: phd_capabilities.properties.device_id,
1324 device_type: match phd_capabilities.properties.device_type {
1325 ash::vk::PhysicalDeviceType::OTHER => wgt::DeviceType::Other,
1326 ash::vk::PhysicalDeviceType::INTEGRATED_GPU => wgt::DeviceType::IntegratedGpu,
1327 ash::vk::PhysicalDeviceType::DISCRETE_GPU => wgt::DeviceType::DiscreteGpu,
1328 ash::vk::PhysicalDeviceType::VIRTUAL_GPU => wgt::DeviceType::VirtualGpu,
1329 ash::vk::PhysicalDeviceType::CPU => wgt::DeviceType::Cpu,
1330 _ => wgt::DeviceType::Other,
1331 },
1332 driver: {
1333 phd_capabilities
1334 .driver
1335 .as_ref()
1336 .and_then(|driver| cstr_from_bytes_until_nul(&driver.driver_name))
1337 .and_then(|name| name.to_str().ok())
1338 .unwrap_or("?")
1339 .to_owned()
1340 },
1341 driver_info: {
1342 phd_capabilities
1343 .driver
1344 .as_ref()
1345 .and_then(|driver| cstr_from_bytes_until_nul(&driver.driver_info))
1346 .and_then(|name| name.to_str().ok())
1347 .unwrap_or("?")
1348 .to_owned()
1349 },
1350 backend: wgt::Backend::Vulkan,
1351 };
1352
1353 let (available_features, downlevel_flags) =
1354 phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities);
1355 let mut workarounds = super::Workarounds::empty();
1356 {
1357 workarounds |= super::Workarounds::SEPARATE_ENTRY_POINTS;
1359 workarounds.set(
1360 super::Workarounds::EMPTY_RESOLVE_ATTACHMENT_LISTS,
1361 phd_capabilities.properties.vendor_id == db::qualcomm::VENDOR,
1362 );
1363 workarounds.set(
1364 super::Workarounds::FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16,
1365 phd_capabilities.properties.vendor_id == db::nvidia::VENDOR,
1366 );
1367 };
1368
1369 if let Some(driver) = phd_capabilities.driver {
1370 if driver.conformance_version.major == 0 {
1371 if driver.driver_id == ash::vk::DriverId::MOLTENVK {
1372 log::debug!("Adapter is not Vulkan compliant, but is MoltenVK, continuing");
1373 } else if self
1374 .shared
1375 .flags
1376 .contains(wgt::InstanceFlags::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER)
1377 {
1378 log::warn!("Adapter is not Vulkan compliant: {}", info.name);
1379 } else {
1380 log::warn!(
1381 "Adapter is not Vulkan compliant, hiding adapter: {}",
1382 info.name
1383 );
1384 return None;
1385 }
1386 }
1387 }
1388 if phd_capabilities.device_api_version == vk::API_VERSION_1_0
1389 && !phd_capabilities.supports_extension(vk::KhrStorageBufferStorageClassFn::name())
1390 {
1391 log::warn!(
1392 "SPIR-V storage buffer class is not supported, hiding adapter: {}",
1393 info.name
1394 );
1395 return None;
1396 }
1397 if !phd_capabilities.supports_extension(vk::AmdNegativeViewportHeightFn::name())
1398 && !phd_capabilities.supports_extension(vk::KhrMaintenance1Fn::name())
1399 && phd_capabilities.device_api_version < vk::API_VERSION_1_1
1400 {
1401 log::warn!(
1402 "viewport Y-flip is not supported, hiding adapter: {}",
1403 info.name
1404 );
1405 return None;
1406 }
1407
1408 let queue_families = unsafe {
1409 self.shared
1410 .raw
1411 .get_physical_device_queue_family_properties(phd)
1412 };
1413 let queue_flags = queue_families.first()?.queue_flags;
1414 if !queue_flags.contains(vk::QueueFlags::GRAPHICS) {
1415 log::warn!("The first queue only exposes {:?}", queue_flags);
1416 return None;
1417 }
1418
1419 let private_caps = super::PrivateCapabilities {
1420 flip_y_requires_shift: phd_capabilities.device_api_version >= vk::API_VERSION_1_1
1421 || phd_capabilities.supports_extension(vk::KhrMaintenance1Fn::name()),
1422 imageless_framebuffers: match phd_features.imageless_framebuffer {
1423 Some(features) => features.imageless_framebuffer == vk::TRUE,
1424 None => phd_features
1425 .imageless_framebuffer
1426 .map_or(false, |ext| ext.imageless_framebuffer != 0),
1427 },
1428 image_view_usage: phd_capabilities.device_api_version >= vk::API_VERSION_1_1
1429 || phd_capabilities.supports_extension(vk::KhrMaintenance2Fn::name()),
1430 timeline_semaphores: match phd_features.timeline_semaphore {
1431 Some(features) => features.timeline_semaphore == vk::TRUE,
1432 None => phd_features
1433 .timeline_semaphore
1434 .map_or(false, |ext| ext.timeline_semaphore != 0),
1435 },
1436 texture_d24: supports_format(
1437 &self.shared.raw,
1438 phd,
1439 vk::Format::X8_D24_UNORM_PACK32,
1440 vk::ImageTiling::OPTIMAL,
1441 depth_stencil_required_flags(),
1442 ),
1443 texture_d24_s8: supports_format(
1444 &self.shared.raw,
1445 phd,
1446 vk::Format::D24_UNORM_S8_UINT,
1447 vk::ImageTiling::OPTIMAL,
1448 depth_stencil_required_flags(),
1449 ),
1450 texture_s8: supports_format(
1451 &self.shared.raw,
1452 phd,
1453 vk::Format::S8_UINT,
1454 vk::ImageTiling::OPTIMAL,
1455 depth_stencil_required_flags(),
1456 ),
1457 non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1,
1458 can_present: true,
1459 robust_buffer_access: phd_features.core.robust_buffer_access != 0,
1461 robust_image_access: match phd_features.robustness2 {
1462 Some(ref f) => f.robust_image_access2 != 0,
1463 None => phd_features
1464 .image_robustness
1465 .map_or(false, |ext| ext.robust_image_access != 0),
1466 },
1467 robust_buffer_access2: phd_features
1468 .robustness2
1469 .as_ref()
1470 .map(|r| r.robust_buffer_access2 == 1)
1471 .unwrap_or_default(),
1472 robust_image_access2: phd_features
1473 .robustness2
1474 .as_ref()
1475 .map(|r| r.robust_image_access2 == 1)
1476 .unwrap_or_default(),
1477 zero_initialize_workgroup_memory: phd_features
1478 .zero_initialize_workgroup_memory
1479 .map_or(false, |ext| {
1480 ext.shader_zero_initialize_workgroup_memory == vk::TRUE
1481 }),
1482 image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2
1483 || phd_capabilities.supports_extension(vk::KhrImageFormatListFn::name()),
1484 };
1485 let capabilities = crate::Capabilities {
1486 limits: phd_capabilities.to_wgpu_limits(),
1487 alignments: phd_capabilities.to_hal_alignments(),
1488 downlevel: wgt::DownlevelCapabilities {
1489 flags: downlevel_flags,
1490 limits: wgt::DownlevelLimits {},
1491 shader_model: wgt::ShaderModel::Sm5, },
1493 };
1494
1495 let adapter = super::Adapter {
1496 raw: phd,
1497 instance: Arc::clone(&self.shared),
1498 known_memory_flags: vk::MemoryPropertyFlags::DEVICE_LOCAL
1500 | vk::MemoryPropertyFlags::HOST_VISIBLE
1501 | vk::MemoryPropertyFlags::HOST_COHERENT
1502 | vk::MemoryPropertyFlags::HOST_CACHED
1503 | vk::MemoryPropertyFlags::LAZILY_ALLOCATED,
1504 phd_capabilities,
1505 downlevel_flags,
1507 private_caps,
1508 workarounds,
1509 };
1510
1511 Some(crate::ExposedAdapter {
1512 adapter,
1513 info,
1514 features: available_features,
1515 capabilities,
1516 })
1517 }
1518}
1519
1520impl super::Adapter {
1521 pub fn raw_physical_device(&self) -> ash::vk::PhysicalDevice {
1522 self.raw
1523 }
1524
1525 pub fn physical_device_capabilities(&self) -> &PhysicalDeviceProperties {
1526 &self.phd_capabilities
1527 }
1528
1529 pub fn shared_instance(&self) -> &super::InstanceShared {
1530 &self.instance
1531 }
1532
1533 pub fn required_device_extensions(&self, features: wgt::Features) -> Vec<&'static CStr> {
1534 let (supported_extensions, unsupported_extensions) = self
1535 .phd_capabilities
1536 .get_required_extensions(features)
1537 .iter()
1538 .partition::<Vec<&CStr>, _>(|&&extension| {
1539 self.phd_capabilities.supports_extension(extension)
1540 });
1541
1542 if !unsupported_extensions.is_empty() {
1543 log::warn!("Missing extensions: {:?}", unsupported_extensions);
1544 }
1545
1546 log::debug!("Supported extensions: {:?}", supported_extensions);
1547 supported_extensions
1548 }
1549
1550 pub fn physical_device_features(
1565 &self,
1566 enabled_extensions: &[&'static CStr],
1567 features: wgt::Features,
1568 ) -> PhysicalDeviceFeatures {
1569 PhysicalDeviceFeatures::from_extensions_and_requested_features(
1570 self.phd_capabilities.device_api_version,
1571 enabled_extensions,
1572 features,
1573 self.downlevel_flags,
1574 &self.private_caps,
1575 )
1576 }
1577
1578 #[allow(clippy::too_many_arguments)]
1584 pub unsafe fn device_from_raw(
1585 &self,
1586 raw_device: ash::Device,
1587 handle_is_owned: bool,
1588 enabled_extensions: &[&'static CStr],
1589 features: wgt::Features,
1590 family_index: u32,
1591 queue_index: u32,
1592 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1593 let mem_properties = {
1594 profiling::scope!("vkGetPhysicalDeviceMemoryProperties");
1595 unsafe {
1596 self.instance
1597 .raw
1598 .get_physical_device_memory_properties(self.raw)
1599 }
1600 };
1601 let memory_types =
1602 &mem_properties.memory_types[..mem_properties.memory_type_count as usize];
1603 let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| {
1604 if self.known_memory_flags.contains(mem.property_flags) {
1605 u | (1 << i)
1606 } else {
1607 u
1608 }
1609 });
1610
1611 let swapchain_fn = khr::Swapchain::new(&self.instance.raw, &raw_device);
1612
1613 let indirect_count_fn = if enabled_extensions.contains(&khr::DrawIndirectCount::name()) {
1614 Some(khr::DrawIndirectCount::new(&self.instance.raw, &raw_device))
1615 } else {
1616 None
1617 };
1618 let timeline_semaphore_fn = if enabled_extensions.contains(&khr::TimelineSemaphore::name())
1619 {
1620 Some(super::ExtensionFn::Extension(khr::TimelineSemaphore::new(
1621 &self.instance.raw,
1622 &raw_device,
1623 )))
1624 } else if self.phd_capabilities.device_api_version >= vk::API_VERSION_1_2 {
1625 Some(super::ExtensionFn::Promoted)
1626 } else {
1627 None
1628 };
1629 let ray_tracing_fns = if enabled_extensions.contains(&khr::AccelerationStructure::name())
1630 && enabled_extensions.contains(&khr::BufferDeviceAddress::name())
1631 {
1632 Some(super::RayTracingDeviceExtensionFunctions {
1633 acceleration_structure: khr::AccelerationStructure::new(
1634 &self.instance.raw,
1635 &raw_device,
1636 ),
1637 buffer_device_address: khr::BufferDeviceAddress::new(
1638 &self.instance.raw,
1639 &raw_device,
1640 ),
1641 })
1642 } else {
1643 None
1644 };
1645
1646 let naga_options = {
1647 use naga::back::spv;
1648
1649 let mut capabilities = vec![
1652 spv::Capability::Shader,
1653 spv::Capability::Matrix,
1654 spv::Capability::Sampled1D,
1655 spv::Capability::Image1D,
1656 spv::Capability::ImageQuery,
1657 spv::Capability::DerivativeControl,
1658 spv::Capability::StorageImageExtendedFormats,
1659 ];
1660
1661 if self
1662 .downlevel_flags
1663 .contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES)
1664 {
1665 capabilities.push(spv::Capability::SampledCubeArray);
1666 }
1667
1668 if self
1669 .downlevel_flags
1670 .contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING)
1671 {
1672 capabilities.push(spv::Capability::SampleRateShading);
1673 }
1674
1675 if features.contains(wgt::Features::MULTIVIEW) {
1676 capabilities.push(spv::Capability::MultiView);
1677 }
1678
1679 if features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX) {
1680 capabilities.push(spv::Capability::Geometry);
1681 }
1682
1683 if features.intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX) {
1684 capabilities.push(spv::Capability::GroupNonUniform);
1685 capabilities.push(spv::Capability::GroupNonUniformVote);
1686 capabilities.push(spv::Capability::GroupNonUniformArithmetic);
1687 capabilities.push(spv::Capability::GroupNonUniformBallot);
1688 capabilities.push(spv::Capability::GroupNonUniformShuffle);
1689 capabilities.push(spv::Capability::GroupNonUniformShuffleRelative);
1690 }
1691
1692 if features.intersects(
1693 wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
1694 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
1695 ) {
1696 capabilities.push(spv::Capability::ShaderNonUniform);
1697 }
1698 if features.contains(wgt::Features::BGRA8UNORM_STORAGE) {
1699 capabilities.push(spv::Capability::StorageImageWriteWithoutFormat);
1700 }
1701
1702 if features.contains(wgt::Features::RAY_QUERY) {
1703 capabilities.push(spv::Capability::RayQueryKHR);
1704 }
1705
1706 if features.contains(wgt::Features::SHADER_INT64) {
1707 capabilities.push(spv::Capability::Int64);
1708 }
1709
1710 let mut flags = spv::WriterFlags::empty();
1711 flags.set(
1712 spv::WriterFlags::DEBUG,
1713 self.instance.flags.contains(wgt::InstanceFlags::DEBUG),
1714 );
1715 flags.set(
1716 spv::WriterFlags::LABEL_VARYINGS,
1717 self.phd_capabilities.properties.vendor_id != crate::auxil::db::qualcomm::VENDOR,
1718 );
1719 flags.set(
1720 spv::WriterFlags::FORCE_POINT_SIZE,
1721 true, );
1726 spv::Options {
1727 lang_version: if features
1728 .intersects(wgt::Features::SUBGROUP | wgt::Features::SUBGROUP_VERTEX)
1729 {
1730 (1, 3)
1731 } else {
1732 (1, 0)
1733 },
1734 flags,
1735 capabilities: Some(capabilities.iter().cloned().collect()),
1736 bounds_check_policies: naga::proc::BoundsCheckPolicies {
1737 index: naga::proc::BoundsCheckPolicy::Restrict,
1738 buffer: if self.private_caps.robust_buffer_access {
1739 naga::proc::BoundsCheckPolicy::Unchecked
1740 } else {
1741 naga::proc::BoundsCheckPolicy::Restrict
1742 },
1743 image_load: if self.private_caps.robust_image_access {
1744 naga::proc::BoundsCheckPolicy::Unchecked
1745 } else {
1746 naga::proc::BoundsCheckPolicy::Restrict
1747 },
1748 image_store: naga::proc::BoundsCheckPolicy::Unchecked,
1749 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
1751 },
1752 zero_initialize_workgroup_memory: if self
1753 .private_caps
1754 .zero_initialize_workgroup_memory
1755 {
1756 spv::ZeroInitializeWorkgroupMemoryMode::Native
1757 } else {
1758 spv::ZeroInitializeWorkgroupMemoryMode::Polyfill
1759 },
1760 binding_map: BTreeMap::default(),
1762 debug_info: None,
1763 }
1764 };
1765
1766 let raw_queue = {
1767 profiling::scope!("vkGetDeviceQueue");
1768 unsafe { raw_device.get_device_queue(family_index, queue_index) }
1769 };
1770
1771 let shared = Arc::new(super::DeviceShared {
1772 raw: raw_device,
1773 family_index,
1774 queue_index,
1775 raw_queue,
1776 handle_is_owned,
1777 instance: Arc::clone(&self.instance),
1778 physical_device: self.raw,
1779 enabled_extensions: enabled_extensions.into(),
1780 extension_fns: super::DeviceExtensionFunctions {
1781 draw_indirect_count: indirect_count_fn,
1782 timeline_semaphore: timeline_semaphore_fn,
1783 ray_tracing: ray_tracing_fns,
1784 },
1785 vendor_id: self.phd_capabilities.properties.vendor_id,
1786 timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
1787 private_caps: self.private_caps.clone(),
1788 features,
1789 workarounds: self.workarounds,
1790 render_passes: Mutex::new(Default::default()),
1791 framebuffers: Mutex::new(Default::default()),
1792 });
1793
1794 let relay_semaphores = super::RelaySemaphores::new(&shared)?;
1795
1796 let queue = super::Queue {
1797 raw: raw_queue,
1798 swapchain_fn,
1799 device: Arc::clone(&shared),
1800 family_index,
1801 relay_semaphores: Mutex::new(relay_semaphores),
1802 };
1803
1804 let mem_allocator = {
1805 let limits = self.phd_capabilities.properties.limits;
1806 let config = gpu_alloc::Config::i_am_prototyping(); let max_memory_allocation_size =
1808 if let Some(maintenance_3) = self.phd_capabilities.maintenance_3 {
1809 maintenance_3.max_memory_allocation_size
1810 } else {
1811 u64::max_value()
1812 };
1813 let properties = gpu_alloc::DeviceProperties {
1814 max_memory_allocation_count: limits.max_memory_allocation_count,
1815 max_memory_allocation_size,
1816 non_coherent_atom_size: limits.non_coherent_atom_size,
1817 memory_types: memory_types
1818 .iter()
1819 .map(|memory_type| gpu_alloc::MemoryType {
1820 props: gpu_alloc::MemoryPropertyFlags::from_bits_truncate(
1821 memory_type.property_flags.as_raw() as u8,
1822 ),
1823 heap: memory_type.heap_index,
1824 })
1825 .collect(),
1826 memory_heaps: mem_properties.memory_heaps
1827 [..mem_properties.memory_heap_count as usize]
1828 .iter()
1829 .map(|&memory_heap| gpu_alloc::MemoryHeap {
1830 size: memory_heap.size,
1831 })
1832 .collect(),
1833 buffer_device_address: enabled_extensions
1834 .contains(&khr::BufferDeviceAddress::name()),
1835 };
1836 gpu_alloc::GpuAllocator::new(config, properties)
1837 };
1838 let desc_allocator = gpu_descriptor::DescriptorAllocator::new(
1839 if let Some(di) = self.phd_capabilities.descriptor_indexing {
1840 di.max_update_after_bind_descriptors_in_all_pools
1841 } else {
1842 0
1843 },
1844 );
1845
1846 let device = super::Device {
1847 shared,
1848 mem_allocator: Mutex::new(mem_allocator),
1849 desc_allocator: Mutex::new(desc_allocator),
1850 valid_ash_memory_types,
1851 naga_options,
1852 #[cfg(feature = "renderdoc")]
1853 render_doc: Default::default(),
1854 };
1855
1856 Ok(crate::OpenDevice { device, queue })
1857 }
1858}
1859
1860impl crate::Adapter for super::Adapter {
1861 type A = super::Api;
1862
1863 unsafe fn open(
1864 &self,
1865 features: wgt::Features,
1866 _limits: &wgt::Limits,
1867 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1868 let enabled_extensions = self.required_device_extensions(features);
1869 let mut enabled_phd_features = self.physical_device_features(&enabled_extensions, features);
1870
1871 let family_index = 0; let family_info = vk::DeviceQueueCreateInfo::builder()
1873 .queue_family_index(family_index)
1874 .queue_priorities(&[1.0])
1875 .build();
1876 let family_infos = [family_info];
1877
1878 let str_pointers = enabled_extensions
1879 .iter()
1880 .map(|&s| {
1881 s.as_ptr()
1883 })
1884 .collect::<Vec<_>>();
1885
1886 let pre_info = vk::DeviceCreateInfo::builder()
1887 .queue_create_infos(&family_infos)
1888 .enabled_extension_names(&str_pointers);
1889 let info = enabled_phd_features
1890 .add_to_device_create_builder(pre_info)
1891 .build();
1892 let raw_device = {
1893 profiling::scope!("vkCreateDevice");
1894 unsafe { self.instance.raw.create_device(self.raw, &info, None)? }
1895 };
1896
1897 unsafe {
1898 self.device_from_raw(
1899 raw_device,
1900 true,
1901 &enabled_extensions,
1902 features,
1903 family_info.queue_family_index,
1904 0,
1905 )
1906 }
1907 }
1908
1909 unsafe fn texture_format_capabilities(
1910 &self,
1911 format: wgt::TextureFormat,
1912 ) -> crate::TextureFormatCapabilities {
1913 use crate::TextureFormatCapabilities as Tfc;
1914
1915 let vk_format = self.private_caps.map_texture_format(format);
1916 let properties = unsafe {
1917 self.instance
1918 .raw
1919 .get_physical_device_format_properties(self.raw, vk_format)
1920 };
1921 let features = properties.optimal_tiling_features;
1922
1923 let mut flags = Tfc::empty();
1924 flags.set(
1925 Tfc::SAMPLED,
1926 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE),
1927 );
1928 flags.set(
1929 Tfc::SAMPLED_LINEAR,
1930 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR),
1931 );
1932 flags.set(
1937 Tfc::STORAGE | Tfc::STORAGE_READ_WRITE,
1938 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE),
1939 );
1940 flags.set(
1941 Tfc::STORAGE_ATOMIC,
1942 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC),
1943 );
1944 flags.set(
1945 Tfc::COLOR_ATTACHMENT,
1946 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT),
1947 );
1948 flags.set(
1949 Tfc::COLOR_ATTACHMENT_BLEND,
1950 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND),
1951 );
1952 flags.set(
1953 Tfc::DEPTH_STENCIL_ATTACHMENT,
1954 features.contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT),
1955 );
1956 flags.set(
1957 Tfc::COPY_SRC,
1958 features.intersects(vk::FormatFeatureFlags::TRANSFER_SRC),
1959 );
1960 flags.set(
1961 Tfc::COPY_DST,
1962 features.intersects(vk::FormatFeatureFlags::TRANSFER_DST),
1963 );
1964 flags.set(Tfc::MULTISAMPLE_RESOLVE, !format.is_compressed());
1966
1967 let format_aspect = crate::FormatAspects::from(format);
1969 let limits = self.phd_capabilities.properties.limits;
1970
1971 let sample_flags = if format_aspect.contains(crate::FormatAspects::DEPTH) {
1972 limits
1973 .framebuffer_depth_sample_counts
1974 .min(limits.sampled_image_depth_sample_counts)
1975 } else if format_aspect.contains(crate::FormatAspects::STENCIL) {
1976 limits
1977 .framebuffer_stencil_sample_counts
1978 .min(limits.sampled_image_stencil_sample_counts)
1979 } else {
1980 let first_aspect = format_aspect
1981 .iter()
1982 .next()
1983 .expect("All texture should at least one aspect")
1984 .map();
1985
1986 assert_ne!(first_aspect, wgt::TextureAspect::DepthOnly);
1988 assert_ne!(first_aspect, wgt::TextureAspect::StencilOnly);
1989
1990 match format.sample_type(Some(first_aspect), None).unwrap() {
1991 wgt::TextureSampleType::Float { .. } => limits
1992 .framebuffer_color_sample_counts
1993 .min(limits.sampled_image_color_sample_counts),
1994 wgt::TextureSampleType::Sint | wgt::TextureSampleType::Uint => {
1995 limits.sampled_image_integer_sample_counts
1996 }
1997 _ => unreachable!(),
1998 }
1999 };
2000
2001 flags.set(
2002 Tfc::MULTISAMPLE_X2,
2003 sample_flags.contains(vk::SampleCountFlags::TYPE_2),
2004 );
2005 flags.set(
2006 Tfc::MULTISAMPLE_X4,
2007 sample_flags.contains(vk::SampleCountFlags::TYPE_4),
2008 );
2009 flags.set(
2010 Tfc::MULTISAMPLE_X8,
2011 sample_flags.contains(vk::SampleCountFlags::TYPE_8),
2012 );
2013 flags.set(
2014 Tfc::MULTISAMPLE_X16,
2015 sample_flags.contains(vk::SampleCountFlags::TYPE_16),
2016 );
2017
2018 flags
2019 }
2020
2021 unsafe fn surface_capabilities(
2022 &self,
2023 surface: &super::Surface,
2024 ) -> Option<crate::SurfaceCapabilities> {
2025 if !self.private_caps.can_present {
2026 return None;
2027 }
2028 let queue_family_index = 0; {
2030 profiling::scope!("vkGetPhysicalDeviceSurfaceSupportKHR");
2031 match unsafe {
2032 surface.functor.get_physical_device_surface_support(
2033 self.raw,
2034 queue_family_index,
2035 surface.raw,
2036 )
2037 } {
2038 Ok(true) => (),
2039 Ok(false) => return None,
2040 Err(e) => {
2041 log::error!("get_physical_device_surface_support: {}", e);
2042 return None;
2043 }
2044 }
2045 }
2046
2047 let caps = {
2048 profiling::scope!("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
2049 match unsafe {
2050 surface
2051 .functor
2052 .get_physical_device_surface_capabilities(self.raw, surface.raw)
2053 } {
2054 Ok(caps) => caps,
2055 Err(e) => {
2056 log::error!("get_physical_device_surface_capabilities: {}", e);
2057 return None;
2058 }
2059 }
2060 };
2061
2062 let max_image_count = if caps.max_image_count == 0 {
2064 !0
2065 } else {
2066 caps.max_image_count
2067 };
2068
2069 let current_extent = if caps.current_extent.width != !0 && caps.current_extent.height != !0
2071 {
2072 Some(wgt::Extent3d {
2073 width: caps.current_extent.width,
2074 height: caps.current_extent.height,
2075 depth_or_array_layers: 1,
2076 })
2077 } else {
2078 None
2079 };
2080
2081 let raw_present_modes = {
2082 profiling::scope!("vkGetPhysicalDeviceSurfacePresentModesKHR");
2083 match unsafe {
2084 surface
2085 .functor
2086 .get_physical_device_surface_present_modes(self.raw, surface.raw)
2087 } {
2088 Ok(present_modes) => present_modes,
2089 Err(e) => {
2090 log::error!("get_physical_device_surface_present_modes: {}", e);
2091 Vec::new()
2092 }
2093 }
2094 };
2095
2096 let raw_surface_formats = {
2097 profiling::scope!("vkGetPhysicalDeviceSurfaceFormatsKHR");
2098 match unsafe {
2099 surface
2100 .functor
2101 .get_physical_device_surface_formats(self.raw, surface.raw)
2102 } {
2103 Ok(formats) => formats,
2104 Err(e) => {
2105 log::error!("get_physical_device_surface_formats: {}", e);
2106 Vec::new()
2107 }
2108 }
2109 };
2110
2111 let formats = raw_surface_formats
2112 .into_iter()
2113 .filter_map(conv::map_vk_surface_formats)
2114 .collect();
2115 Some(crate::SurfaceCapabilities {
2116 formats,
2117 maximum_frame_latency: (caps.min_image_count - 1)..=(max_image_count - 1), current_extent,
2123 usage: conv::map_vk_image_usage(caps.supported_usage_flags),
2124 present_modes: raw_present_modes
2125 .into_iter()
2126 .flat_map(conv::map_vk_present_mode)
2127 .collect(),
2128 composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha),
2129 })
2130 }
2131
2132 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
2133 #[cfg(unix)]
2138 {
2139 let mut timespec = libc::timespec {
2140 tv_sec: 0,
2141 tv_nsec: 0,
2142 };
2143 unsafe {
2144 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut timespec);
2145 }
2146
2147 wgt::PresentationTimestamp(
2148 timespec.tv_sec as u128 * 1_000_000_000 + timespec.tv_nsec as u128,
2149 )
2150 }
2151 #[cfg(not(unix))]
2152 {
2153 wgt::PresentationTimestamp::INVALID_TIMESTAMP
2154 }
2155 }
2156}
2157
2158fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
2159 let tiling = vk::ImageTiling::OPTIMAL;
2160 let features = vk::FormatFeatureFlags::SAMPLED_IMAGE
2161 | vk::FormatFeatureFlags::STORAGE_IMAGE
2162 | vk::FormatFeatureFlags::TRANSFER_SRC
2163 | vk::FormatFeatureFlags::TRANSFER_DST;
2164 let r16unorm = supports_format(instance, phd, vk::Format::R16_UNORM, tiling, features);
2165 let r16snorm = supports_format(instance, phd, vk::Format::R16_SNORM, tiling, features);
2166 let rg16unorm = supports_format(instance, phd, vk::Format::R16G16_UNORM, tiling, features);
2167 let rg16snorm = supports_format(instance, phd, vk::Format::R16G16_SNORM, tiling, features);
2168 let rgba16unorm = supports_format(
2169 instance,
2170 phd,
2171 vk::Format::R16G16B16A16_UNORM,
2172 tiling,
2173 features,
2174 );
2175 let rgba16snorm = supports_format(
2176 instance,
2177 phd,
2178 vk::Format::R16G16B16A16_SNORM,
2179 tiling,
2180 features,
2181 );
2182
2183 r16unorm && r16snorm && rg16unorm && rg16snorm && rgba16unorm && rgba16snorm
2184}
2185
2186fn is_float32_filterable_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
2187 let tiling = vk::ImageTiling::OPTIMAL;
2188 let features = vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR;
2189 let r_float = supports_format(instance, phd, vk::Format::R32_SFLOAT, tiling, features);
2190 let rg_float = supports_format(instance, phd, vk::Format::R32G32_SFLOAT, tiling, features);
2191 let rgba_float = supports_format(
2192 instance,
2193 phd,
2194 vk::Format::R32G32B32A32_SFLOAT,
2195 tiling,
2196 features,
2197 );
2198 r_float && rg_float && rgba_float
2199}
2200
2201fn supports_format(
2202 instance: &ash::Instance,
2203 phd: vk::PhysicalDevice,
2204 format: vk::Format,
2205 tiling: vk::ImageTiling,
2206 features: vk::FormatFeatureFlags,
2207) -> bool {
2208 let properties = unsafe { instance.get_physical_device_format_properties(phd, format) };
2209 match tiling {
2210 vk::ImageTiling::LINEAR => properties.linear_tiling_features.contains(features),
2211 vk::ImageTiling::OPTIMAL => properties.optimal_tiling_features.contains(features),
2212 _ => false,
2213 }
2214}
2215
2216fn supports_bgra8unorm_storage(
2217 instance: &ash::Instance,
2218 phd: vk::PhysicalDevice,
2219 device_api_version: u32,
2220) -> bool {
2221 if device_api_version < vk::API_VERSION_1_3 {
2227 return false;
2228 }
2229
2230 unsafe {
2231 let mut properties3 = vk::FormatProperties3::default();
2232 let mut properties2 = vk::FormatProperties2::builder().push_next(&mut properties3);
2233
2234 instance.get_physical_device_format_properties2(
2235 phd,
2236 vk::Format::B8G8R8A8_UNORM,
2237 &mut properties2,
2238 );
2239
2240 let features2 = properties2.format_properties.optimal_tiling_features;
2241 let features3 = properties3.optimal_tiling_features;
2242
2243 features2.contains(vk::FormatFeatureFlags::STORAGE_IMAGE)
2244 && features3.contains(vk::FormatFeatureFlags2::STORAGE_WRITE_WITHOUT_FORMAT)
2245 }
2246}
2247
2248fn is_intel_igpu_outdated_for_robustness2(
2252 props: vk::PhysicalDeviceProperties,
2253 driver: Option<vk::PhysicalDeviceDriverPropertiesKHR>,
2254) -> bool {
2255 const DRIVER_VERSION_WORKING: u32 = (101 << 14) | 2115; let is_outdated = props.vendor_id == crate::auxil::db::intel::VENDOR
2258 && props.device_type == vk::PhysicalDeviceType::INTEGRATED_GPU
2259 && props.driver_version < DRIVER_VERSION_WORKING
2260 && driver
2261 .map(|driver| driver.driver_id == vk::DriverId::INTEL_PROPRIETARY_WINDOWS)
2262 .unwrap_or_default();
2263
2264 if is_outdated {
2265 log::warn!(
2266 "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)",
2267 props.driver_version,
2268 DRIVER_VERSION_WORKING
2269 );
2270 }
2271 is_outdated
2272}