//! The raw Vulkan half of the probe. //! //! wgpu reports a feature only after a chain of its own decisions -- which //! physical device, which API version, which extension list -- so "wgpu says //! no" and "the driver says no" are different claims. This asks //! `vkGetPhysicalDeviceFeatures2` itself and prints the inputs to that chain, //! so a disagreement can be attributed rather than guessed at. use ash::{Entry, vk}; use std::ffi::CStr; pub fn report() { let entry = match unsafe { Entry::load() } { Ok(e) => e, Err(e) => { println!("\nraw vulkan: cannot load loader -- {e}"); return; } }; let instance_version = match unsafe { entry.try_enumerate_instance_version() } { Ok(Some(v)) => v, Ok(None) => vk::API_VERSION_1_0, Err(e) => { println!("\nraw vulkan: enumerate_instance_version failed -- {e}"); return; } }; println!("\nraw vulkan:"); println!(" loader instance version: {}", ver(instance_version)); // Ask for the highest instance version the loader admits to: wgpu clamps // the device version by the instance's, so an instance created at 1.0 // makes a 1.3 device look like 1.0. let app_info = vk::ApplicationInfo::default().api_version(instance_version); let create = vk::InstanceCreateInfo::default().application_info(&app_info); let instance = match unsafe { entry.create_instance(&create, None) } { Ok(i) => i, Err(e) => { println!(" create_instance failed -- {e}"); return; } }; let devices = unsafe { instance.enumerate_physical_devices() }.unwrap_or_default(); for phd in devices { let props = unsafe { instance.get_physical_device_properties(phd) }; let name = unsafe { CStr::from_ptr(props.device_name.as_ptr()) }; println!(" device: {}", name.to_string_lossy()); println!(" device api version: {}", ver(props.api_version)); let exts = unsafe { instance.enumerate_device_extension_properties(phd) }.unwrap_or_default(); let has_ext = exts.iter().any(|e| { (unsafe { CStr::from_ptr(e.extension_name.as_ptr()) }) == c"VK_EXT_descriptor_indexing" }); println!(" VK_EXT_descriptor_indexing advertised: {has_ext}"); println!(" device extensions: {}", exts.len()); let mut indexing = vk::PhysicalDeviceDescriptorIndexingFeatures::default(); let mut features2 = vk::PhysicalDeviceFeatures2::default().push_next(&mut indexing); unsafe { instance.get_physical_device_features2(phd, &mut features2) }; for (name, v) in [ ( "shaderSampledImageArrayNonUniformIndexing", indexing.shader_sampled_image_array_non_uniform_indexing, ), ( "descriptorBindingSampledImageUpdateAfterBind", indexing.descriptor_binding_sampled_image_update_after_bind, ), ( "shaderStorageImageArrayNonUniformIndexing", indexing.shader_storage_image_array_non_uniform_indexing, ), ( "descriptorBindingStorageImageUpdateAfterBind", indexing.descriptor_binding_storage_image_update_after_bind, ), ( "shaderStorageBufferArrayNonUniformIndexing", indexing.shader_storage_buffer_array_non_uniform_indexing, ), ( "descriptorBindingStorageBufferUpdateAfterBind", indexing.descriptor_binding_storage_buffer_update_after_bind, ), ( "descriptorBindingPartiallyBound", indexing.descriptor_binding_partially_bound, ), ] { println!(" {name:48} {}", if v != 0 { "yes" } else { "NO" }); } } unsafe { instance.destroy_instance(None) }; } fn ver(v: u32) -> String { format!( "{}.{}.{}", vk::api_version_major(v), vk::api_version_minor(v), vk::api_version_patch(v) ) }