1use super::*;
2
3pub struct Device {
4 device: vulk::Device,
5 queue: vk::Queue,
6 queue_family_index: u32,
7 queue_family_properties: vk::QueueFamilyProperties,
8 pub(crate) command_pool: vk::CommandPool,
9}
10
11impl std::fmt::Debug for Device {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 f.debug_struct("Device")
14 .field("device", &"Device {..}")
15 .field("queue", &self.queue)
16 .field("queue_family_index", &self.queue_family_index)
17 .field("queue_family_properties", &self.queue_family_properties)
18 .field("command_pool", &self.command_pool)
19 .finish()
20 }
21}
22
23#[derive(Debug)]
24pub struct TimestampCalibration {
25 pub host_domain: u64,
27 pub device_domain: u64,
28 pub max_deviation: u64,
29}
30
31impl Device {
32 pub unsafe fn create(
33 instance: &Instance,
34 physical_device: &PhysicalDevice,
35 surface: Option<&Surface>,
36 ) -> Result<Self> {
37 let (queue_family_index, queue_family_properties) = physical_device
39 .queue_family_properties
40 .iter()
41 .copied()
42 .enumerate()
43 .find_map(|(queue_family_index, queue_family_properties)| {
44 if let Some(surface) = surface {
46 let present_supported = instance
47 .get_physical_device_surface_support_khr(
48 physical_device.handle(),
49 queue_family_index as _,
50 surface.handle(),
51 )
52 .unwrap();
53 if present_supported != vk::TRUE {
54 return None;
55 }
56 }
57
58 if queue_family_properties.queue_flags.contains(
60 vk::QueueFlagBits::Graphics
61 | vk::QueueFlagBits::Compute
62 | vk::QueueFlagBits::Transfer,
63 ) {
64 Some((queue_family_index as u32, queue_family_properties))
65 } else {
66 None
67 }
68 })
69 .context("Finding compatible queue families")?;
70
71 let mut physical_device_ray_tracing_maintenance1_features_khr =
73 vk::PhysicalDeviceRayTracingMaintenance1FeaturesKHR {
74 s_type: vk::StructureType::PhysicalDeviceRayTracingMaintenance1FeaturesKHR,
75 p_next: null_mut(),
76 ray_tracing_maintenance1: vk::TRUE,
77 ray_tracing_pipeline_trace_rays_indirect2: vk::TRUE,
78 };
79 let mut physical_device_acceleration_structure_features_khr =
80 vk::PhysicalDeviceAccelerationStructureFeaturesKHR {
81 s_type: vk::StructureType::PhysicalDeviceAccelerationStructureFeaturesKHR,
82 p_next: addr_of_mut!(physical_device_ray_tracing_maintenance1_features_khr).cast(),
83 acceleration_structure: vk::TRUE,
84 acceleration_structure_capture_replay: vk::FALSE,
85 acceleration_structure_indirect_build: vk::FALSE,
86 acceleration_structure_host_commands: vk::FALSE,
87 descriptor_binding_acceleration_structure_update_after_bind: vk::FALSE,
88 };
89 let mut physical_device_ray_tracing_pipeline_features_khr =
90 vk::PhysicalDeviceRayTracingPipelineFeaturesKHR {
91 s_type: vk::StructureType::PhysicalDeviceRayTracingPipelineFeaturesKHR,
92 p_next: addr_of_mut!(physical_device_acceleration_structure_features_khr).cast(),
93 ray_tracing_pipeline: vk::TRUE,
94 ray_tracing_pipeline_shader_group_handle_capture_replay: vk::FALSE,
95 ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: vk::FALSE,
96 ray_tracing_pipeline_trace_rays_indirect: vk::TRUE,
97 ray_traversal_primitive_culling: vk::TRUE,
98 };
99 let mut physical_device_ray_query_features_khr = vk::PhysicalDeviceRayQueryFeaturesKHR {
100 s_type: vk::StructureType::PhysicalDeviceRayQueryFeaturesKHR,
101 p_next: addr_of_mut!(physical_device_ray_tracing_pipeline_features_khr).cast(),
102 ray_query: vk::TRUE,
103 };
104 let mut physical_device_mesh_shader_features_ext =
105 vk::PhysicalDeviceMeshShaderFeaturesEXT {
106 s_type: vk::StructureType::PhysicalDeviceMeshShaderFeaturesEXT,
107 p_next: addr_of_mut!(physical_device_ray_query_features_khr).cast(),
108 task_shader: vk::TRUE,
109 mesh_shader: vk::TRUE,
110 multiview_mesh_shader: vk::FALSE,
111 primitive_fragment_shading_rate_mesh_shader: vk::FALSE,
112 mesh_shader_queries: vk::TRUE,
113 };
114 let mut physical_device_shader_object_features_ext =
115 vk::PhysicalDeviceShaderObjectFeaturesEXT {
116 s_type: vk::StructureType::PhysicalDeviceShaderObjectFeaturesEXT,
117 p_next: addr_of_mut!(physical_device_mesh_shader_features_ext).cast(),
118 shader_object: vk::TRUE,
119 };
120 let mut physical_device_descriptor_buffer_features_ext =
121 vk::PhysicalDeviceDescriptorBufferFeaturesEXT {
122 s_type: vk::StructureType::PhysicalDeviceDescriptorBufferFeaturesEXT,
123 p_next: addr_of_mut!(physical_device_shader_object_features_ext).cast(),
124 descriptor_buffer: vk::TRUE,
125 descriptor_buffer_capture_replay: vk::FALSE,
126 descriptor_buffer_image_layout_ignored: vk::FALSE,
127 descriptor_buffer_push_descriptors: vk::FALSE,
128 };
129 let mut physical_device_vulkan13_features = vk::PhysicalDeviceVulkan13Features {
130 s_type: vk::StructureType::PhysicalDeviceVulkan13Features,
131 p_next: addr_of_mut!(physical_device_descriptor_buffer_features_ext).cast(),
132 robust_image_access: vk::FALSE,
133 inline_uniform_block: vk::FALSE,
134 descriptor_binding_inline_uniform_block_update_after_bind: vk::FALSE,
135 pipeline_creation_cache_control: vk::FALSE,
136 private_data: vk::FALSE,
137 shader_demote_to_helper_invocation: vk::FALSE,
138 shader_terminate_invocation: vk::FALSE,
139 subgroup_size_control: vk::FALSE,
140 compute_full_subgroups: vk::FALSE,
141 synchronization2: vk::TRUE,
142 texture_compression_astc_hdr: vk::FALSE,
143 shader_zero_initialize_workgroup_memory: vk::FALSE,
144 dynamic_rendering: vk::TRUE,
145 shader_integer_dot_product: vk::FALSE,
146 maintenance4: vk::FALSE,
147 };
148 let mut physical_device_vulkan12_features = vk::PhysicalDeviceVulkan12Features {
149 s_type: vk::StructureType::PhysicalDeviceVulkan12Features,
150 p_next: addr_of_mut!(physical_device_vulkan13_features).cast(),
151 sampler_mirror_clamp_to_edge: vk::FALSE,
152 draw_indirect_count: vk::FALSE,
153 storage_buffer8_bit_access: vk::FALSE,
154 uniform_and_storage_buffer8_bit_access: vk::FALSE,
155 storage_push_constant8: vk::FALSE,
156 shader_buffer_int64_atomics: vk::TRUE,
157 shader_shared_int64_atomics: vk::FALSE,
158 shader_float16: vk::FALSE,
159 shader_int8: vk::FALSE,
160 descriptor_indexing: vk::TRUE,
161 shader_input_attachment_array_dynamic_indexing: vk::FALSE,
162 shader_uniform_texel_buffer_array_dynamic_indexing: vk::FALSE,
163 shader_storage_texel_buffer_array_dynamic_indexing: vk::FALSE,
164 shader_uniform_buffer_array_non_uniform_indexing: vk::FALSE,
165 shader_sampled_image_array_non_uniform_indexing: vk::FALSE,
166 shader_storage_buffer_array_non_uniform_indexing: vk::FALSE,
167 shader_storage_image_array_non_uniform_indexing: vk::FALSE,
168 shader_input_attachment_array_non_uniform_indexing: vk::FALSE,
169 shader_uniform_texel_buffer_array_non_uniform_indexing: vk::FALSE,
170 shader_storage_texel_buffer_array_non_uniform_indexing: vk::FALSE,
171 descriptor_binding_uniform_buffer_update_after_bind: vk::FALSE,
172 descriptor_binding_sampled_image_update_after_bind: vk::FALSE,
173 descriptor_binding_storage_image_update_after_bind: vk::FALSE,
174 descriptor_binding_storage_buffer_update_after_bind: vk::FALSE,
175 descriptor_binding_uniform_texel_buffer_update_after_bind: vk::FALSE,
176 descriptor_binding_storage_texel_buffer_update_after_bind: vk::FALSE,
177 descriptor_binding_update_unused_while_pending: vk::FALSE,
178 descriptor_binding_partially_bound: vk::FALSE,
179 descriptor_binding_variable_descriptor_count: vk::FALSE,
180 runtime_descriptor_array: vk::FALSE,
181 sampler_filter_minmax: vk::FALSE,
182 scalar_block_layout: vk::TRUE,
183 imageless_framebuffer: vk::FALSE,
184 uniform_buffer_standard_layout: vk::FALSE,
185 shader_subgroup_extended_types: vk::FALSE,
186 separate_depth_stencil_layouts: vk::FALSE,
187 host_query_reset: vk::TRUE,
188 timeline_semaphore: vk::TRUE,
189 buffer_device_address: vk::TRUE,
190 buffer_device_address_capture_replay: vk::FALSE,
191 buffer_device_address_multi_device: vk::FALSE,
192 vulkan_memory_model: vk::FALSE,
193 vulkan_memory_model_device_scope: vk::FALSE,
194 vulkan_memory_model_availability_visibility_chains: vk::FALSE,
195 shader_output_viewport_index: vk::FALSE,
196 shader_output_layer: vk::FALSE,
197 subgroup_broadcast_dynamic_id: vk::FALSE,
198 };
199 let mut physical_device_vulkan11_features = vk::PhysicalDeviceVulkan11Features {
200 s_type: vk::StructureType::PhysicalDeviceVulkan11Features,
201 p_next: addr_of_mut!(physical_device_vulkan12_features).cast(),
202 storage_buffer16_bit_access: vk::TRUE,
203 uniform_and_storage_buffer16_bit_access: vk::TRUE,
204 storage_push_constant16: vk::TRUE,
205 storage_input_output16: vk::FALSE,
206 multiview: vk::FALSE,
207 multiview_geometry_shader: vk::FALSE,
208 multiview_tessellation_shader: vk::FALSE,
209 variable_pointers_storage_buffer: vk::FALSE,
210 variable_pointers: vk::FALSE,
211 protected_memory: vk::FALSE,
212 sampler_ycbcr_conversion: vk::FALSE,
213 shader_draw_parameters: vk::FALSE,
214 };
215 let physical_device_features2 = vk::PhysicalDeviceFeatures2 {
216 s_type: vk::StructureType::PhysicalDeviceFeatures2,
217 p_next: addr_of_mut!(physical_device_vulkan11_features).cast(),
218 features: vk::PhysicalDeviceFeatures {
219 robust_buffer_access: vk::FALSE,
220 full_draw_index_uint32: vk::FALSE,
221 image_cube_array: vk::FALSE,
222 independent_blend: vk::FALSE,
223 geometry_shader: vk::FALSE,
224 tessellation_shader: vk::FALSE,
225 sample_rate_shading: vk::FALSE,
226 dual_src_blend: vk::FALSE,
227 logic_op: vk::FALSE,
228 multi_draw_indirect: vk::FALSE,
229 draw_indirect_first_instance: vk::FALSE,
230 depth_clamp: vk::FALSE,
231 depth_bias_clamp: vk::FALSE,
232 fill_mode_non_solid: vk::FALSE,
233 depth_bounds: vk::FALSE,
234 wide_lines: vk::FALSE,
235 large_points: vk::FALSE,
236 alpha_to_one: vk::FALSE,
237 multi_viewport: vk::FALSE,
238 sampler_anisotropy: vk::FALSE,
239 texture_compression_etc2: vk::FALSE,
240 texture_compression_astc_ldr: vk::FALSE,
241 texture_compression_bc: vk::FALSE,
242 occlusion_query_precise: vk::FALSE,
243 pipeline_statistics_query: vk::TRUE,
244 vertex_pipeline_stores_and_atomics: vk::FALSE,
245 fragment_stores_and_atomics: vk::FALSE,
246 shader_tessellation_and_geometry_point_size: vk::FALSE,
247 shader_image_gather_extended: vk::FALSE,
248 shader_storage_image_extended_formats: vk::FALSE,
249 shader_storage_image_multisample: vk::FALSE,
250 shader_storage_image_read_without_format: vk::FALSE,
251 shader_storage_image_write_without_format: vk::FALSE,
252 shader_uniform_buffer_array_dynamic_indexing: vk::FALSE,
253 shader_sampled_image_array_dynamic_indexing: vk::FALSE,
254 shader_storage_buffer_array_dynamic_indexing: vk::FALSE,
255 shader_storage_image_array_dynamic_indexing: vk::FALSE,
256 shader_clip_distance: vk::FALSE,
257 shader_cull_distance: vk::FALSE,
258 shader_float64: vk::FALSE,
259 shader_int64: vk::TRUE,
260 shader_int16: vk::TRUE,
261 shader_resource_residency: vk::FALSE,
262 shader_resource_min_lod: vk::FALSE,
263 sparse_binding: vk::FALSE,
264 sparse_residency_buffer: vk::FALSE,
265 sparse_residency_image_2d: vk::FALSE,
266 sparse_residency_image_3d: vk::FALSE,
267 sparse_residency2_samples: vk::FALSE,
268 sparse_residency4_samples: vk::FALSE,
269 sparse_residency8_samples: vk::FALSE,
270 sparse_residency16_samples: vk::FALSE,
271 sparse_residency_aliased: vk::FALSE,
272 variable_multisample_rate: vk::FALSE,
273 inherited_queries: vk::FALSE,
274 },
275 };
276
277 let mut enabled_extension_names = vec![];
279 enabled_extension_names.extend_from_slice(&vulk::REQUIRED_DEVICE_EXTENSIONS);
280 if instance.validation_layers() {
281 enabled_extension_names.extend_from_slice(&vulk::DEBUGGING_DEVICE_EXTENSIONS);
282 }
283 if cfg!(windows) {
284 enabled_extension_names.extend_from_slice(&vulk::WIN32_DEVICE_EXTENSIONS);
285 }
286
287 let device = instance.create_device(
289 physical_device.handle(),
290 &vk::DeviceCreateInfo {
291 s_type: vk::StructureType::DeviceCreateInfo,
292 p_next: addr_of!(physical_device_features2).cast(),
293 flags: vk::DeviceCreateFlags::empty(),
294 queue_create_info_count: 1,
295 p_queue_create_infos: &vk::DeviceQueueCreateInfo {
296 s_type: vk::StructureType::DeviceQueueCreateInfo,
297 p_next: null(),
298 flags: vk::DeviceQueueCreateFlags::empty(),
299 queue_family_index,
300 queue_count: 1,
301 p_queue_priorities: [1.0].as_ptr(),
302 },
303 enabled_layer_count: 0,
304 pp_enabled_layer_names: null(),
305 enabled_extension_count: enabled_extension_names.len() as _,
306 pp_enabled_extension_names: enabled_extension_names.as_ptr(),
307 p_enabled_features: null(),
308 },
309 )?;
310 let device = vulk::Device::load(instance, device)?;
311
312 let queue = device.get_device_queue2(&vk::DeviceQueueInfo2 {
314 s_type: vk::StructureType::DeviceQueueInfo2,
315 p_next: null(),
316 flags: vk::DeviceQueueCreateFlags::empty(),
317 queue_family_index,
318 queue_index: 0,
319 });
320
321 let command_pool = device.create_command_pool(&vk::CommandPoolCreateInfo {
323 s_type: vk::StructureType::CommandPoolCreateInfo,
324 p_next: null(),
325 flags: vk::CommandPoolCreateFlagBits::ResetCommandBuffer.into(),
326 queue_family_index,
327 })?;
328
329 let time_domains = vulk::read_to_vec(
331 |count, ptr| {
332 instance.get_physical_device_calibrateable_time_domains_ext(
333 physical_device.handle(),
334 count,
335 ptr,
336 )
337 },
338 None,
339 )?;
340 let supports_host_domain = time_domains.iter().any(|td| {
341 matches!(
342 *td,
343 vk::TimeDomainEXT::ClockMonotonicEXT
344 | vk::TimeDomainEXT::QueryPerformanceCounterEXT
345 )
346 });
347 ensure!(supports_host_domain);
348 let supports_device_domain = time_domains
349 .iter()
350 .any(|td| matches!(*td, vk::TimeDomainEXT::DeviceEXT));
351 ensure!(supports_device_domain);
352
353 Ok(Self {
354 device,
355 queue,
356 queue_family_index,
357 queue_family_properties,
358 command_pool,
359 })
360 }
361
362 pub unsafe fn destroy(self) {
363 self.device.destroy_command_pool(self.command_pool);
364 self.device.destroy_device();
365 }
366
367 #[must_use]
368 pub fn queue_handle(&self) -> vk::Queue {
369 self.queue
370 }
371
372 #[must_use]
373 pub fn queue_family_index(&self) -> u32 {
374 self.queue_family_index
375 }
376
377 #[must_use]
378 pub fn queue_family_properties(&self) -> vk::QueueFamilyProperties {
379 self.queue_family_properties
380 }
381
382 pub unsafe fn timestamp_calibration(&self) -> Result<TimestampCalibration> {
383 let calibrated_timestamp_info_ext = [
384 vk::CalibratedTimestampInfoEXT {
385 s_type: vk::StructureType::CalibratedTimestampInfoEXT,
386 p_next: null(),
387 time_domain: vk::TimeDomainEXT::ClockMonotonicEXT,
388 },
389 vk::CalibratedTimestampInfoEXT {
390 s_type: vk::StructureType::CalibratedTimestampInfoEXT,
391 p_next: null(),
392 time_domain: vk::TimeDomainEXT::DeviceEXT,
393 },
394 ];
395 let mut timestamps = [0_u64; 2];
396 let mut max_deviation = 0;
397 self.device.get_calibrated_timestamps_ext(
398 calibrated_timestamp_info_ext.len() as _,
399 calibrated_timestamp_info_ext.as_ptr(),
400 timestamps.as_mut_ptr(),
401 &mut max_deviation,
402 )?;
403 let host_domain = timestamps[0];
404 let device_domain = timestamps[1];
405 Ok(TimestampCalibration {
406 host_domain,
407 device_domain,
408 max_deviation,
409 })
410 }
411}
412
413impl std::ops::Deref for Device {
414 type Target = vulk::Device;
415
416 fn deref(&self) -> &Self::Target {
417 &self.device
418 }
419}