1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::graphics::vulkan::{
device::QueueFamilyIndices, Instance, WindowSurface,
};
use anyhow::{Context, Result};
use ash::{version::InstanceV1_0, vk};
pub fn find_optimal(
instance: &Instance,
window_surface: &dyn WindowSurface,
) -> Result<vk::PhysicalDevice> {
let physical_devices =
unsafe { instance.ash.enumerate_physical_devices()? };
let physical_device = physical_devices
.iter()
.find(|device| is_device_suitable(&instance, device, window_surface))
.context("unable to pick a suitable device")?;
Ok(*physical_device)
}
fn is_device_suitable(
instance: &Instance,
physical_device: &vk::PhysicalDevice,
window_surface: &dyn WindowSurface,
) -> bool {
let queues_supported = QueueFamilyIndices::find(
physical_device,
&instance.ash,
window_surface,
)
.is_ok();
let features =
unsafe { instance.ash.get_physical_device_features(*physical_device) };
let extensions_supported =
check_required_extensions(&instance, physical_device);
let format_available = if extensions_supported {
unsafe { !window_surface.supported_formats(physical_device).is_empty() }
} else {
false
};
let presentation_mode_available = if extensions_supported {
unsafe {
!window_surface
.supported_presentation_modes(physical_device)
.is_empty()
}
} else {
false
};
queues_supported
&& extensions_supported
&& format_available
&& presentation_mode_available
&& features.geometry_shader == vk::TRUE
}
fn check_required_extensions(
instance: &Instance,
physical_device: &vk::PhysicalDevice,
) -> bool {
let extensions = unsafe {
instance
.ash
.enumerate_device_extension_properties(*physical_device)
.unwrap_or_else(|_| vec![])
};
extensions
.iter()
.map(|extension| {
String::from_utf8(
extension.extension_name.iter().map(|c| *c as u8).collect(),
)
.unwrap()
})
.filter(|name| required_extensions().contains(name))
.collect::<Vec<String>>()
.is_empty()
}
pub fn required_features() -> vk::PhysicalDeviceFeatures {
vk::PhysicalDeviceFeatures {
geometry_shader: 1,
..Default::default()
}
}
pub fn required_extensions() -> Vec<String> {
let swapchain = ash::extensions::khr::Swapchain::name()
.to_owned()
.into_string()
.unwrap();
vec![swapchain]
}