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}
17
18#[derive(Debug, Default)]
20pub struct PhysicalDeviceFeatures {
21 core: vk::PhysicalDeviceFeatures,
22 pub(super) descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
23 imageless_framebuffer: Option<vk::PhysicalDeviceImagelessFramebufferFeaturesKHR>,
24 timeline_semaphore: Option<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>,
25 image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
26 robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT>,
27 multiview: Option<vk::PhysicalDeviceMultiviewFeaturesKHR>,
28 astc_hdr: Option<vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT>,
29 shader_float16: Option<(
30 vk::PhysicalDeviceShaderFloat16Int8Features,
31 vk::PhysicalDevice16BitStorageFeatures,
32 )>,
33 zero_initialize_workgroup_memory:
34 Option<vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures>,
35}
36
37unsafe impl Send for PhysicalDeviceFeatures {}
39unsafe impl Sync for PhysicalDeviceFeatures {}
40
41impl PhysicalDeviceFeatures {
42 pub fn add_to_device_create_builder<'a>(
44 &'a mut self,
45 mut info: vk::DeviceCreateInfoBuilder<'a>,
46 ) -> vk::DeviceCreateInfoBuilder<'a> {
47 info = info.enabled_features(&self.core);
48 if let Some(ref mut feature) = self.descriptor_indexing {
49 info = info.push_next(feature);
50 }
51 if let Some(ref mut feature) = self.imageless_framebuffer {
52 info = info.push_next(feature);
53 }
54 if let Some(ref mut feature) = self.timeline_semaphore {
55 info = info.push_next(feature);
56 }
57 if let Some(ref mut feature) = self.image_robustness {
58 info = info.push_next(feature);
59 }
60 if let Some(ref mut feature) = self.robustness2 {
61 info = info.push_next(feature);
62 }
63 if let Some(ref mut feature) = self.astc_hdr {
64 info = info.push_next(feature);
65 }
66 if let Some((ref mut f16_i8_feature, ref mut _16bit_feature)) = self.shader_float16 {
67 info = info.push_next(f16_i8_feature);
68 info = info.push_next(_16bit_feature);
69 }
70 if let Some(ref mut feature) = self.zero_initialize_workgroup_memory {
71 info = info.push_next(feature);
72 }
73 info
74 }
75
76 fn from_extensions_and_requested_features(
80 effective_api_version: u32,
81 enabled_extensions: &[&'static CStr],
82 requested_features: wgt::Features,
83 downlevel_flags: wgt::DownlevelFlags,
84 private_caps: &super::PrivateCapabilities,
85 ) -> Self {
86 let needs_sampled_image_non_uniform = requested_features.contains(
87 wgt::Features::TEXTURE_BINDING_ARRAY
88 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
89 );
90 let needs_storage_buffer_non_uniform = requested_features.contains(
91 wgt::Features::BUFFER_BINDING_ARRAY
92 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
93 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
94 );
95 let needs_uniform_buffer_non_uniform = requested_features.contains(
96 wgt::Features::TEXTURE_BINDING_ARRAY
97 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
98 );
99 let needs_storage_image_non_uniform = requested_features.contains(
100 wgt::Features::TEXTURE_BINDING_ARRAY
101 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
102 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
103 );
104 let needs_partially_bound =
105 requested_features.intersects(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
106
107 Self {
108 core: vk::PhysicalDeviceFeatures::builder()
111 .robust_buffer_access(private_caps.robust_buffer_access)
112 .independent_blend(downlevel_flags.contains(wgt::DownlevelFlags::INDEPENDENT_BLEND))
113 .sample_rate_shading(
114 downlevel_flags.contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING),
115 )
116 .image_cube_array(
117 downlevel_flags.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES),
118 )
119 .draw_indirect_first_instance(
120 requested_features.contains(wgt::Features::INDIRECT_FIRST_INSTANCE),
121 )
122 .multi_draw_indirect(
124 requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT),
125 )
126 .fill_mode_non_solid(requested_features.intersects(
127 wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT,
128 ))
129 .sampler_anisotropy(
133 downlevel_flags.contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING),
134 )
135 .texture_compression_etc2(
136 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ETC2),
137 )
138 .texture_compression_astc_ldr(
139 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC),
140 )
141 .texture_compression_bc(
142 requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_BC),
143 )
144 .pipeline_statistics_query(
146 requested_features.contains(wgt::Features::PIPELINE_STATISTICS_QUERY),
147 )
148 .vertex_pipeline_stores_and_atomics(
149 requested_features.contains(wgt::Features::VERTEX_WRITABLE_STORAGE),
150 )
151 .fragment_stores_and_atomics(
152 downlevel_flags.contains(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE),
153 )
154 .shader_uniform_buffer_array_dynamic_indexing(
157 requested_features.contains(wgt::Features::BUFFER_BINDING_ARRAY),
158 )
159 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
160 wgt::Features::BUFFER_BINDING_ARRAY
161 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
162 ))
163 .shader_sampled_image_array_dynamic_indexing(
164 requested_features.contains(wgt::Features::TEXTURE_BINDING_ARRAY),
165 )
166 .shader_storage_buffer_array_dynamic_indexing(requested_features.contains(
167 wgt::Features::TEXTURE_BINDING_ARRAY
168 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
169 ))
170 .shader_float64(requested_features.contains(wgt::Features::SHADER_F64))
174 .shader_int16(requested_features.contains(wgt::Features::SHADER_I16))
176 .geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX))
178 .depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL))
179 .build(),
180 descriptor_indexing: if requested_features.intersects(indexing_features()) {
181 Some(
182 vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::builder()
183 .shader_sampled_image_array_non_uniform_indexing(
184 needs_sampled_image_non_uniform,
185 )
186 .shader_storage_image_array_non_uniform_indexing(
187 needs_storage_image_non_uniform,
188 )
189 .shader_uniform_buffer_array_non_uniform_indexing(
190 needs_uniform_buffer_non_uniform,
191 )
192 .shader_storage_buffer_array_non_uniform_indexing(
193 needs_storage_buffer_non_uniform,
194 )
195 .descriptor_binding_partially_bound(needs_partially_bound)
196 .build(),
197 )
198 } else {
199 None
200 },
201 imageless_framebuffer: if effective_api_version >= vk::API_VERSION_1_2
202 || enabled_extensions.contains(&vk::KhrImagelessFramebufferFn::name())
203 {
204 Some(
205 vk::PhysicalDeviceImagelessFramebufferFeaturesKHR::builder()
206 .imageless_framebuffer(private_caps.imageless_framebuffers)
207 .build(),
208 )
209 } else {
210 None
211 },
212 timeline_semaphore: if effective_api_version >= vk::API_VERSION_1_2
213 || enabled_extensions.contains(&vk::KhrTimelineSemaphoreFn::name())
214 {
215 Some(
216 vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::builder()
217 .timeline_semaphore(private_caps.timeline_semaphores)
218 .build(),
219 )
220 } else {
221 None
222 },
223 image_robustness: if effective_api_version >= vk::API_VERSION_1_3
224 || enabled_extensions.contains(&vk::ExtImageRobustnessFn::name())
225 {
226 Some(
227 vk::PhysicalDeviceImageRobustnessFeaturesEXT::builder()
228 .robust_image_access(private_caps.robust_image_access)
229 .build(),
230 )
231 } else {
232 None
233 },
234 robustness2: if enabled_extensions.contains(&vk::ExtRobustness2Fn::name()) {
235 Some(
239 vk::PhysicalDeviceRobustness2FeaturesEXT::builder()
240 .robust_buffer_access2(private_caps.robust_buffer_access)
241 .robust_image_access2(private_caps.robust_image_access)
242 .build(),
243 )
244 } else {
245 None
246 },
247 multiview: if effective_api_version >= vk::API_VERSION_1_1
248 || enabled_extensions.contains(&vk::KhrMultiviewFn::name())
249 {
250 Some(
251 vk::PhysicalDeviceMultiviewFeatures::builder()
252 .multiview(requested_features.contains(wgt::Features::MULTIVIEW))
253 .build(),
254 )
255 } else {
256 None
257 },
258 astc_hdr: if enabled_extensions.contains(&vk::ExtTextureCompressionAstcHdrFn::name()) {
259 Some(
260 vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::builder()
261 .texture_compression_astc_hdr(true)
262 .build(),
263 )
264 } else {
265 None
266 },
267 shader_float16: if requested_features.contains(wgt::Features::SHADER_F16) {
268 Some((
269 vk::PhysicalDeviceShaderFloat16Int8Features::builder()
270 .shader_float16(true)
271 .build(),
272 vk::PhysicalDevice16BitStorageFeatures::builder()
273 .storage_buffer16_bit_access(true)
274 .uniform_and_storage_buffer16_bit_access(true)
275 .build(),
276 ))
277 } else {
278 None
279 },
280 zero_initialize_workgroup_memory: if effective_api_version >= vk::API_VERSION_1_3
281 || enabled_extensions.contains(&vk::KhrZeroInitializeWorkgroupMemoryFn::name())
282 {
283 Some(
284 vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::builder()
285 .shader_zero_initialize_workgroup_memory(
286 private_caps.zero_initialize_workgroup_memory,
287 )
288 .build(),
289 )
290 } else {
291 None
292 },
293 }
294 }
295
296 fn to_wgpu(
297 &self,
298 instance: &ash::Instance,
299 phd: vk::PhysicalDevice,
300 caps: &PhysicalDeviceCapabilities,
301 ) -> (wgt::Features, wgt::DownlevelFlags) {
302 use crate::auxil::db;
303 use wgt::{DownlevelFlags as Df, Features as F};
304 let mut features = F::empty()
305 | F::SPIRV_SHADER_PASSTHROUGH
306 | F::MAPPABLE_PRIMARY_BUFFERS
307 | F::PUSH_CONSTANTS
308 | F::ADDRESS_MODE_CLAMP_TO_BORDER
309 | F::ADDRESS_MODE_CLAMP_TO_ZERO
310 | F::TIMESTAMP_QUERY
311 | F::TIMESTAMP_QUERY_INSIDE_PASSES
312 | F::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
313 | F::CLEAR_TEXTURE;
314
315 let mut dl_flags = Df::COMPUTE_SHADERS
316 | Df::BASE_VERTEX
317 | Df::READ_ONLY_DEPTH_STENCIL
318 | Df::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
319 | Df::COMPARISON_SAMPLERS
320 | Df::VERTEX_STORAGE
321 | Df::FRAGMENT_STORAGE
322 | Df::DEPTH_TEXTURE_AND_BUFFER_COPIES
323 | Df::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED
324 | Df::UNRESTRICTED_INDEX_BUFFER
325 | Df::INDIRECT_EXECUTION
326 | Df::VIEW_FORMATS
327 | Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES;
328
329 dl_flags.set(
330 Df::SURFACE_VIEW_FORMATS,
331 caps.supports_extension(vk::KhrSwapchainMutableFormatFn::name()),
332 );
333 dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0);
334 dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0);
335 dl_flags.set(
336 Df::FRAGMENT_WRITABLE_STORAGE,
337 self.core.fragment_stores_and_atomics != 0,
338 );
339 dl_flags.set(Df::MULTISAMPLED_SHADING, self.core.sample_rate_shading != 0);
340 dl_flags.set(Df::INDEPENDENT_BLEND, self.core.independent_blend != 0);
341 dl_flags.set(
342 Df::FULL_DRAW_INDEX_UINT32,
343 self.core.full_draw_index_uint32 != 0,
344 );
345 dl_flags.set(Df::DEPTH_BIAS_CLAMP, self.core.depth_bias_clamp != 0);
346
347 features.set(
348 F::INDIRECT_FIRST_INSTANCE,
349 self.core.draw_indirect_first_instance != 0,
350 );
351 features.set(F::MULTI_DRAW_INDIRECT, self.core.multi_draw_indirect != 0);
353 features.set(F::POLYGON_MODE_LINE, self.core.fill_mode_non_solid != 0);
354 features.set(F::POLYGON_MODE_POINT, self.core.fill_mode_non_solid != 0);
355 features.set(
359 F::TEXTURE_COMPRESSION_ETC2,
360 self.core.texture_compression_etc2 != 0,
361 );
362 features.set(
363 F::TEXTURE_COMPRESSION_ASTC,
364 self.core.texture_compression_astc_ldr != 0,
365 );
366 features.set(
367 F::TEXTURE_COMPRESSION_BC,
368 self.core.texture_compression_bc != 0,
369 );
370 features.set(
371 F::PIPELINE_STATISTICS_QUERY,
372 self.core.pipeline_statistics_query != 0,
373 );
374 features.set(
375 F::VERTEX_WRITABLE_STORAGE,
376 self.core.vertex_pipeline_stores_and_atomics != 0,
377 );
378 features.set(
381 F::BUFFER_BINDING_ARRAY,
382 self.core.shader_uniform_buffer_array_dynamic_indexing != 0,
383 );
384 features.set(
385 F::TEXTURE_BINDING_ARRAY,
386 self.core.shader_sampled_image_array_dynamic_indexing != 0,
387 );
388 features.set(F::SHADER_PRIMITIVE_INDEX, self.core.geometry_shader != 0);
389 if Self::all_features_supported(
390 &features,
391 &[
392 (
393 F::BUFFER_BINDING_ARRAY,
394 self.core.shader_storage_buffer_array_dynamic_indexing,
395 ),
396 (
397 F::TEXTURE_BINDING_ARRAY,
398 self.core.shader_storage_image_array_dynamic_indexing,
399 ),
400 ],
401 ) {
402 features.insert(F::STORAGE_RESOURCE_BINDING_ARRAY);
403 }
404 features.set(F::SHADER_F64, self.core.shader_float64 != 0);
408 features.set(F::SHADER_I16, self.core.shader_int16 != 0);
410
411 features.set(
414 F::MULTI_DRAW_INDIRECT_COUNT,
415 caps.supports_extension(vk::KhrDrawIndirectCountFn::name()),
416 );
417 features.set(
418 F::CONSERVATIVE_RASTERIZATION,
419 caps.supports_extension(vk::ExtConservativeRasterizationFn::name()),
420 );
421
422 let intel_windows = caps.properties.vendor_id == db::intel::VENDOR && cfg!(windows);
423
424 if let Some(ref descriptor_indexing) = self.descriptor_indexing {
425 const STORAGE: F = F::STORAGE_RESOURCE_BINDING_ARRAY;
426 if Self::all_features_supported(
427 &features,
428 &[
429 (
430 F::TEXTURE_BINDING_ARRAY,
431 descriptor_indexing.shader_sampled_image_array_non_uniform_indexing,
432 ),
433 (
434 F::BUFFER_BINDING_ARRAY | STORAGE,
435 descriptor_indexing.shader_storage_buffer_array_non_uniform_indexing,
436 ),
437 ],
438 ) {
439 features.insert(F::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING);
440 }
441 if Self::all_features_supported(
442 &features,
443 &[
444 (
445 F::BUFFER_BINDING_ARRAY,
446 descriptor_indexing.shader_uniform_buffer_array_non_uniform_indexing,
447 ),
448 (
449 F::TEXTURE_BINDING_ARRAY | STORAGE,
450 descriptor_indexing.shader_storage_image_array_non_uniform_indexing,
451 ),
452 ],
453 ) {
454 features.insert(F::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING);
455 }
456 if descriptor_indexing.descriptor_binding_partially_bound != 0 && !intel_windows {
457 features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
458 }
459 }
460
461 features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0);
462
463 if let Some(ref multiview) = self.multiview {
464 features.set(F::MULTIVIEW, multiview.multiview != 0);
465 }
466
467 features.set(
468 F::TEXTURE_FORMAT_16BIT_NORM,
469 is_format_16bit_norm_supported(instance, phd),
470 );
471
472 if let Some(ref astc_hdr) = self.astc_hdr {
473 features.set(
474 F::TEXTURE_COMPRESSION_ASTC_HDR,
475 astc_hdr.texture_compression_astc_hdr != 0,
476 );
477 }
478
479 if let Some((ref f16_i8, ref bit16)) = self.shader_float16 {
480 features.set(
481 F::SHADER_F16,
482 f16_i8.shader_float16 != 0
483 && bit16.storage_buffer16_bit_access != 0
484 && bit16.uniform_and_storage_buffer16_bit_access != 0,
485 );
486 }
487
488 let supports_depth_format = |format| {
489 supports_format(
490 instance,
491 phd,
492 format,
493 vk::ImageTiling::OPTIMAL,
494 depth_stencil_required_flags(),
495 )
496 };
497
498 let texture_s8 = supports_depth_format(vk::Format::S8_UINT);
499 let texture_d32 = supports_depth_format(vk::Format::D32_SFLOAT);
500 let texture_d24_s8 = supports_depth_format(vk::Format::D24_UNORM_S8_UINT);
501 let texture_d32_s8 = supports_depth_format(vk::Format::D32_SFLOAT_S8_UINT);
502
503 let stencil8 = texture_s8 || texture_d24_s8;
504 let depth24_plus_stencil8 = texture_d24_s8 || texture_d32_s8;
505
506 dl_flags.set(
507 Df::WEBGPU_TEXTURE_FORMAT_SUPPORT,
508 stencil8 && depth24_plus_stencil8 && texture_d32,
509 );
510
511 features.set(F::DEPTH32FLOAT_STENCIL8, texture_d32_s8);
512
513 let rg11b10ufloat_renderable = supports_format(
514 instance,
515 phd,
516 vk::Format::B10G11R11_UFLOAT_PACK32,
517 vk::ImageTiling::OPTIMAL,
518 vk::FormatFeatureFlags::COLOR_ATTACHMENT
519 | vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND,
520 );
521 features.set(F::RG11B10UFLOAT_RENDERABLE, rg11b10ufloat_renderable);
522
523 (features, dl_flags)
524 }
525
526 fn all_features_supported(
527 features: &wgt::Features,
528 implications: &[(wgt::Features, vk::Bool32)],
529 ) -> bool {
530 implications
531 .iter()
532 .all(|&(flag, support)| !features.contains(flag) || support != 0)
533 }
534}
535
536#[derive(Default)]
538pub struct PhysicalDeviceCapabilities {
539 supported_extensions: Vec<vk::ExtensionProperties>,
540 properties: vk::PhysicalDeviceProperties,
541 maintenance_3: Option<vk::PhysicalDeviceMaintenance3Properties>,
542 descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingPropertiesEXT>,
543 driver: Option<vk::PhysicalDeviceDriverPropertiesKHR>,
544 effective_api_version: u32,
558}
559
560unsafe impl Send for PhysicalDeviceCapabilities {}
562unsafe impl Sync for PhysicalDeviceCapabilities {}
563
564impl PhysicalDeviceCapabilities {
565 pub fn properties(&self) -> vk::PhysicalDeviceProperties {
566 self.properties
567 }
568
569 pub fn supports_extension(&self, extension: &CStr) -> bool {
570 use crate::auxil::cstr_from_bytes_until_nul;
571 self.supported_extensions
572 .iter()
573 .any(|ep| cstr_from_bytes_until_nul(&ep.extension_name) == Some(extension))
574 }
575
576 fn get_required_extensions(&self, requested_features: wgt::Features) -> Vec<&'static CStr> {
578 let mut extensions = Vec::new();
579
580 extensions.push(vk::KhrSwapchainFn::name());
585
586 if self.effective_api_version < vk::API_VERSION_1_1 {
587 if self.supports_extension(vk::KhrMaintenance1Fn::name()) {
589 extensions.push(vk::KhrMaintenance1Fn::name());
590 } else {
591 extensions.push(vk::AmdNegativeViewportHeightFn::name());
593 }
594
595 if self.supports_extension(vk::KhrMaintenance2Fn::name()) {
597 extensions.push(vk::KhrMaintenance2Fn::name());
598 }
599
600 if self.supports_extension(vk::KhrMaintenance3Fn::name()) {
602 extensions.push(vk::KhrMaintenance3Fn::name());
603 }
604
605 extensions.push(vk::KhrStorageBufferStorageClassFn::name());
607
608 if requested_features.contains(wgt::Features::MULTIVIEW) {
610 extensions.push(vk::KhrMultiviewFn::name());
611 }
612 }
613
614 if self.effective_api_version < vk::API_VERSION_1_2 {
615 if self.supports_extension(vk::KhrImageFormatListFn::name()) {
617 extensions.push(vk::KhrImageFormatListFn::name());
618 }
619
620 if self.supports_extension(vk::KhrImagelessFramebufferFn::name()) {
622 extensions.push(vk::KhrImagelessFramebufferFn::name());
623 if self.effective_api_version < vk::API_VERSION_1_1 {
625 extensions.push(vk::KhrMaintenance2Fn::name());
626 }
627 }
628
629 if self.supports_extension(vk::KhrDriverPropertiesFn::name()) {
631 extensions.push(vk::KhrDriverPropertiesFn::name());
632 }
633
634 if self.supports_extension(vk::KhrTimelineSemaphoreFn::name()) {
636 extensions.push(vk::KhrTimelineSemaphoreFn::name());
637 }
638
639 if requested_features.intersects(indexing_features()) {
641 extensions.push(vk::ExtDescriptorIndexingFn::name());
642 }
643
644 if requested_features.contains(wgt::Features::SHADER_F16) {
646 extensions.push(vk::KhrShaderFloat16Int8Fn::name());
647 if self.effective_api_version < vk::API_VERSION_1_1 {
649 extensions.push(vk::Khr16bitStorageFn::name());
650 }
651 }
652
653 }
656
657 if self.effective_api_version < vk::API_VERSION_1_3 {
658 if self.supports_extension(vk::ExtImageRobustnessFn::name()) {
660 extensions.push(vk::ExtImageRobustnessFn::name());
661 }
662 }
663
664 if self.supports_extension(vk::KhrSwapchainMutableFormatFn::name()) {
666 extensions.push(vk::KhrSwapchainMutableFormatFn::name());
667 }
668
669 if self.supports_extension(vk::ExtRobustness2Fn::name()) {
671 extensions.push(vk::ExtRobustness2Fn::name());
672 }
673
674 if requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT_COUNT) {
678 extensions.push(vk::KhrDrawIndirectCountFn::name());
679 }
680
681 if requested_features.contains(wgt::Features::CONSERVATIVE_RASTERIZATION) {
683 extensions.push(vk::ExtConservativeRasterizationFn::name());
684 }
685
686 #[cfg(any(target_os = "macos", target_os = "ios"))]
688 extensions.push(vk::KhrPortabilitySubsetFn::name());
689
690 if requested_features.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR) {
692 extensions.push(vk::ExtTextureCompressionAstcHdrFn::name());
693 }
694
695 extensions
696 }
697
698 fn to_wgpu_limits(&self) -> wgt::Limits {
699 let limits = &self.properties.limits;
700
701 let max_compute_workgroup_sizes = limits.max_compute_work_group_size;
702 let max_compute_workgroups_per_dimension = limits.max_compute_work_group_count[0]
703 .min(limits.max_compute_work_group_count[1])
704 .min(limits.max_compute_work_group_count[2]);
705
706 let is_nvidia = self.properties.vendor_id == crate::auxil::db::nvidia::VENDOR;
708 let max_buffer_size =
709 if (cfg!(target_os = "linux") || cfg!(target_os = "android")) && !is_nvidia {
710 i32::MAX as u64
711 } else {
712 u64::MAX
713 };
714
715 wgt::Limits {
716 max_texture_dimension_1d: limits.max_image_dimension1_d,
717 max_texture_dimension_2d: limits.max_image_dimension2_d,
718 max_texture_dimension_3d: limits.max_image_dimension3_d,
719 max_texture_array_layers: limits.max_image_array_layers,
720 max_bind_groups: limits
721 .max_bound_descriptor_sets
722 .min(crate::MAX_BIND_GROUPS as u32),
723 max_bindings_per_bind_group: wgt::Limits::default().max_bindings_per_bind_group,
724 max_dynamic_uniform_buffers_per_pipeline_layout: limits
725 .max_descriptor_set_uniform_buffers_dynamic,
726 max_dynamic_storage_buffers_per_pipeline_layout: limits
727 .max_descriptor_set_storage_buffers_dynamic,
728 max_sampled_textures_per_shader_stage: limits.max_per_stage_descriptor_sampled_images,
729 max_samplers_per_shader_stage: limits.max_per_stage_descriptor_samplers,
730 max_storage_buffers_per_shader_stage: limits.max_per_stage_descriptor_storage_buffers,
731 max_storage_textures_per_shader_stage: limits.max_per_stage_descriptor_storage_images,
732 max_uniform_buffers_per_shader_stage: limits.max_per_stage_descriptor_uniform_buffers,
733 max_uniform_buffer_binding_size: limits
734 .max_uniform_buffer_range
735 .min(crate::auxil::MAX_I32_BINDING_SIZE),
736 max_storage_buffer_binding_size: limits
737 .max_storage_buffer_range
738 .min(crate::auxil::MAX_I32_BINDING_SIZE),
739 max_vertex_buffers: limits
740 .max_vertex_input_bindings
741 .min(crate::MAX_VERTEX_BUFFERS as u32),
742 max_vertex_attributes: limits.max_vertex_input_attributes,
743 max_vertex_buffer_array_stride: limits.max_vertex_input_binding_stride,
744 max_push_constant_size: limits.max_push_constants_size,
745 min_uniform_buffer_offset_alignment: limits.min_uniform_buffer_offset_alignment as u32,
746 min_storage_buffer_offset_alignment: limits.min_storage_buffer_offset_alignment as u32,
747 max_inter_stage_shader_components: limits
748 .max_vertex_output_components
749 .min(limits.max_fragment_input_components),
750 max_compute_workgroup_storage_size: limits.max_compute_shared_memory_size,
751 max_compute_invocations_per_workgroup: limits.max_compute_work_group_invocations,
752 max_compute_workgroup_size_x: max_compute_workgroup_sizes[0],
753 max_compute_workgroup_size_y: max_compute_workgroup_sizes[1],
754 max_compute_workgroup_size_z: max_compute_workgroup_sizes[2],
755 max_compute_workgroups_per_dimension,
756 max_buffer_size,
757 }
758 }
759
760 fn to_hal_alignments(&self) -> crate::Alignments {
761 let limits = &self.properties.limits;
762 crate::Alignments {
763 buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
764 .unwrap(),
765 buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
766 .unwrap(),
767 }
768 }
769}
770
771impl super::InstanceShared {
772 #[allow(trivial_casts)] fn inspect(
774 &self,
775 phd: vk::PhysicalDevice,
776 ) -> (PhysicalDeviceCapabilities, PhysicalDeviceFeatures) {
777 let capabilities = {
778 let mut capabilities = PhysicalDeviceCapabilities::default();
779 capabilities.supported_extensions =
780 unsafe { self.raw.enumerate_device_extension_properties(phd).unwrap() };
781 capabilities.properties = if let Some(ref get_device_properties) =
782 self.get_physical_device_properties
783 {
784 let supports_descriptor_indexing = self.driver_api_version >= vk::API_VERSION_1_2
786 || capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name());
787 let supports_driver_properties = self.driver_api_version >= vk::API_VERSION_1_2
788 || capabilities.supports_extension(vk::KhrDriverPropertiesFn::name());
789
790 let mut builder = vk::PhysicalDeviceProperties2KHR::builder();
791 if self.driver_api_version >= vk::API_VERSION_1_1
792 || capabilities.supports_extension(vk::KhrMaintenance3Fn::name())
793 {
794 capabilities.maintenance_3 =
795 Some(vk::PhysicalDeviceMaintenance3Properties::default());
796 builder = builder.push_next(capabilities.maintenance_3.as_mut().unwrap());
797 }
798
799 if supports_descriptor_indexing {
800 let next = capabilities
801 .descriptor_indexing
802 .insert(vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::default());
803 builder = builder.push_next(next);
804 }
805
806 if supports_driver_properties {
807 let next = capabilities
808 .driver
809 .insert(vk::PhysicalDeviceDriverPropertiesKHR::default());
810 builder = builder.push_next(next);
811 }
812
813 let mut properties2 = builder.build();
814 unsafe {
815 get_device_properties.get_physical_device_properties2(phd, &mut properties2);
816 }
817 properties2.properties
818 } else {
819 unsafe { self.raw.get_physical_device_properties(phd) }
820 };
821
822 capabilities.effective_api_version = self
824 .driver_api_version
825 .min(capabilities.properties.api_version);
826 capabilities
827 };
828
829 let mut features = PhysicalDeviceFeatures::default();
830 features.core = if let Some(ref get_device_properties) = self.get_physical_device_properties
831 {
832 let core = vk::PhysicalDeviceFeatures::default();
833 let mut builder = vk::PhysicalDeviceFeatures2KHR::builder().features(core);
834
835 if capabilities.effective_api_version >= vk::API_VERSION_1_1
837 || capabilities.supports_extension(vk::KhrMultiviewFn::name())
838 {
839 let next = features
840 .multiview
841 .insert(vk::PhysicalDeviceMultiviewFeatures::default());
842 builder = builder.push_next(next);
843 }
844
845 if capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name()) {
846 let next = features
847 .descriptor_indexing
848 .insert(vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default());
849 builder = builder.push_next(next);
850 }
851
852 if capabilities.supports_extension(vk::KhrImagelessFramebufferFn::name()) {
854 let next = features
855 .imageless_framebuffer
856 .insert(vk::PhysicalDeviceImagelessFramebufferFeaturesKHR::default());
857 builder = builder.push_next(next);
858 }
859
860 if capabilities.supports_extension(vk::KhrTimelineSemaphoreFn::name()) {
862 let next = features
863 .timeline_semaphore
864 .insert(vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default());
865 builder = builder.push_next(next);
866 }
867
868 if capabilities.supports_extension(vk::ExtImageRobustnessFn::name()) {
869 let next = features
870 .image_robustness
871 .insert(vk::PhysicalDeviceImageRobustnessFeaturesEXT::default());
872 builder = builder.push_next(next);
873 }
874 if capabilities.supports_extension(vk::ExtRobustness2Fn::name()) {
875 let next = features
876 .robustness2
877 .insert(vk::PhysicalDeviceRobustness2FeaturesEXT::default());
878 builder = builder.push_next(next);
879 }
880 if capabilities.supports_extension(vk::ExtTextureCompressionAstcHdrFn::name()) {
881 let next = features
882 .astc_hdr
883 .insert(vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::default());
884 builder = builder.push_next(next);
885 }
886 if capabilities.supports_extension(vk::KhrShaderFloat16Int8Fn::name())
887 && capabilities.supports_extension(vk::Khr16bitStorageFn::name())
888 {
889 let next = features.shader_float16.insert((
890 vk::PhysicalDeviceShaderFloat16Int8FeaturesKHR::default(),
891 vk::PhysicalDevice16BitStorageFeaturesKHR::default(),
892 ));
893 builder = builder.push_next(&mut next.0);
894 builder = builder.push_next(&mut next.1);
895 }
896
897 if capabilities.effective_api_version >= vk::API_VERSION_1_3
899 || capabilities.supports_extension(vk::KhrZeroInitializeWorkgroupMemoryFn::name())
900 {
901 let next = features
902 .zero_initialize_workgroup_memory
903 .insert(vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures::default());
904 builder = builder.push_next(next);
905 }
906
907 let mut features2 = builder.build();
908 unsafe {
909 get_device_properties.get_physical_device_features2(phd, &mut features2);
910 }
911 features2.features
912 } else {
913 unsafe { self.raw.get_physical_device_features(phd) }
914 };
915
916 (capabilities, features)
917 }
918}
919
920impl super::Instance {
921 pub fn expose_adapter(
922 &self,
923 phd: vk::PhysicalDevice,
924 ) -> Option<crate::ExposedAdapter<super::Api>> {
925 use crate::auxil::cstr_from_bytes_until_nul;
926 use crate::auxil::db;
927
928 let (phd_capabilities, phd_features) = self.shared.inspect(phd);
929
930 let info = wgt::AdapterInfo {
931 name: {
932 cstr_from_bytes_until_nul(&phd_capabilities.properties.device_name)
933 .and_then(|info| info.to_str().ok())
934 .unwrap_or("?")
935 .to_owned()
936 },
937 vendor: phd_capabilities.properties.vendor_id,
938 device: phd_capabilities.properties.device_id,
939 device_type: match phd_capabilities.properties.device_type {
940 ash::vk::PhysicalDeviceType::OTHER => wgt::DeviceType::Other,
941 ash::vk::PhysicalDeviceType::INTEGRATED_GPU => wgt::DeviceType::IntegratedGpu,
942 ash::vk::PhysicalDeviceType::DISCRETE_GPU => wgt::DeviceType::DiscreteGpu,
943 ash::vk::PhysicalDeviceType::VIRTUAL_GPU => wgt::DeviceType::VirtualGpu,
944 ash::vk::PhysicalDeviceType::CPU => wgt::DeviceType::Cpu,
945 _ => wgt::DeviceType::Other,
946 },
947 driver: {
948 phd_capabilities
949 .driver
950 .as_ref()
951 .and_then(|driver| cstr_from_bytes_until_nul(&driver.driver_name))
952 .and_then(|name| name.to_str().ok())
953 .unwrap_or("?")
954 .to_owned()
955 },
956 driver_info: {
957 phd_capabilities
958 .driver
959 .as_ref()
960 .and_then(|driver| cstr_from_bytes_until_nul(&driver.driver_info))
961 .and_then(|name| name.to_str().ok())
962 .unwrap_or("?")
963 .to_owned()
964 },
965 backend: wgt::Backend::Vulkan,
966 };
967
968 let (available_features, downlevel_flags) =
969 phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities);
970 let mut workarounds = super::Workarounds::empty();
971 {
972 let _is_windows_intel_dual_src_bug = cfg!(windows)
974 && phd_capabilities.properties.vendor_id == db::intel::VENDOR
975 && (phd_capabilities.properties.device_id & db::intel::DEVICE_KABY_LAKE_MASK
976 == db::intel::DEVICE_KABY_LAKE_MASK
977 || phd_capabilities.properties.device_id & db::intel::DEVICE_SKY_LAKE_MASK
978 == db::intel::DEVICE_SKY_LAKE_MASK);
979 workarounds |= super::Workarounds::SEPARATE_ENTRY_POINTS;
981 workarounds.set(
982 super::Workarounds::EMPTY_RESOLVE_ATTACHMENT_LISTS,
983 phd_capabilities.properties.vendor_id == db::qualcomm::VENDOR,
984 );
985 workarounds.set(
986 super::Workarounds::FORCE_FILL_BUFFER_WITH_SIZE_GREATER_4096_ALIGNED_OFFSET_16,
987 phd_capabilities.properties.vendor_id == db::nvidia::VENDOR,
988 );
989 };
990
991 if phd_capabilities.effective_api_version == vk::API_VERSION_1_0
992 && !phd_capabilities.supports_extension(vk::KhrStorageBufferStorageClassFn::name())
993 {
994 log::warn!(
995 "SPIR-V storage buffer class is not supported, hiding adapter: {}",
996 info.name
997 );
998 return None;
999 }
1000 if !phd_capabilities.supports_extension(vk::AmdNegativeViewportHeightFn::name())
1001 && !phd_capabilities.supports_extension(vk::KhrMaintenance1Fn::name())
1002 && phd_capabilities.effective_api_version < vk::API_VERSION_1_1
1003 {
1004 log::warn!(
1005 "viewport Y-flip is not supported, hiding adapter: {}",
1006 info.name
1007 );
1008 return None;
1009 }
1010
1011 let queue_families = unsafe {
1012 self.shared
1013 .raw
1014 .get_physical_device_queue_family_properties(phd)
1015 };
1016 let queue_flags = queue_families.first()?.queue_flags;
1017 if !queue_flags.contains(vk::QueueFlags::GRAPHICS) {
1018 log::warn!("The first queue only exposes {:?}", queue_flags);
1019 return None;
1020 }
1021
1022 let private_caps = super::PrivateCapabilities {
1023 flip_y_requires_shift: phd_capabilities.effective_api_version >= vk::API_VERSION_1_1
1024 || phd_capabilities.supports_extension(vk::KhrMaintenance1Fn::name()),
1025 imageless_framebuffers: match phd_features.imageless_framebuffer {
1026 Some(features) => features.imageless_framebuffer == vk::TRUE,
1027 None => phd_features
1028 .imageless_framebuffer
1029 .map_or(false, |ext| ext.imageless_framebuffer != 0),
1030 },
1031 image_view_usage: phd_capabilities.effective_api_version >= vk::API_VERSION_1_1
1032 || phd_capabilities.supports_extension(vk::KhrMaintenance2Fn::name()),
1033 timeline_semaphores: match phd_features.timeline_semaphore {
1034 Some(features) => features.timeline_semaphore == vk::TRUE,
1035 None => phd_features
1036 .timeline_semaphore
1037 .map_or(false, |ext| ext.timeline_semaphore != 0),
1038 },
1039 texture_d24: supports_format(
1040 &self.shared.raw,
1041 phd,
1042 vk::Format::X8_D24_UNORM_PACK32,
1043 vk::ImageTiling::OPTIMAL,
1044 depth_stencil_required_flags(),
1045 ),
1046 texture_d24_s8: supports_format(
1047 &self.shared.raw,
1048 phd,
1049 vk::Format::D24_UNORM_S8_UINT,
1050 vk::ImageTiling::OPTIMAL,
1051 depth_stencil_required_flags(),
1052 ),
1053 texture_s8: supports_format(
1054 &self.shared.raw,
1055 phd,
1056 vk::Format::S8_UINT,
1057 vk::ImageTiling::OPTIMAL,
1058 depth_stencil_required_flags(),
1059 ),
1060 non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1,
1061 can_present: true,
1062 robust_buffer_access: phd_features.core.robust_buffer_access != 0,
1064 robust_image_access: match phd_features.robustness2 {
1065 Some(ref f) => f.robust_image_access2 != 0,
1066 None => phd_features
1067 .image_robustness
1068 .map_or(false, |ext| ext.robust_image_access != 0),
1069 },
1070 zero_initialize_workgroup_memory: phd_features
1071 .zero_initialize_workgroup_memory
1072 .map_or(false, |ext| {
1073 ext.shader_zero_initialize_workgroup_memory == vk::TRUE
1074 }),
1075 };
1076 let capabilities = crate::Capabilities {
1077 limits: phd_capabilities.to_wgpu_limits(),
1078 alignments: phd_capabilities.to_hal_alignments(),
1079 downlevel: wgt::DownlevelCapabilities {
1080 flags: downlevel_flags,
1081 limits: wgt::DownlevelLimits {},
1082 shader_model: wgt::ShaderModel::Sm5, },
1084 };
1085
1086 let adapter = super::Adapter {
1087 raw: phd,
1088 instance: Arc::clone(&self.shared),
1089 known_memory_flags: vk::MemoryPropertyFlags::DEVICE_LOCAL
1091 | vk::MemoryPropertyFlags::HOST_VISIBLE
1092 | vk::MemoryPropertyFlags::HOST_COHERENT
1093 | vk::MemoryPropertyFlags::HOST_CACHED
1094 | vk::MemoryPropertyFlags::LAZILY_ALLOCATED,
1095 phd_capabilities,
1096 downlevel_flags,
1098 private_caps,
1099 workarounds,
1100 };
1101
1102 Some(crate::ExposedAdapter {
1103 adapter,
1104 info,
1105 features: available_features,
1106 capabilities,
1107 })
1108 }
1109}
1110
1111impl super::Adapter {
1112 pub fn raw_physical_device(&self) -> ash::vk::PhysicalDevice {
1113 self.raw
1114 }
1115
1116 pub fn physical_device_capabilities(&self) -> &PhysicalDeviceCapabilities {
1117 &self.phd_capabilities
1118 }
1119
1120 pub fn shared_instance(&self) -> &super::InstanceShared {
1121 &self.instance
1122 }
1123
1124 pub fn required_device_extensions(&self, features: wgt::Features) -> Vec<&'static CStr> {
1125 let (supported_extensions, unsupported_extensions) = self
1126 .phd_capabilities
1127 .get_required_extensions(features)
1128 .iter()
1129 .partition::<Vec<&CStr>, _>(|&&extension| {
1130 self.phd_capabilities.supports_extension(extension)
1131 });
1132
1133 if !unsupported_extensions.is_empty() {
1134 log::warn!("Missing extensions: {:?}", unsupported_extensions);
1135 }
1136
1137 log::debug!("Supported extensions: {:?}", supported_extensions);
1138 supported_extensions
1139 }
1140
1141 pub fn physical_device_features(
1143 &self,
1144 enabled_extensions: &[&'static CStr],
1145 features: wgt::Features,
1146 ) -> PhysicalDeviceFeatures {
1147 PhysicalDeviceFeatures::from_extensions_and_requested_features(
1148 self.phd_capabilities.effective_api_version,
1149 enabled_extensions,
1150 features,
1151 self.downlevel_flags,
1152 &self.private_caps,
1153 )
1154 }
1155
1156 #[allow(clippy::too_many_arguments)]
1162 pub unsafe fn device_from_raw(
1163 &self,
1164 raw_device: ash::Device,
1165 handle_is_owned: bool,
1166 enabled_extensions: &[&'static CStr],
1167 features: wgt::Features,
1168 family_index: u32,
1169 queue_index: u32,
1170 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1171 let mem_properties = {
1172 profiling::scope!("vkGetPhysicalDeviceMemoryProperties");
1173 unsafe {
1174 self.instance
1175 .raw
1176 .get_physical_device_memory_properties(self.raw)
1177 }
1178 };
1179 let memory_types =
1180 &mem_properties.memory_types[..mem_properties.memory_type_count as usize];
1181 let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| {
1182 if self.known_memory_flags.contains(mem.property_flags) {
1183 u | (1 << i)
1184 } else {
1185 u
1186 }
1187 });
1188
1189 let swapchain_fn = khr::Swapchain::new(&self.instance.raw, &raw_device);
1190
1191 let indirect_count_fn = if enabled_extensions.contains(&khr::DrawIndirectCount::name()) {
1192 Some(khr::DrawIndirectCount::new(&self.instance.raw, &raw_device))
1193 } else {
1194 None
1195 };
1196 let timeline_semaphore_fn = if enabled_extensions.contains(&khr::TimelineSemaphore::name())
1197 {
1198 Some(super::ExtensionFn::Extension(khr::TimelineSemaphore::new(
1199 &self.instance.raw,
1200 &raw_device,
1201 )))
1202 } else if self.phd_capabilities.effective_api_version >= vk::API_VERSION_1_2 {
1203 Some(super::ExtensionFn::Promoted)
1204 } else {
1205 None
1206 };
1207
1208 let image_checks = if self.private_caps.robust_image_access {
1209 naga::proc::BoundsCheckPolicy::Unchecked
1210 } else {
1211 naga::proc::BoundsCheckPolicy::Restrict
1212 };
1213
1214 let naga_options = {
1215 use naga::back::spv;
1216
1217 let mut capabilities = vec![
1218 spv::Capability::Shader,
1219 spv::Capability::Matrix,
1220 spv::Capability::Sampled1D,
1221 spv::Capability::Image1D,
1222 spv::Capability::ImageQuery,
1223 spv::Capability::DerivativeControl,
1224 spv::Capability::SampledCubeArray,
1225 spv::Capability::SampleRateShading,
1226 spv::Capability::StorageImageExtendedFormats,
1230 ];
1232
1233 if features.contains(wgt::Features::MULTIVIEW) {
1234 capabilities.push(spv::Capability::MultiView);
1235 }
1236
1237 if features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX) {
1238 capabilities.push(spv::Capability::Geometry);
1239 }
1240
1241 if features.intersects(
1242 wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
1243 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
1244 ) {
1245 capabilities.push(spv::Capability::ShaderNonUniform);
1246 }
1247
1248 let mut flags = spv::WriterFlags::empty();
1249 flags.set(
1250 spv::WriterFlags::DEBUG,
1251 self.instance.flags.contains(crate::InstanceFlags::DEBUG),
1252 );
1253 flags.set(
1254 spv::WriterFlags::LABEL_VARYINGS,
1255 self.phd_capabilities.properties.vendor_id != crate::auxil::db::qualcomm::VENDOR,
1256 );
1257 flags.set(
1258 spv::WriterFlags::FORCE_POINT_SIZE,
1259 true, );
1264 spv::Options {
1265 lang_version: (1, 0),
1266 flags,
1267 capabilities: Some(capabilities.iter().cloned().collect()),
1268 bounds_check_policies: naga::proc::BoundsCheckPolicies {
1269 index: naga::proc::BoundsCheckPolicy::Restrict,
1270 buffer: if self.private_caps.robust_buffer_access {
1271 naga::proc::BoundsCheckPolicy::Unchecked
1272 } else {
1273 naga::proc::BoundsCheckPolicy::Restrict
1274 },
1275 image_load: image_checks,
1276 image_store: image_checks,
1277 binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
1279 },
1280 zero_initialize_workgroup_memory: if self
1281 .private_caps
1282 .zero_initialize_workgroup_memory
1283 {
1284 spv::ZeroInitializeWorkgroupMemoryMode::Native
1285 } else {
1286 spv::ZeroInitializeWorkgroupMemoryMode::Polyfill
1287 },
1288 binding_map: BTreeMap::default(),
1290 debug_info: None,
1291 }
1292 };
1293
1294 let raw_queue = {
1295 profiling::scope!("vkGetDeviceQueue");
1296 unsafe { raw_device.get_device_queue(family_index, queue_index) }
1297 };
1298
1299 let shared = Arc::new(super::DeviceShared {
1300 raw: raw_device,
1301 family_index,
1302 queue_index,
1303 raw_queue,
1304 handle_is_owned,
1305 instance: Arc::clone(&self.instance),
1306 physical_device: self.raw,
1307 enabled_extensions: enabled_extensions.into(),
1308 extension_fns: super::DeviceExtensionFunctions {
1309 draw_indirect_count: indirect_count_fn,
1310 timeline_semaphore: timeline_semaphore_fn,
1311 },
1312 vendor_id: self.phd_capabilities.properties.vendor_id,
1313 timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
1314 private_caps: self.private_caps.clone(),
1315 workarounds: self.workarounds,
1316 render_passes: Mutex::new(Default::default()),
1317 framebuffers: Mutex::new(Default::default()),
1318 });
1319 let mut relay_semaphores = [vk::Semaphore::null(); 2];
1320 for sem in relay_semaphores.iter_mut() {
1321 unsafe {
1322 *sem = shared
1323 .raw
1324 .create_semaphore(&vk::SemaphoreCreateInfo::builder(), None)?
1325 };
1326 }
1327 let queue = super::Queue {
1328 raw: raw_queue,
1329 swapchain_fn,
1330 device: Arc::clone(&shared),
1331 family_index,
1332 relay_semaphores,
1333 relay_index: None,
1334 };
1335
1336 let mem_allocator = {
1337 let limits = self.phd_capabilities.properties.limits;
1338 let config = gpu_alloc::Config::i_am_prototyping(); let max_memory_allocation_size =
1340 if let Some(maintenance_3) = self.phd_capabilities.maintenance_3 {
1341 maintenance_3.max_memory_allocation_size
1342 } else {
1343 u64::max_value()
1344 };
1345 let properties = gpu_alloc::DeviceProperties {
1346 max_memory_allocation_count: limits.max_memory_allocation_count,
1347 max_memory_allocation_size,
1348 non_coherent_atom_size: limits.non_coherent_atom_size,
1349 memory_types: memory_types
1350 .iter()
1351 .map(|memory_type| gpu_alloc::MemoryType {
1352 props: gpu_alloc::MemoryPropertyFlags::from_bits_truncate(
1353 memory_type.property_flags.as_raw() as u8,
1354 ),
1355 heap: memory_type.heap_index,
1356 })
1357 .collect(),
1358 memory_heaps: mem_properties.memory_heaps
1359 [..mem_properties.memory_heap_count as usize]
1360 .iter()
1361 .map(|&memory_heap| gpu_alloc::MemoryHeap {
1362 size: memory_heap.size,
1363 })
1364 .collect(),
1365 buffer_device_address: false,
1366 };
1367 gpu_alloc::GpuAllocator::new(config, properties)
1368 };
1369 let desc_allocator = gpu_descriptor::DescriptorAllocator::new(
1370 if let Some(di) = self.phd_capabilities.descriptor_indexing {
1371 di.max_update_after_bind_descriptors_in_all_pools
1372 } else {
1373 0
1374 },
1375 );
1376
1377 let device = super::Device {
1378 shared,
1379 mem_allocator: Mutex::new(mem_allocator),
1380 desc_allocator: Mutex::new(desc_allocator),
1381 valid_ash_memory_types,
1382 naga_options,
1383 #[cfg(feature = "renderdoc")]
1384 render_doc: Default::default(),
1385 };
1386
1387 Ok(crate::OpenDevice { device, queue })
1388 }
1389}
1390
1391impl crate::Adapter<super::Api> for super::Adapter {
1392 unsafe fn open(
1393 &self,
1394 features: wgt::Features,
1395 _limits: &wgt::Limits,
1396 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1397 let enabled_extensions = self.required_device_extensions(features);
1398 let mut enabled_phd_features = self.physical_device_features(&enabled_extensions, features);
1399
1400 let family_index = 0; let family_info = vk::DeviceQueueCreateInfo::builder()
1402 .queue_family_index(family_index)
1403 .queue_priorities(&[1.0])
1404 .build();
1405 let family_infos = [family_info];
1406
1407 let str_pointers = enabled_extensions
1408 .iter()
1409 .map(|&s| {
1410 s.as_ptr()
1412 })
1413 .collect::<Vec<_>>();
1414
1415 let pre_info = vk::DeviceCreateInfo::builder()
1416 .queue_create_infos(&family_infos)
1417 .enabled_extension_names(&str_pointers);
1418 let info = enabled_phd_features
1419 .add_to_device_create_builder(pre_info)
1420 .build();
1421 let raw_device = {
1422 profiling::scope!("vkCreateDevice");
1423 unsafe { self.instance.raw.create_device(self.raw, &info, None)? }
1424 };
1425
1426 unsafe {
1427 self.device_from_raw(
1428 raw_device,
1429 true,
1430 &enabled_extensions,
1431 features,
1432 family_info.queue_family_index,
1433 0,
1434 )
1435 }
1436 }
1437
1438 unsafe fn texture_format_capabilities(
1439 &self,
1440 format: wgt::TextureFormat,
1441 ) -> crate::TextureFormatCapabilities {
1442 use crate::TextureFormatCapabilities as Tfc;
1443
1444 let vk_format = self.private_caps.map_texture_format(format);
1445 let properties = unsafe {
1446 self.instance
1447 .raw
1448 .get_physical_device_format_properties(self.raw, vk_format)
1449 };
1450 let features = properties.optimal_tiling_features;
1451
1452 let mut flags = Tfc::empty();
1453 flags.set(
1454 Tfc::SAMPLED,
1455 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE),
1456 );
1457 flags.set(
1458 Tfc::SAMPLED_LINEAR,
1459 features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR),
1460 );
1461 flags.set(
1466 Tfc::STORAGE | Tfc::STORAGE_READ_WRITE,
1467 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE),
1468 );
1469 flags.set(
1470 Tfc::STORAGE_ATOMIC,
1471 features.contains(vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC),
1472 );
1473 flags.set(
1474 Tfc::COLOR_ATTACHMENT,
1475 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT),
1476 );
1477 flags.set(
1478 Tfc::COLOR_ATTACHMENT_BLEND,
1479 features.contains(vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND),
1480 );
1481 flags.set(
1482 Tfc::DEPTH_STENCIL_ATTACHMENT,
1483 features.contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT),
1484 );
1485 flags.set(
1486 Tfc::COPY_SRC,
1487 features.intersects(vk::FormatFeatureFlags::TRANSFER_SRC),
1488 );
1489 flags.set(
1490 Tfc::COPY_DST,
1491 features.intersects(vk::FormatFeatureFlags::TRANSFER_DST),
1492 );
1493 flags.set(Tfc::MULTISAMPLE_RESOLVE, !format.is_compressed());
1495
1496 let format_aspect = crate::FormatAspects::from(format);
1498 let limits = self.phd_capabilities.properties.limits;
1499
1500 let sample_flags = if format_aspect.contains(crate::FormatAspects::DEPTH) {
1501 limits
1502 .framebuffer_depth_sample_counts
1503 .min(limits.sampled_image_depth_sample_counts)
1504 } else if format_aspect.contains(crate::FormatAspects::STENCIL) {
1505 limits
1506 .framebuffer_stencil_sample_counts
1507 .min(limits.sampled_image_stencil_sample_counts)
1508 } else {
1509 match format.sample_type(None).unwrap() {
1510 wgt::TextureSampleType::Float { filterable: _ } => limits
1511 .framebuffer_color_sample_counts
1512 .min(limits.sampled_image_color_sample_counts),
1513 wgt::TextureSampleType::Sint | wgt::TextureSampleType::Uint => {
1514 limits.sampled_image_integer_sample_counts
1515 }
1516 _ => unreachable!(),
1517 }
1518 };
1519
1520 flags.set(
1521 Tfc::MULTISAMPLE_X2,
1522 sample_flags.contains(vk::SampleCountFlags::TYPE_2),
1523 );
1524 flags.set(
1525 Tfc::MULTISAMPLE_X4,
1526 sample_flags.contains(vk::SampleCountFlags::TYPE_4),
1527 );
1528 flags.set(
1529 Tfc::MULTISAMPLE_X8,
1530 sample_flags.contains(vk::SampleCountFlags::TYPE_8),
1531 );
1532 flags.set(
1533 Tfc::MULTISAMPLE_X16,
1534 sample_flags.contains(vk::SampleCountFlags::TYPE_16),
1535 );
1536
1537 flags
1538 }
1539
1540 unsafe fn surface_capabilities(
1541 &self,
1542 surface: &super::Surface,
1543 ) -> Option<crate::SurfaceCapabilities> {
1544 if !self.private_caps.can_present {
1545 return None;
1546 }
1547 let queue_family_index = 0; {
1549 profiling::scope!("vkGetPhysicalDeviceSurfaceSupportKHR");
1550 match unsafe {
1551 surface.functor.get_physical_device_surface_support(
1552 self.raw,
1553 queue_family_index,
1554 surface.raw,
1555 )
1556 } {
1557 Ok(true) => (),
1558 Ok(false) => return None,
1559 Err(e) => {
1560 log::error!("get_physical_device_surface_support: {}", e);
1561 return None;
1562 }
1563 }
1564 }
1565
1566 let caps = {
1567 profiling::scope!("vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
1568 match unsafe {
1569 surface
1570 .functor
1571 .get_physical_device_surface_capabilities(self.raw, surface.raw)
1572 } {
1573 Ok(caps) => caps,
1574 Err(e) => {
1575 log::error!("get_physical_device_surface_capabilities: {}", e);
1576 return None;
1577 }
1578 }
1579 };
1580
1581 let max_image_count = if caps.max_image_count == 0 {
1583 !0
1584 } else {
1585 caps.max_image_count
1586 };
1587
1588 let current_extent = if caps.current_extent.width != !0 && caps.current_extent.height != !0
1590 {
1591 Some(wgt::Extent3d {
1592 width: caps.current_extent.width,
1593 height: caps.current_extent.height,
1594 depth_or_array_layers: 1,
1595 })
1596 } else {
1597 None
1598 };
1599
1600 let min_extent = wgt::Extent3d {
1601 width: caps.min_image_extent.width,
1602 height: caps.min_image_extent.height,
1603 depth_or_array_layers: 1,
1604 };
1605
1606 let max_extent = wgt::Extent3d {
1607 width: caps.max_image_extent.width,
1608 height: caps.max_image_extent.height,
1609 depth_or_array_layers: caps.max_image_array_layers,
1610 };
1611
1612 let raw_present_modes = {
1613 profiling::scope!("vkGetPhysicalDeviceSurfacePresentModesKHR");
1614 match unsafe {
1615 surface
1616 .functor
1617 .get_physical_device_surface_present_modes(self.raw, surface.raw)
1618 } {
1619 Ok(present_modes) => present_modes,
1620 Err(e) => {
1621 log::error!("get_physical_device_surface_present_modes: {}", e);
1622 Vec::new()
1623 }
1624 }
1625 };
1626
1627 let raw_surface_formats = {
1628 profiling::scope!("vkGetPhysicalDeviceSurfaceFormatsKHR");
1629 match unsafe {
1630 surface
1631 .functor
1632 .get_physical_device_surface_formats(self.raw, surface.raw)
1633 } {
1634 Ok(formats) => formats,
1635 Err(e) => {
1636 log::error!("get_physical_device_surface_formats: {}", e);
1637 Vec::new()
1638 }
1639 }
1640 };
1641
1642 let formats = raw_surface_formats
1643 .into_iter()
1644 .filter_map(conv::map_vk_surface_formats)
1645 .collect();
1646 Some(crate::SurfaceCapabilities {
1647 formats,
1648 swap_chain_sizes: caps.min_image_count..=max_image_count,
1649 current_extent,
1650 extents: min_extent..=max_extent,
1651 usage: conv::map_vk_image_usage(caps.supported_usage_flags),
1652 present_modes: raw_present_modes
1653 .into_iter()
1654 .flat_map(conv::map_vk_present_mode)
1655 .collect(),
1656 composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha),
1657 })
1658 }
1659
1660 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
1661 #[cfg(unix)]
1666 {
1667 let mut timespec = libc::timespec {
1668 tv_sec: 0,
1669 tv_nsec: 0,
1670 };
1671 unsafe {
1672 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut timespec);
1673 }
1674
1675 wgt::PresentationTimestamp(
1676 timespec.tv_sec as u128 * 1_000_000_000 + timespec.tv_nsec as u128,
1677 )
1678 }
1679 #[cfg(not(unix))]
1680 {
1681 wgt::PresentationTimestamp::INVALID_TIMESTAMP
1682 }
1683 }
1684}
1685
1686fn is_format_16bit_norm_supported(instance: &ash::Instance, phd: vk::PhysicalDevice) -> bool {
1687 let tiling = vk::ImageTiling::OPTIMAL;
1688 let features = vk::FormatFeatureFlags::SAMPLED_IMAGE
1689 | vk::FormatFeatureFlags::STORAGE_IMAGE
1690 | vk::FormatFeatureFlags::TRANSFER_SRC
1691 | vk::FormatFeatureFlags::TRANSFER_DST;
1692 let r16unorm = supports_format(instance, phd, vk::Format::R16_UNORM, tiling, features);
1693 let r16snorm = supports_format(instance, phd, vk::Format::R16_SNORM, tiling, features);
1694 let rg16unorm = supports_format(instance, phd, vk::Format::R16G16_UNORM, tiling, features);
1695 let rg16snorm = supports_format(instance, phd, vk::Format::R16G16_SNORM, tiling, features);
1696 let rgba16unorm = supports_format(
1697 instance,
1698 phd,
1699 vk::Format::R16G16B16A16_UNORM,
1700 tiling,
1701 features,
1702 );
1703 let rgba16snorm = supports_format(
1704 instance,
1705 phd,
1706 vk::Format::R16G16B16A16_SNORM,
1707 tiling,
1708 features,
1709 );
1710
1711 r16unorm && r16snorm && rg16unorm && rg16snorm && rgba16unorm && rgba16snorm
1712}
1713
1714fn supports_format(
1715 instance: &ash::Instance,
1716 phd: vk::PhysicalDevice,
1717 format: vk::Format,
1718 tiling: vk::ImageTiling,
1719 features: vk::FormatFeatureFlags,
1720) -> bool {
1721 let properties = unsafe { instance.get_physical_device_format_properties(phd, format) };
1722 match tiling {
1723 vk::ImageTiling::LINEAR => properties.linear_tiling_features.contains(features),
1724 vk::ImageTiling::OPTIMAL => properties.optimal_tiling_features.contains(features),
1725 _ => false,
1726 }
1727}