vulk_ext/vkx/
device.rs

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    // On Posix, host_domain seems to match machine uptime.
26    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        // Find compatible queue family.
38        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                // Present support.
45                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                // Queue capabilities.
59                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        // Required features.
72        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        // Extensions.
278        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        // Device.
288        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        // Queue.
313        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        // Command pool.
322        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        // Timestamp calibration support.
330        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}