demo_vk/graphics/vulkan/
sync_commands.rs

1use {
2    crate::{
3        graphics::vulkan::{raii, VulkanContext},
4        trace,
5    },
6    anyhow::{Context, 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 = raii::CommandPool::new(
23            "SyncCommands",
24            cxt.device.clone(),
25            &vk::CommandPoolCreateInfo {
26                flags: vk::CommandPoolCreateFlags::TRANSIENT,
27                queue_family_index: cxt.graphics_queue_family_index,
28                ..Default::default()
29            },
30        )
31        .with_context(trace!("Unable to create command pool!"))?;
32        let command_buffer = unsafe {
33            cxt.allocate_command_buffers(&vk::CommandBufferAllocateInfo {
34                command_pool: command_pool.raw,
35                level: vk::CommandBufferLevel::PRIMARY,
36                command_buffer_count: 1,
37                ..Default::default()
38            })
39            .with_context(trace!("Unable to allocate the command buffer!"))?[0]
40        };
41        let fence = raii::Fence::new(
42            "SyncCommands",
43            cxt.device.clone(),
44            &vk::FenceCreateInfo::default(),
45        )?;
46        Ok(Self {
47            command_pool,
48            command_buffer,
49            fence,
50            cxt,
51        })
52    }
53
54    pub fn submit_and_wait(
55        &self,
56        build_commands: impl FnOnce(vk::CommandBuffer) -> Result<()>,
57    ) -> Result<()> {
58        unsafe {
59            self.cxt
60                .reset_command_pool(
61                    self.command_pool.raw,
62                    vk::CommandPoolResetFlags::empty(),
63                )
64                .with_context(trace!("Error while resetting command pool!"))?;
65
66            self.cxt.begin_command_buffer(
67                self.command_buffer,
68                &vk::CommandBufferBeginInfo {
69                    flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
70                    ..Default::default()
71                },
72            )?;
73        }
74
75        build_commands(self.command_buffer).with_context(trace!(
76            "Error while adding commands to the buffer!"
77        ))?;
78
79        unsafe {
80            self.cxt
81                .end_command_buffer(self.command_buffer)
82                .with_context(trace!("Error while ending command buffer!"))?;
83
84            self.cxt
85                .queue_submit(
86                    self.cxt.graphics_queue,
87                    &[vk::SubmitInfo {
88                        wait_semaphore_count: 0,
89                        p_wait_semaphores: std::ptr::null(),
90                        p_wait_dst_stage_mask: std::ptr::null(),
91                        command_buffer_count: 1,
92                        p_command_buffers: &self.command_buffer,
93                        signal_semaphore_count: 0,
94                        p_signal_semaphores: std::ptr::null(),
95                        ..Default::default()
96                    }],
97                    self.fence.raw,
98                )
99                .with_context(trace!("Error while submitting commands!"))?;
100
101            self.cxt
102                .wait_for_fences(&[self.fence.raw], true, u64::MAX)
103                .with_context(trace!(
104                    "Error while waiting for commands to finish!"
105                ))?;
106            self.cxt
107                .reset_fences(&[self.fence.raw])
108                .with_context(trace!("Error while resetting fences!"))?;
109        }
110
111        Ok(())
112    }
113}