demo_vk/graphics/vulkan/context/
mod.rs

1mod instance;
2mod logical_device;
3mod physical_device;
4
5use {
6    crate::{
7        graphics::vulkan::{raii, Allocator},
8        trace,
9    },
10    anyhow::{Context, Result},
11    ash::vk::{self},
12    std::sync::Arc,
13};
14
15pub use self::instance::Instance;
16
17/// Holds all of the device features structs which can be used when creating a
18/// VulkanContext.
19///
20/// Note: None of the pnext pointers should be specified in these structures.
21///       The relevant pnext chain will be assembled on-demand when calling
22///       into Vulkan and never before.
23#[derive(Debug, Default)]
24pub struct RequiredDeviceFeatures {
25    pub physical_device_features: vk::PhysicalDeviceFeatures,
26    pub physical_device_vulkan12_features:
27        vk::PhysicalDeviceVulkan12Features<'static>,
28    pub physical_device_dynamic_rendering_features:
29        vk::PhysicalDeviceDynamicRenderingFeatures<'static>,
30}
31
32/// The Vulkan context is the logical handle for all Vulkan operations within
33/// the app.
34///
35/// It supports finding and using a single logical device along with all
36/// required queues and a device memory allocator.
37pub struct VulkanContext {
38    pub instance: Instance,
39    pub surface_khr: Arc<raii::Surface>,
40    pub physical_device: vk::PhysicalDevice,
41    pub device: Arc<raii::Device>,
42
43    /// The queue family index for the graphics + present queue.
44    pub graphics_queue_family_index: u32,
45
46    /// The graphics queue supports GRAPHICS and presentation operations.
47    pub graphics_queue: vk::Queue,
48
49    /// The device memory allocator.
50    pub allocator: Arc<Allocator>,
51}
52
53impl VulkanContext {
54    /// Creates a new Vulkan Context for the first suitable device that supports
55    /// presenting to the GLFW window surface.
56    pub fn new(
57        window: &glfw::Window,
58        required_device_features: RequiredDeviceFeatures,
59    ) -> Result<Arc<Self>> {
60        let instance = Instance::for_window("Shader-Toy-Slang", window)
61            .with_context(trace!("Unable to create vulkan instance!"))?;
62
63        let surface_khr =
64            raii::Surface::for_window(instance.ash.clone(), window)
65                .with_context(trace!(
66                    "Unable to create Vulkan surface from glfw window!"
67                ))?;
68
69        let physical_device = physical_device::pick_suitable_device(
70            &instance,
71            &surface_khr,
72            &required_device_features,
73        )
74        .with_context(trace!(
75            "Error while picking a suitable physical device!"
76        ))?;
77
78        let (device, graphics_queue_family_index) =
79            logical_device::create_logical_device(
80                &instance,
81                &surface_khr,
82                physical_device,
83                required_device_features,
84            )
85            .with_context(trace!("Error while creating the logical device!"))?;
86
87        let graphics_queue =
88            unsafe { device.get_device_queue(graphics_queue_family_index, 0) };
89
90        let allocator = Allocator::new(device.clone(), physical_device)
91            .with_context(trace!(
92                "Error while creating device memory allocator!"
93            ))?;
94
95        Ok(Arc::new(Self {
96            instance,
97            surface_khr,
98            physical_device,
99            device,
100            graphics_queue_family_index,
101            graphics_queue,
102            allocator: Arc::new(allocator),
103        }))
104    }
105}
106
107impl std::ops::Deref for VulkanContext {
108    type Target = ash::Device;
109
110    fn deref(&self) -> &Self::Target {
111        &self.device.raw
112    }
113}
114
115impl std::fmt::Debug for VulkanContext {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.debug_struct("VulkanContext")
118            .field("instance", &self.instance)
119            .field("surface_khr", &self.surface_khr)
120            .field("physical_device", &self.physical_device)
121            .field("device", &self.device)
122            .field(
123                "graphics_queue_family_index",
124                &self.graphics_queue_family_index,
125            )
126            .field("graphics_queue", &self.graphics_queue)
127            .finish()
128    }
129}