use ash::vk;
pub(in crate::vulkan) struct TestGpu {
pub device: ash::Device,
pub instance: ash::Instance,
pub physical_device: vk::PhysicalDevice,
_entry: ash::Entry,
}
impl Drop for TestGpu {
fn drop(&mut self) {
unsafe {
self.device.destroy_device(None);
self.instance.destroy_instance(None);
}
}
}
pub(in crate::vulkan) fn test_gpu() -> Option<TestGpu> {
let gpu = test_gpu_impl(false);
if gpu.is_none() {
eprintln!("skipped: no Vulkan driver");
}
gpu
}
pub(in crate::vulkan) fn test_gpu_with_device_address() -> Option<TestGpu> {
let gpu = test_gpu_impl(true);
if gpu.is_none() {
eprintln!("skipped: no bufferDeviceAddress-capable Vulkan driver");
}
gpu
}
fn test_gpu_impl(device_address: bool) -> Option<TestGpu> {
let entry = crate::vulkan::loader::load_entry().ok()?;
let app = vk::ApplicationInfo::default().api_version(if device_address {
vk::API_VERSION_1_2
} else {
vk::API_VERSION_1_0
});
let instance = unsafe {
entry.create_instance(
&vk::InstanceCreateInfo::default().application_info(&app),
None,
)
}
.ok()?;
let destroy_instance = |instance: ash::Instance| {
unsafe { instance.destroy_instance(None) };
None
};
let physical_device = match unsafe { instance.enumerate_physical_devices() } {
Ok(devices) if !devices.is_empty() => devices[0],
_ => return destroy_instance(instance),
};
let mut enable = vk::PhysicalDeviceBufferDeviceAddressFeatures::default();
if device_address {
let props = unsafe { instance.get_physical_device_properties(physical_device) };
if props.api_version < vk::API_VERSION_1_2 {
return destroy_instance(instance);
}
let mut bda = vk::PhysicalDeviceBufferDeviceAddressFeatures::default();
let mut feats = vk::PhysicalDeviceFeatures2::default().push_next(&mut bda);
unsafe { instance.get_physical_device_features2(physical_device, &mut feats) };
if bda.buffer_device_address == 0 {
return destroy_instance(instance);
}
enable = enable.buffer_device_address(true);
}
let queue_infos = [vk::DeviceQueueCreateInfo::default()
.queue_family_index(0)
.queue_priorities(&[1.0])];
let mut device_info = vk::DeviceCreateInfo::default().queue_create_infos(&queue_infos);
if device_address {
device_info = device_info.push_next(&mut enable);
}
let device = match unsafe { instance.create_device(physical_device, &device_info, None) } {
Ok(device) => device,
Err(_) => return destroy_instance(instance),
};
Some(TestGpu {
device,
instance,
physical_device,
_entry: entry,
})
}