demo_vk/graphics/vulkan/
sync_commands.rs

1use {
2    crate::{
3        graphics::vulkan::{raii, VulkanContext},
4        unwrap_here,
5    },
6    anyhow::Result,
7    ash::vk,
8    std::sync::Arc,
9};
10
11/// A utility for synchronously submitting commands to the GPU.
12#[derive(Debug)]
13pub struct SyncCommands {
14    command_pool: raii::CommandPool,
15    command_buffer: vk::CommandBuffer,
16    fence: raii::Fence,
17    cxt: Arc<VulkanContext>,
18}
19
20impl SyncCommands {
21    pub fn new(cxt: Arc<VulkanContext>) -> Result<Self> {
22        let command_pool = unwrap_here!(
23            "Create command pool",
24            raii::CommandPool::new(
25                "SyncCommands",
26                cxt.device.clone(),
27                &vk::CommandPoolCreateInfo {
28                    flags: vk::CommandPoolCreateFlags::TRANSIENT,
29                    queue_family_index: cxt.graphics_queue_family_index,
30                    ..Default::default()
31                },
32            )
33        );
34        let command_buffer =
35            unwrap_here!("Allocate primary command buffer", unsafe {
36                cxt.allocate_command_buffers(&vk::CommandBufferAllocateInfo {
37                    command_pool: command_pool.raw,
38                    level: vk::CommandBufferLevel::PRIMARY,
39                    command_buffer_count: 1,
40                    ..Default::default()
41                })?
42                .first()
43                .copied()
44                .context("Expected exactly one command buffer to be returned!")
45            });
46        let fence = unwrap_here!(
47            "Create command fence",
48            raii::Fence::new(
49                "SyncCommands",
50                cxt.device.clone(),
51                &vk::FenceCreateInfo::default(),
52            )
53        );
54        Ok(Self {
55            command_pool,
56            command_buffer,
57            fence,
58            cxt,
59        })
60    }
61
62    pub fn submit_and_wait(
63        &self,
64        build_commands: impl FnOnce(vk::CommandBuffer) -> Result<()>,
65    ) -> Result<()> {
66        unwrap_here!("Reset command pool", unsafe {
67            self.cxt.reset_command_pool(
68                self.command_pool.raw,
69                vk::CommandPoolResetFlags::empty(),
70            )
71        });
72
73        unwrap_here!("Begin command buffer one time submit", unsafe {
74            self.cxt.begin_command_buffer(
75                self.command_buffer,
76                &vk::CommandBufferBeginInfo {
77                    flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
78                    ..Default::default()
79                },
80            )
81        });
82
83        unwrap_here!(
84            "Add commands to the buffer",
85            build_commands(self.command_buffer)
86        );
87
88        unwrap_here!("End command buffer", unsafe {
89            self.cxt.end_command_buffer(self.command_buffer)
90        });
91
92        unwrap_here!("Submit commands and signal fence", unsafe {
93            self.cxt.queue_submit(
94                self.cxt.graphics_queue,
95                &[vk::SubmitInfo {
96                    wait_semaphore_count: 0,
97                    p_wait_semaphores: std::ptr::null(),
98                    p_wait_dst_stage_mask: std::ptr::null(),
99                    command_buffer_count: 1,
100                    p_command_buffers: &self.command_buffer,
101                    signal_semaphore_count: 0,
102                    p_signal_semaphores: std::ptr::null(),
103                    ..Default::default()
104                }],
105                self.fence.raw,
106            )
107        });
108
109        unwrap_here!("Wait for submission fence", unsafe {
110            self.cxt.wait_for_fences(&[self.fence.raw], true, u64::MAX)
111        });
112
113        unwrap_here!("Reset fence after commands complete", unsafe {
114            self.cxt.reset_fences(&[self.fence.raw])
115        });
116
117        Ok(())
118    }
119}